Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 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 "net/socket/unix_domain_client_socket_posix.h" | |
| 6 | |
| 7 #include <errno.h> | |
| 8 #include <sys/socket.h> | |
| 9 #include <unistd.h> | |
| 10 | |
| 11 #include "base/callback.h" | |
| 12 #include "base/callback_helpers.h" | |
| 13 #include "base/posix/eintr_wrapper.h" | |
| 14 #include "net/base/io_buffer.h" | |
| 15 #include "net/base/net_errors.h" | |
| 16 #include "net/base/net_util.h" | |
| 17 #include "net/socket/stream_socket.h" | |
| 18 | |
| 19 namespace net { | |
| 20 | |
| 21 UnixDomainClientSocket::UnixDomainClientSocket(const std::string& socket_path, | |
| 22 bool use_abstract_namespace) | |
| 23 : socket_path_(socket_path), | |
| 24 use_abstract_namespace_(use_abstract_namespace), | |
| 25 socket_fd_(kInvalidSocket), | |
| 26 waiting_connect_(true), | |
| 27 read_buf_len_(0), | |
| 28 write_buf_len_(0) { | |
| 29 } | |
| 30 | |
| 31 UnixDomainClientSocket::UnixDomainClientSocket(SocketDescriptor socket_fd) | |
| 32 : use_abstract_namespace_(false), | |
| 33 socket_fd_(socket_fd), | |
| 34 waiting_connect_(false), | |
| 35 read_buf_len_(0), | |
| 36 write_buf_len_(0) { | |
| 37 } | |
| 38 | |
| 39 UnixDomainClientSocket::~UnixDomainClientSocket() { | |
| 40 Disconnect(); | |
| 41 } | |
| 42 | |
| 43 // static | |
| 44 bool UnixDomainClientSocket::FillAddress(const std::string& socket_path, | |
| 45 bool use_abstract_namespace, | |
| 46 sockaddr_un* socket_addr, | |
| 47 socklen_t* addr_len) { | |
| 48 size_t path_max = *addr_len - offsetof(struct sockaddr_un, sun_path); | |
| 49 // Non abstract namespace pathname should be null-terminated. Abstract | |
| 50 // namespace pathname must start with '\0'. So, the size is always greater | |
| 51 // than socket_path size by 1. | |
| 52 size_t path_size = socket_path.size() + 1; | |
| 53 if (path_size > path_max) | |
| 54 return false; | |
| 55 | |
| 56 memset(socket_addr, 0, *addr_len); | |
| 57 socket_addr->sun_family = AF_UNIX; | |
| 58 if (!use_abstract_namespace) { | |
| 59 memcpy(socket_addr->sun_path, socket_path.c_str(), socket_path.size()); | |
| 60 return true; | |
| 61 } | |
| 62 | |
| 63 #if defined(OS_ANDROID) || defined(OS_LINUX) | |
| 64 // Convert the path given into abstract socket name. It must start with | |
| 65 // the '\0' character, so we are adding it. |addr_len| must specify the | |
| 66 // length of the structure exactly, as potentially the socket name may | |
| 67 // have '\0' characters embedded (although we don't support this). | |
| 68 // Note that addr.sun_path is already zero initialized. | |
| 69 memcpy(socket_addr->sun_path + 1, socket_path.c_str(), socket_path.size()); | |
| 70 *addr_len = socket_path.size() + offsetof(struct sockaddr_un, sun_path) + 1; | |
| 71 return true; | |
| 72 #else | |
| 73 return false; | |
| 74 #endif | |
| 75 } | |
| 76 | |
| 77 int UnixDomainClientSocket::Connect(const CompletionCallback& callback) { | |
|
mmenke
2014/06/11 16:05:50
DCHECK(waiting_connect_)?
byungchul
2014/06/20 08:22:32
Done.
| |
| 78 if (IsConnected()) | |
| 79 return ERR_SOCKET_IS_CONNECTED; | |
|
mmenke
2014/06/11 16:05:50
Should we DCHECK on this instead? (I know we don'
byungchul
2014/06/20 08:22:32
Done.
| |
| 80 | |
| 81 if (socket_path_.empty()) | |
| 82 return ERR_ADDRESS_INVALID; | |
| 83 | |
| 84 DCHECK(!callback.is_null()); | |
| 85 DCHECK(write_callback_.is_null()); | |
|
mmenke
2014/06/11 16:05:50
Move these up before the IsConnected check?
byungchul
2014/06/20 08:22:32
Done.
| |
| 86 | |
| 87 int rv = DoConnect(); | |
| 88 if (rv != ERR_IO_PENDING) { | |
| 89 if (rv == OK) | |
| 90 waiting_connect_ = false; | |
| 91 return rv; | |
| 92 } | |
| 93 | |
| 94 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
| 95 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE, | |
| 96 &write_socket_watcher_, this)) { | |
| 97 PLOG(ERROR) << "WatchFileDescriptor failed on write"; | |
| 98 return MapSystemError(errno); | |
| 99 } | |
| 100 | |
| 101 write_callback_ = callback; | |
| 102 return ERR_IO_PENDING; | |
| 103 } | |
| 104 | |
| 105 int UnixDomainClientSocket::DoConnect() { | |
| 106 sockaddr_un addr; | |
| 107 socklen_t addr_len = sizeof(addr); | |
| 108 if (!FillAddress(socket_path_, use_abstract_namespace_, &addr, &addr_len)) | |
| 109 return ERR_ADDRESS_INVALID; | |
| 110 | |
| 111 if (socket_fd_ == kInvalidSocket) { | |
| 112 SocketDescriptor s = CreatePlatformSocket(PF_UNIX, SOCK_STREAM, 0); | |
| 113 if (s == kInvalidSocket) | |
| 114 return errno ? MapSystemError(errno) : ERR_UNEXPECTED; | |
| 115 | |
| 116 if (SetNonBlocking(s)) { | |
| 117 int rv = MapSystemError(errno); | |
| 118 close(s); | |
| 119 return rv; | |
| 120 } | |
| 121 | |
| 122 socket_fd_ = s; | |
| 123 } | |
| 124 | |
| 125 int rv = HANDLE_EINTR(connect(socket_fd_, | |
| 126 reinterpret_cast<sockaddr*>(&addr), | |
| 127 addr_len)); | |
| 128 DCHECK_LE(rv, 0); | |
| 129 return rv == 0 ? OK : | |
| 130 errno == EINPROGRESS ? ERR_IO_PENDING : MapSystemError(errno); | |
| 131 } | |
| 132 | |
| 133 void UnixDomainClientSocket::DidCompleteConnect() { | |
| 134 // Get the error that connect() completed with. | |
| 135 int os_error = 0; | |
| 136 socklen_t len = sizeof(os_error); | |
| 137 if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0) | |
| 138 os_error = errno; | |
| 139 | |
| 140 int rv = MapSystemError(os_error); | |
| 141 if (rv == ERR_IO_PENDING) | |
| 142 return; | |
| 143 | |
| 144 write_socket_watcher_.StopWatchingFileDescriptor(); | |
| 145 waiting_connect_ = false; | |
| 146 base::ResetAndReturn(&write_callback_).Run(rv); | |
| 147 } | |
| 148 | |
| 149 void UnixDomainClientSocket::Disconnect() { | |
| 150 if (socket_fd_ == kInvalidSocket) | |
| 151 return; | |
| 152 close(socket_fd_); | |
| 153 socket_fd_ = kInvalidSocket; | |
| 154 } | |
| 155 | |
| 156 bool UnixDomainClientSocket::IsConnected() const { | |
| 157 return socket_fd_ != kInvalidSocket && !waiting_connect_; | |
| 158 } | |
| 159 | |
| 160 bool UnixDomainClientSocket::IsConnectedAndIdle() const { | |
| 161 return IsConnected(); | |
| 162 } | |
| 163 | |
| 164 int UnixDomainClientSocket::GetPeerAddress(IPEndPoint* address) const { | |
| 165 NOTIMPLEMENTED(); | |
| 166 return ERR_NOT_IMPLEMENTED; | |
| 167 } | |
| 168 | |
| 169 int UnixDomainClientSocket::GetLocalAddress(IPEndPoint* address) const { | |
| 170 NOTIMPLEMENTED(); | |
| 171 return ERR_NOT_IMPLEMENTED; | |
| 172 } | |
| 173 | |
| 174 const BoundNetLog& UnixDomainClientSocket::NetLog() const { | |
| 175 return netlog_; | |
| 176 } | |
| 177 | |
| 178 void UnixDomainClientSocket::SetSubresourceSpeculation() { | |
| 179 } | |
| 180 | |
| 181 void UnixDomainClientSocket::SetOmniboxSpeculation() { | |
| 182 } | |
| 183 | |
| 184 bool UnixDomainClientSocket::WasEverUsed() const { | |
| 185 return true; // We don't care. | |
| 186 } | |
| 187 | |
| 188 bool UnixDomainClientSocket::UsingTCPFastOpen() const { | |
| 189 return false; | |
| 190 } | |
| 191 | |
| 192 bool UnixDomainClientSocket::WasNpnNegotiated() const { | |
| 193 return false; | |
| 194 } | |
| 195 | |
| 196 NextProto UnixDomainClientSocket::GetNegotiatedProtocol() const { | |
| 197 return kProtoUnknown; | |
| 198 } | |
| 199 | |
| 200 bool UnixDomainClientSocket::GetSSLInfo(SSLInfo* ssl_info) { | |
| 201 return false; | |
| 202 } | |
| 203 | |
| 204 int UnixDomainClientSocket::Read(IOBuffer* buf, int buf_len, | |
| 205 const CompletionCallback& callback) { | |
| 206 DCHECK(buf); | |
| 207 DCHECK_LT(0, buf_len); | |
| 208 DCHECK(!callback.is_null()); | |
| 209 DCHECK(read_callback_.is_null()); | |
| 210 | |
| 211 if (!IsConnected()) | |
| 212 return ERR_SOCKET_NOT_CONNECTED; | |
| 213 | |
| 214 int rv = DoRead(buf, buf_len); | |
| 215 if (rv != ERR_IO_PENDING) | |
| 216 return rv; | |
| 217 | |
| 218 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
| 219 socket_fd_, true, base::MessageLoopForIO::WATCH_READ, | |
| 220 &read_socket_watcher_, this)) { | |
| 221 PLOG(ERROR) << "WatchFileDescriptor failed on read"; | |
| 222 return MapSystemError(errno); | |
| 223 } | |
| 224 | |
| 225 read_buf_ = buf; | |
| 226 read_buf_len_ = buf_len; | |
| 227 read_callback_ = callback; | |
| 228 return ERR_IO_PENDING; | |
| 229 } | |
| 230 | |
| 231 int UnixDomainClientSocket::DoRead(IOBuffer* buf, int buf_len) { | |
| 232 int rv = HANDLE_EINTR(read(socket_fd_, buf->data(), buf_len)); | |
| 233 return rv >= 0 ? rv : MapSystemError(errno); | |
| 234 } | |
| 235 | |
| 236 void UnixDomainClientSocket::DidCompleteRead() { | |
| 237 int rv = DoRead(read_buf_, read_buf_len_); | |
| 238 if (rv == ERR_IO_PENDING) | |
| 239 return; | |
| 240 | |
| 241 read_socket_watcher_.StopWatchingFileDescriptor(); | |
| 242 read_buf_ = NULL; | |
| 243 read_buf_len_ = 0; | |
| 244 base::ResetAndReturn(&read_callback_).Run(rv); | |
| 245 } | |
| 246 | |
| 247 int UnixDomainClientSocket::Write(IOBuffer* buf, int buf_len, | |
| 248 const CompletionCallback& callback) { | |
| 249 DCHECK(buf); | |
| 250 DCHECK_LT(0, buf_len); | |
| 251 DCHECK(!callback.is_null()); | |
| 252 DCHECK(write_callback_.is_null()); | |
| 253 | |
| 254 if (!IsConnected()) | |
| 255 return ERR_SOCKET_NOT_CONNECTED; | |
| 256 | |
| 257 int rv = DoWrite(buf, buf_len); | |
| 258 if (rv != ERR_IO_PENDING) | |
| 259 return rv; | |
| 260 | |
| 261 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
| 262 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE, | |
| 263 &write_socket_watcher_, this)) { | |
| 264 PLOG(ERROR) << "WatchFileDescriptor failed on write"; | |
| 265 return MapSystemError(errno); | |
| 266 } | |
| 267 | |
| 268 write_buf_ = buf; | |
| 269 write_buf_len_ = buf_len; | |
| 270 write_callback_ = callback; | |
| 271 return ERR_IO_PENDING; | |
| 272 } | |
| 273 | |
| 274 int UnixDomainClientSocket::DoWrite(IOBuffer* buf, int buf_len) { | |
| 275 int rv = HANDLE_EINTR(write(socket_fd_, buf->data(), buf_len)); | |
| 276 return rv >= 0 ? rv : MapSystemError(errno); | |
| 277 } | |
| 278 | |
| 279 void UnixDomainClientSocket::DidCompleteWrite() { | |
|
mmenke
2014/06/11 16:05:50
This function seems to be misnamed (As is DidCompl
byungchul
2014/06/11 17:30:28
Per your request, will try to split this change in
mmenke
2014/06/11 17:53:27
Yea, makes sense.
Hrm... Since TCPSocketLibevent
byungchul
2014/06/20 08:22:32
Done. Please review https://codereview.chromium.or
| |
| 280 int rv = DoWrite(write_buf_, write_buf_len_); | |
| 281 if (rv == ERR_IO_PENDING) | |
| 282 return; | |
| 283 | |
| 284 write_socket_watcher_.StopWatchingFileDescriptor(); | |
| 285 write_buf_ = NULL; | |
| 286 write_buf_len_ = 0; | |
| 287 base::ResetAndReturn(&write_callback_).Run(rv); | |
| 288 } | |
| 289 | |
| 290 int UnixDomainClientSocket::SetReceiveBufferSize(int32 size) { | |
| 291 NOTIMPLEMENTED(); | |
| 292 return ERR_NOT_IMPLEMENTED; | |
| 293 } | |
| 294 | |
| 295 int UnixDomainClientSocket::SetSendBufferSize(int32 size) { | |
| 296 NOTIMPLEMENTED(); | |
| 297 return ERR_NOT_IMPLEMENTED; | |
| 298 } | |
| 299 | |
| 300 void UnixDomainClientSocket::OnFileCanReadWithoutBlocking(int fd) { | |
| 301 if (read_callback_.is_null()) { | |
| 302 NOTREACHED(); | |
| 303 } else { | |
| 304 DidCompleteRead(); | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 void UnixDomainClientSocket::OnFileCanWriteWithoutBlocking(int fd) { | |
| 309 if (write_callback_.is_null()) { | |
| 310 NOTREACHED(); | |
|
mmenke
2014/06/11 16:05:50
Shouldn't be handling this case, should just have
byungchul
2014/06/20 08:22:32
Done.
| |
| 311 } else if (waiting_connect_) { | |
| 312 DidCompleteConnect(); | |
| 313 } else { | |
| 314 DidCompleteWrite(); | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 } // namespace net | |
| OLD | NEW |