14a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
24a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
34a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// found in the LICENSE file.
44a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
54a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/multi_process_lock.h"
64a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
74a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <stdio.h>
84a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <sys/socket.h>
94a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <sys/un.h>
104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <unistd.h>
114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/eintr_wrapper.h"
134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/logging.h"
144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochclass MultiProcessLockLinux : public MultiProcessLock {
164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch public:
174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  explicit MultiProcessLockLinux(const std::string& name)
184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      : name_(name), fd_(-1) { }
194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  virtual ~MultiProcessLockLinux() {
214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (fd_ != -1) {
224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      Unlock();
234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  virtual bool TryLock() {
274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (fd_ != -1) {
284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      DLOG(ERROR) << "MultiProcessLock is already locked - " << name_;
294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return true;
304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (name_.length() > MULTI_PROCESS_LOCK_NAME_MAX_LEN) {
33201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(ERROR) << "Socket name too long (" << name_.length()
34201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                 << " > " << MULTI_PROCESS_LOCK_NAME_MAX_LEN << ") - " << name_;
354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return false;
364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    struct sockaddr_un address;
394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // +1 for terminator, +1 for 0 in position 0 that makes it an
414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // abstract named socket.
424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // If this assert fails it is because sockaddr_un.sun_path size has been
434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // redefined and MULTI_PROCESS_LOCK_NAME_MAX_LEN can change accordingly.
444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    COMPILE_ASSERT(sizeof(address.sun_path)
454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        == MULTI_PROCESS_LOCK_NAME_MAX_LEN + 2, sun_path_size_changed);
464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    memset(&address, 0, sizeof(address));
484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    int print_length = snprintf(&address.sun_path[1],
494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                MULTI_PROCESS_LOCK_NAME_MAX_LEN + 1,
504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                "%s", name_.c_str());
514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (print_length < 0 ||
534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        print_length > static_cast<int>(MULTI_PROCESS_LOCK_NAME_MAX_LEN)) {
544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      PLOG(ERROR) << "Couldn't create sun_path - " << name_;
554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return false;
564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // Must set the first character of the path to something non-zero
594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // before we call SUN_LEN which depends on strcpy working.
604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    address.sun_path[0] = '@';
614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    size_t length = SUN_LEN(&address);
624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // Reset the first character of the path back to zero so that
644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // bind returns an abstract name socket.
654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    address.sun_path[0] = 0;
664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    address.sun_family = AF_LOCAL;
674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    int socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (socket_fd < 0) {
704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      PLOG(ERROR) << "Couldn't create socket - " << name_;
714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return false;
724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (bind(socket_fd,
754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch             reinterpret_cast<sockaddr *>(&address),
764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch             length) == 0) {
774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      fd_ = socket_fd;
784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return true;
794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    } else {
804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      PLOG(ERROR) << "Couldn't bind socket - "
814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                  << &(address.sun_path[1])
824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                  << " Length: " << length;
834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      if (HANDLE_EINTR(close(socket_fd)) < 0) {
844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        PLOG(ERROR) << "close";
854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      }
864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return false;
874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  virtual void Unlock() {
914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (fd_ == -1) {
924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      DLOG(ERROR) << "Over-unlocked MultiProcessLock - " << name_;
934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return;
944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (HANDLE_EINTR(close(fd_)) < 0) {
964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      PLOG(ERROR) << "close";
974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    fd_ = -1;
994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
1004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch private:
1024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string name_;
1034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int fd_;
1044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(MultiProcessLockLinux);
1054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch};
1064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochMultiProcessLock* MultiProcessLock::Create(const std::string &name) {
1084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return new MultiProcessLockLinux(name);
1094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
110