OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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 "mojo/edk/embedder/named_platform_handle_utils.h" |
| 6 |
| 7 #include <errno.h> |
| 8 #include <sys/socket.h> |
| 9 #include <sys/un.h> |
| 10 #include <unistd.h> |
| 11 |
| 12 #include "base/files/file_path.h" |
| 13 #include "base/files/file_util.h" |
| 14 #include "base/logging.h" |
| 15 #include "base/posix/eintr_wrapper.h" |
| 16 #include "mojo/edk/embedder/named_platform_handle.h" |
| 17 |
| 18 namespace mojo { |
| 19 namespace edk { |
| 20 namespace { |
| 21 |
| 22 // The maximum length of the name of a socket for MODE_NAMED_SERVER or |
| 23 // MODE_NAMED_CLIENT if you want to pass in your own socket. |
| 24 // The standard size on linux is 108, mac is 104. To maintain consistency |
| 25 // across platforms we standardize on the smaller value. |
| 26 const size_t kMaxSocketNameLength = 104; |
| 27 |
| 28 // This function fills in |unix_addr| with the appropriate data for the socket, |
| 29 // and sets |unix_addr_len| to the length of the data therein. |
| 30 // Returns true on success, or false on failure (typically because |handle.name| |
| 31 // violated the naming rules). |
| 32 bool MakeUnixAddr(const NamedPlatformHandle& handle, |
| 33 struct sockaddr_un* unix_addr, |
| 34 size_t* unix_addr_len) { |
| 35 DCHECK(unix_addr); |
| 36 DCHECK(unix_addr_len); |
| 37 DCHECK(handle.is_valid()); |
| 38 |
| 39 // We reject handle.name.length() == kMaxSocketNameLength to make room for the |
| 40 // NUL terminator at the end of the string. |
| 41 if (handle.name.length() >= kMaxSocketNameLength) { |
| 42 LOG(ERROR) << "Socket name too long: " << handle.name; |
| 43 return false; |
| 44 } |
| 45 |
| 46 // Create unix_addr structure. |
| 47 memset(unix_addr, 0, sizeof(struct sockaddr_un)); |
| 48 unix_addr->sun_family = AF_UNIX; |
| 49 strncpy(unix_addr->sun_path, handle.name.c_str(), kMaxSocketNameLength); |
| 50 *unix_addr_len = |
| 51 offsetof(struct sockaddr_un, sun_path) + handle.name.length(); |
| 52 return true; |
| 53 } |
| 54 |
| 55 // This function creates a unix domain socket, and set it as non-blocking. |
| 56 // If successful, this returns a ScopedPlatformHandle containing the socket. |
| 57 // Otherwise, this returns an invalid ScopedPlatformHandle. |
| 58 ScopedPlatformHandle CreateUnixDomainSocket(bool needs_connection) { |
| 59 // Create the unix domain socket. |
| 60 PlatformHandle socket_handle(socket(AF_UNIX, SOCK_STREAM, 0)); |
| 61 socket_handle.needs_connection = needs_connection; |
| 62 ScopedPlatformHandle handle(socket_handle); |
| 63 if (!handle.is_valid()) { |
| 64 PLOG(ERROR) << "Failed to create AF_UNIX socket."; |
| 65 return ScopedPlatformHandle(); |
| 66 } |
| 67 |
| 68 // Now set it as non-blocking. |
| 69 if (!base::SetNonBlocking(handle.get().handle)) { |
| 70 PLOG(ERROR) << "base::SetNonBlocking() failed " << handle.get().handle; |
| 71 return ScopedPlatformHandle(); |
| 72 } |
| 73 return handle; |
| 74 } |
| 75 |
| 76 } // namespace |
| 77 |
| 78 ScopedPlatformHandle CreateClientHandle( |
| 79 const NamedPlatformHandle& named_handle) { |
| 80 if (!named_handle.is_valid()) |
| 81 return ScopedPlatformHandle(); |
| 82 |
| 83 struct sockaddr_un unix_addr; |
| 84 size_t unix_addr_len; |
| 85 if (!MakeUnixAddr(named_handle, &unix_addr, &unix_addr_len)) |
| 86 return ScopedPlatformHandle(); |
| 87 |
| 88 ScopedPlatformHandle handle = CreateUnixDomainSocket(false); |
| 89 if (!handle.is_valid()) |
| 90 return ScopedPlatformHandle(); |
| 91 |
| 92 if (HANDLE_EINTR(connect(handle.get().handle, |
| 93 reinterpret_cast<sockaddr*>(&unix_addr), |
| 94 unix_addr_len)) < 0) { |
| 95 PLOG(ERROR) << "connect " << named_handle.name; |
| 96 return ScopedPlatformHandle(); |
| 97 } |
| 98 |
| 99 return handle; |
| 100 } |
| 101 |
| 102 ScopedPlatformHandle CreateServerHandle(const NamedPlatformHandle& named_handle, |
| 103 bool enforce_uniqueness) { |
| 104 CHECK(!enforce_uniqueness); |
| 105 if (!named_handle.is_valid()) |
| 106 return ScopedPlatformHandle(); |
| 107 |
| 108 // Make sure the path we need exists. |
| 109 base::FilePath socket_dir = base::FilePath(named_handle.name).DirName(); |
| 110 if (!base::CreateDirectory(socket_dir)) { |
| 111 LOG(ERROR) << "Couldn't create directory: " << socket_dir.value(); |
| 112 return ScopedPlatformHandle(); |
| 113 } |
| 114 |
| 115 // Delete any old FS instances. |
| 116 if (unlink(named_handle.name.c_str()) < 0 && errno != ENOENT) { |
| 117 PLOG(ERROR) << "unlink " << named_handle.name; |
| 118 return ScopedPlatformHandle(); |
| 119 } |
| 120 |
| 121 struct sockaddr_un unix_addr; |
| 122 size_t unix_addr_len; |
| 123 if (!MakeUnixAddr(named_handle, &unix_addr, &unix_addr_len)) |
| 124 return ScopedPlatformHandle(); |
| 125 |
| 126 ScopedPlatformHandle handle = CreateUnixDomainSocket(true); |
| 127 if (!handle.is_valid()) |
| 128 return ScopedPlatformHandle(); |
| 129 |
| 130 // Bind the socket. |
| 131 if (bind(handle.get().handle, reinterpret_cast<const sockaddr*>(&unix_addr), |
| 132 unix_addr_len) < 0) { |
| 133 PLOG(ERROR) << "bind " << named_handle.name; |
| 134 return ScopedPlatformHandle(); |
| 135 } |
| 136 |
| 137 // Start listening on the socket. |
| 138 if (listen(handle.get().handle, SOMAXCONN) < 0) { |
| 139 PLOG(ERROR) << "listen " << named_handle.name; |
| 140 unlink(named_handle.name.c_str()); |
| 141 return ScopedPlatformHandle(); |
| 142 } |
| 143 return handle; |
| 144 } |
| 145 |
| 146 } // namespace edk |
| 147 } // namespace mojo |
OLD | NEW |