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