Home | History | Annotate | Download | only in common
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/common/multi_process_lock.h"
      6 
      7 #include <stdio.h>
      8 #include <sys/socket.h>
      9 #include <sys/un.h>
     10 #include <unistd.h>
     11 
     12 #include "base/compiler_specific.h"
     13 #include "base/logging.h"
     14 #include "base/posix/eintr_wrapper.h"
     15 
     16 class MultiProcessLockLinux : public MultiProcessLock {
     17  public:
     18   explicit MultiProcessLockLinux(const std::string& name)
     19       : name_(name), fd_(-1) { }
     20 
     21   virtual ~MultiProcessLockLinux() {
     22     if (fd_ != -1) {
     23       Unlock();
     24     }
     25   }
     26 
     27   virtual bool TryLock() OVERRIDE {
     28     struct sockaddr_un address;
     29 
     30     // +1 for terminator, +1 for 0 in position 0 that makes it an
     31     // abstract named socket.
     32     const size_t max_len = sizeof(address.sun_path) - 2;
     33 
     34     if (fd_ != -1) {
     35       DLOG(ERROR) << "MultiProcessLock is already locked - " << name_;
     36       return true;
     37     }
     38 
     39     if (name_.length() > max_len) {
     40       LOG(ERROR) << "Socket name too long (" << name_.length()
     41                  << " > " << max_len << ") - " << name_;
     42       return false;
     43     }
     44 
     45     memset(&address, 0, sizeof(address));
     46     int print_length = snprintf(&address.sun_path[1],
     47                                 max_len + 1,
     48                                 "%s", name_.c_str());
     49 
     50     if (print_length < 0 ||
     51         print_length > static_cast<int>(max_len)) {
     52       PLOG(ERROR) << "Couldn't create sun_path - " << name_;
     53       return false;
     54     }
     55 
     56     // Must set the first character of the path to something non-zero
     57     // before we call SUN_LEN which depends on strcpy working.
     58     address.sun_path[0] = '@';
     59     size_t length = SUN_LEN(&address);
     60 
     61     // Reset the first character of the path back to zero so that
     62     // bind returns an abstract name socket.
     63     address.sun_path[0] = 0;
     64     address.sun_family = AF_LOCAL;
     65 
     66     int socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
     67     if (socket_fd < 0) {
     68       PLOG(ERROR) << "Couldn't create socket - " << name_;
     69       return false;
     70     }
     71 
     72     if (bind(socket_fd,
     73              reinterpret_cast<sockaddr *>(&address),
     74              length) == 0) {
     75       fd_ = socket_fd;
     76       return true;
     77     } else {
     78       DVLOG(1) << "Couldn't bind socket - "
     79                << &(address.sun_path[1])
     80                << " Length: " << length;
     81       if (IGNORE_EINTR(close(socket_fd)) < 0) {
     82         PLOG(ERROR) << "close";
     83       }
     84       return false;
     85     }
     86   }
     87 
     88   virtual void Unlock() OVERRIDE {
     89     if (fd_ == -1) {
     90       DLOG(ERROR) << "Over-unlocked MultiProcessLock - " << name_;
     91       return;
     92     }
     93     if (IGNORE_EINTR(close(fd_)) < 0) {
     94       DPLOG(ERROR) << "close";
     95     }
     96     fd_ = -1;
     97   }
     98 
     99  private:
    100   std::string name_;
    101   int fd_;
    102   DISALLOW_COPY_AND_ASSIGN(MultiProcessLockLinux);
    103 };
    104 
    105 MultiProcessLock* MultiProcessLock::Create(const std::string &name) {
    106   return new MultiProcessLockLinux(name);
    107 }
    108