15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/multi_process_lock.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/un.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MultiProcessLockLinux : public MultiProcessLock {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit MultiProcessLockLinux(const std::string& name)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : name_(name), fd_(-1) { }
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~MultiProcessLockLinux() {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fd_ != -1) {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Unlock();
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool TryLock() OVERRIDE {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct sockaddr_un address;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // +1 for terminator, +1 for 0 in position 0 that makes it an
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // abstract named socket.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const size_t max_len = sizeof(address.sun_path) - 2;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fd_ != -1) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(ERROR) << "MultiProcessLock is already locked - " << name_;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (name_.length() > max_len) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Socket name too long (" << name_.length()
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " > " << max_len << ") - " << name_;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(&address, 0, sizeof(address));
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int print_length = snprintf(&address.sun_path[1],
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                max_len + 1,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                "%s", name_.c_str());
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (print_length < 0 ||
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print_length > static_cast<int>(max_len)) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PLOG(ERROR) << "Couldn't create sun_path - " << name_;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Must set the first character of the path to something non-zero
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // before we call SUN_LEN which depends on strcpy working.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    address.sun_path[0] = '@';
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t length = SUN_LEN(&address);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Reset the first character of the path back to zero so that
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // bind returns an abstract name socket.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    address.sun_path[0] = 0;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    address.sun_family = AF_LOCAL;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (socket_fd < 0) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PLOG(ERROR) << "Couldn't create socket - " << name_;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bind(socket_fd,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             reinterpret_cast<sockaddr *>(&address),
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             length) == 0) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fd_ = socket_fd;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DVLOG(1) << "Couldn't bind socket - "
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << &(address.sun_path[1])
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " Length: " << length;
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (IGNORE_EINTR(close(socket_fd)) < 0) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PLOG(ERROR) << "close";
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void Unlock() OVERRIDE {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fd_ == -1) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(ERROR) << "Over-unlocked MultiProcessLock - " << name_;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (IGNORE_EINTR(close(fd_)) < 0) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DPLOG(ERROR) << "close";
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fd_ = -1;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string name_;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int fd_;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MultiProcessLockLinux);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiProcessLock* MultiProcessLock::Create(const std::string &name) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new MultiProcessLockLinux(name);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
108