Index: net/socket/unix_domain_client_socket_posix.cc |
diff --git a/net/socket/unix_domain_client_socket_posix.cc b/net/socket/unix_domain_client_socket_posix.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e75e6a28c6094ff48a60c805f021cc8d44812037 |
--- /dev/null |
+++ b/net/socket/unix_domain_client_socket_posix.cc |
@@ -0,0 +1,318 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/socket/unix_domain_client_socket_posix.h" |
+ |
+#include <errno.h> |
+#include <sys/socket.h> |
+#include <unistd.h> |
+ |
+#include "base/callback.h" |
+#include "base/callback_helpers.h" |
+#include "base/posix/eintr_wrapper.h" |
+#include "net/base/io_buffer.h" |
+#include "net/base/net_errors.h" |
+#include "net/base/net_util.h" |
+#include "net/socket/stream_socket.h" |
+ |
+namespace net { |
+ |
+UnixDomainClientSocket::UnixDomainClientSocket(const std::string& socket_path, |
+ bool use_abstract_namespace) |
+ : socket_path_(socket_path), |
+ use_abstract_namespace_(use_abstract_namespace), |
+ socket_fd_(kInvalidSocket), |
+ waiting_connect_(true), |
+ read_buf_len_(0), |
+ write_buf_len_(0) { |
+} |
+ |
+UnixDomainClientSocket::UnixDomainClientSocket(SocketDescriptor socket_fd) |
+ : use_abstract_namespace_(false), |
+ socket_fd_(socket_fd), |
+ waiting_connect_(false), |
+ read_buf_len_(0), |
+ write_buf_len_(0) { |
+} |
+ |
+UnixDomainClientSocket::~UnixDomainClientSocket() { |
+ Disconnect(); |
+} |
+ |
+// static |
+bool UnixDomainClientSocket::FillAddress(const std::string& socket_path, |
+ bool use_abstract_namespace, |
+ sockaddr_un* socket_addr, |
+ socklen_t* addr_len) { |
+ size_t path_max = *addr_len - offsetof(struct sockaddr_un, sun_path); |
+ // Non abstract namespace pathname should be null-terminated. Abstract |
+ // namespace pathname must start with '\0'. So, the size is always greater |
+ // than socket_path size by 1. |
+ size_t path_size = socket_path.size() + 1; |
+ if (path_size > path_max) |
+ return false; |
+ |
+ memset(socket_addr, 0, *addr_len); |
+ socket_addr->sun_family = AF_UNIX; |
+ if (!use_abstract_namespace) { |
+ memcpy(socket_addr->sun_path, socket_path.c_str(), socket_path.size()); |
+ return true; |
+ } |
+ |
+#if defined(OS_ANDROID) || defined(OS_LINUX) |
+ // Convert the path given into abstract socket name. It must start with |
+ // the '\0' character, so we are adding it. |addr_len| must specify the |
+ // length of the structure exactly, as potentially the socket name may |
+ // have '\0' characters embedded (although we don't support this). |
+ // Note that addr.sun_path is already zero initialized. |
+ memcpy(socket_addr->sun_path + 1, socket_path.c_str(), socket_path.size()); |
+ *addr_len = socket_path.size() + offsetof(struct sockaddr_un, sun_path) + 1; |
+ return true; |
+#else |
+ return false; |
+#endif |
+} |
+ |
+int UnixDomainClientSocket::Connect(const CompletionCallback& callback) { |
mmenke
2014/06/11 16:05:50
DCHECK(waiting_connect_)?
byungchul
2014/06/20 08:22:32
Done.
|
+ if (IsConnected()) |
+ 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.
|
+ |
+ if (socket_path_.empty()) |
+ return ERR_ADDRESS_INVALID; |
+ |
+ DCHECK(!callback.is_null()); |
+ 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.
|
+ |
+ int rv = DoConnect(); |
+ if (rv != ERR_IO_PENDING) { |
+ if (rv == OK) |
+ waiting_connect_ = false; |
+ return rv; |
+ } |
+ |
+ if (!base::MessageLoopForIO::current()->WatchFileDescriptor( |
+ socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE, |
+ &write_socket_watcher_, this)) { |
+ PLOG(ERROR) << "WatchFileDescriptor failed on write"; |
+ return MapSystemError(errno); |
+ } |
+ |
+ write_callback_ = callback; |
+ return ERR_IO_PENDING; |
+} |
+ |
+int UnixDomainClientSocket::DoConnect() { |
+ sockaddr_un addr; |
+ socklen_t addr_len = sizeof(addr); |
+ if (!FillAddress(socket_path_, use_abstract_namespace_, &addr, &addr_len)) |
+ return ERR_ADDRESS_INVALID; |
+ |
+ if (socket_fd_ == kInvalidSocket) { |
+ SocketDescriptor s = CreatePlatformSocket(PF_UNIX, SOCK_STREAM, 0); |
+ if (s == kInvalidSocket) |
+ return errno ? MapSystemError(errno) : ERR_UNEXPECTED; |
+ |
+ if (SetNonBlocking(s)) { |
+ int rv = MapSystemError(errno); |
+ close(s); |
+ return rv; |
+ } |
+ |
+ socket_fd_ = s; |
+ } |
+ |
+ int rv = HANDLE_EINTR(connect(socket_fd_, |
+ reinterpret_cast<sockaddr*>(&addr), |
+ addr_len)); |
+ DCHECK_LE(rv, 0); |
+ return rv == 0 ? OK : |
+ errno == EINPROGRESS ? ERR_IO_PENDING : MapSystemError(errno); |
+} |
+ |
+void UnixDomainClientSocket::DidCompleteConnect() { |
+ // Get the error that connect() completed with. |
+ int os_error = 0; |
+ socklen_t len = sizeof(os_error); |
+ if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0) |
+ os_error = errno; |
+ |
+ int rv = MapSystemError(os_error); |
+ if (rv == ERR_IO_PENDING) |
+ return; |
+ |
+ write_socket_watcher_.StopWatchingFileDescriptor(); |
+ waiting_connect_ = false; |
+ base::ResetAndReturn(&write_callback_).Run(rv); |
+} |
+ |
+void UnixDomainClientSocket::Disconnect() { |
+ if (socket_fd_ == kInvalidSocket) |
+ return; |
+ close(socket_fd_); |
+ socket_fd_ = kInvalidSocket; |
+} |
+ |
+bool UnixDomainClientSocket::IsConnected() const { |
+ return socket_fd_ != kInvalidSocket && !waiting_connect_; |
+} |
+ |
+bool UnixDomainClientSocket::IsConnectedAndIdle() const { |
+ return IsConnected(); |
+} |
+ |
+int UnixDomainClientSocket::GetPeerAddress(IPEndPoint* address) const { |
+ NOTIMPLEMENTED(); |
+ return ERR_NOT_IMPLEMENTED; |
+} |
+ |
+int UnixDomainClientSocket::GetLocalAddress(IPEndPoint* address) const { |
+ NOTIMPLEMENTED(); |
+ return ERR_NOT_IMPLEMENTED; |
+} |
+ |
+const BoundNetLog& UnixDomainClientSocket::NetLog() const { |
+ return netlog_; |
+} |
+ |
+void UnixDomainClientSocket::SetSubresourceSpeculation() { |
+} |
+ |
+void UnixDomainClientSocket::SetOmniboxSpeculation() { |
+} |
+ |
+bool UnixDomainClientSocket::WasEverUsed() const { |
+ return true; // We don't care. |
+} |
+ |
+bool UnixDomainClientSocket::UsingTCPFastOpen() const { |
+ return false; |
+} |
+ |
+bool UnixDomainClientSocket::WasNpnNegotiated() const { |
+ return false; |
+} |
+ |
+NextProto UnixDomainClientSocket::GetNegotiatedProtocol() const { |
+ return kProtoUnknown; |
+} |
+ |
+bool UnixDomainClientSocket::GetSSLInfo(SSLInfo* ssl_info) { |
+ return false; |
+} |
+ |
+int UnixDomainClientSocket::Read(IOBuffer* buf, int buf_len, |
+ const CompletionCallback& callback) { |
+ DCHECK(buf); |
+ DCHECK_LT(0, buf_len); |
+ DCHECK(!callback.is_null()); |
+ DCHECK(read_callback_.is_null()); |
+ |
+ if (!IsConnected()) |
+ return ERR_SOCKET_NOT_CONNECTED; |
+ |
+ int rv = DoRead(buf, buf_len); |
+ if (rv != ERR_IO_PENDING) |
+ return rv; |
+ |
+ if (!base::MessageLoopForIO::current()->WatchFileDescriptor( |
+ socket_fd_, true, base::MessageLoopForIO::WATCH_READ, |
+ &read_socket_watcher_, this)) { |
+ PLOG(ERROR) << "WatchFileDescriptor failed on read"; |
+ return MapSystemError(errno); |
+ } |
+ |
+ read_buf_ = buf; |
+ read_buf_len_ = buf_len; |
+ read_callback_ = callback; |
+ return ERR_IO_PENDING; |
+} |
+ |
+int UnixDomainClientSocket::DoRead(IOBuffer* buf, int buf_len) { |
+ int rv = HANDLE_EINTR(read(socket_fd_, buf->data(), buf_len)); |
+ return rv >= 0 ? rv : MapSystemError(errno); |
+} |
+ |
+void UnixDomainClientSocket::DidCompleteRead() { |
+ int rv = DoRead(read_buf_, read_buf_len_); |
+ if (rv == ERR_IO_PENDING) |
+ return; |
+ |
+ read_socket_watcher_.StopWatchingFileDescriptor(); |
+ read_buf_ = NULL; |
+ read_buf_len_ = 0; |
+ base::ResetAndReturn(&read_callback_).Run(rv); |
+} |
+ |
+int UnixDomainClientSocket::Write(IOBuffer* buf, int buf_len, |
+ const CompletionCallback& callback) { |
+ DCHECK(buf); |
+ DCHECK_LT(0, buf_len); |
+ DCHECK(!callback.is_null()); |
+ DCHECK(write_callback_.is_null()); |
+ |
+ if (!IsConnected()) |
+ return ERR_SOCKET_NOT_CONNECTED; |
+ |
+ int rv = DoWrite(buf, buf_len); |
+ if (rv != ERR_IO_PENDING) |
+ return rv; |
+ |
+ if (!base::MessageLoopForIO::current()->WatchFileDescriptor( |
+ socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE, |
+ &write_socket_watcher_, this)) { |
+ PLOG(ERROR) << "WatchFileDescriptor failed on write"; |
+ return MapSystemError(errno); |
+ } |
+ |
+ write_buf_ = buf; |
+ write_buf_len_ = buf_len; |
+ write_callback_ = callback; |
+ return ERR_IO_PENDING; |
+} |
+ |
+int UnixDomainClientSocket::DoWrite(IOBuffer* buf, int buf_len) { |
+ int rv = HANDLE_EINTR(write(socket_fd_, buf->data(), buf_len)); |
+ return rv >= 0 ? rv : MapSystemError(errno); |
+} |
+ |
+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
|
+ int rv = DoWrite(write_buf_, write_buf_len_); |
+ if (rv == ERR_IO_PENDING) |
+ return; |
+ |
+ write_socket_watcher_.StopWatchingFileDescriptor(); |
+ write_buf_ = NULL; |
+ write_buf_len_ = 0; |
+ base::ResetAndReturn(&write_callback_).Run(rv); |
+} |
+ |
+int UnixDomainClientSocket::SetReceiveBufferSize(int32 size) { |
+ NOTIMPLEMENTED(); |
+ return ERR_NOT_IMPLEMENTED; |
+} |
+ |
+int UnixDomainClientSocket::SetSendBufferSize(int32 size) { |
+ NOTIMPLEMENTED(); |
+ return ERR_NOT_IMPLEMENTED; |
+} |
+ |
+void UnixDomainClientSocket::OnFileCanReadWithoutBlocking(int fd) { |
+ if (read_callback_.is_null()) { |
+ NOTREACHED(); |
+ } else { |
+ DidCompleteRead(); |
+ } |
+} |
+ |
+void UnixDomainClientSocket::OnFileCanWriteWithoutBlocking(int fd) { |
+ if (write_callback_.is_null()) { |
+ 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.
|
+ } else if (waiting_connect_) { |
+ DidCompleteConnect(); |
+ } else { |
+ DidCompleteWrite(); |
+ } |
+} |
+ |
+} // namespace net |