| 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_server_socket_posix.h" | |
| 6 | |
| 7 #include <errno.h> | |
| 8 #include <sys/socket.h> | |
| 9 #include <sys/un.h> | |
| 10 #include <unistd.h> | |
| 11 | |
| 12 #include "base/logging.h" | |
| 13 #include "net/base/net_errors.h" | |
| 14 #include "net/socket/socket_libevent.h" | |
| 15 #include "net/socket/unix_domain_client_socket_posix.h" | |
| 16 | |
| 17 namespace net { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 // Intended for use as SetterCallbacks in Accept() helper methods. | |
| 22 void SetStreamSocket(scoped_ptr<StreamSocket>* socket, | |
| 23 scoped_ptr<SocketLibevent> accepted_socket) { | |
| 24 socket->reset(new UnixDomainClientSocket(accepted_socket.Pass())); | |
| 25 } | |
| 26 | |
| 27 void SetSocketDescriptor(SocketDescriptor* socket, | |
| 28 scoped_ptr<SocketLibevent> accepted_socket) { | |
| 29 *socket = accepted_socket->ReleaseConnectedSocket(); | |
| 30 } | |
| 31 | |
| 32 } // anonymous namespace | |
| 33 | |
| 34 UnixDomainServerSocket::UnixDomainServerSocket( | |
| 35 const AuthCallback& auth_callback, | |
| 36 bool use_abstract_namespace) | |
| 37 : auth_callback_(auth_callback), | |
| 38 use_abstract_namespace_(use_abstract_namespace) { | |
| 39 DCHECK(!auth_callback_.is_null()); | |
| 40 } | |
| 41 | |
| 42 UnixDomainServerSocket::~UnixDomainServerSocket() { | |
| 43 } | |
| 44 | |
| 45 // static | |
| 46 bool UnixDomainServerSocket::GetPeerCredentials(SocketDescriptor socket, | |
| 47 Credentials* credentials) { | |
| 48 #if defined(OS_LINUX) || defined(OS_ANDROID) | |
| 49 struct ucred user_cred; | |
| 50 socklen_t len = sizeof(user_cred); | |
| 51 if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &user_cred, &len) < 0) | |
| 52 return false; | |
| 53 credentials->process_id = user_cred.pid; | |
| 54 credentials->user_id = user_cred.uid; | |
| 55 credentials->group_id = user_cred.gid; | |
| 56 return true; | |
| 57 #else | |
| 58 return getpeereid( | |
| 59 socket, &credentials->user_id, &credentials->group_id) == 0; | |
| 60 #endif | |
| 61 } | |
| 62 | |
| 63 int UnixDomainServerSocket::Listen(const IPEndPoint& address, int backlog) { | |
| 64 NOTIMPLEMENTED(); | |
| 65 return ERR_NOT_IMPLEMENTED; | |
| 66 } | |
| 67 | |
| 68 int UnixDomainServerSocket::ListenWithAddressAndPort( | |
| 69 const std::string& unix_domain_path, | |
| 70 uint16 port_unused, | |
| 71 int backlog) { | |
| 72 DCHECK(!listen_socket_); | |
| 73 | |
| 74 SockaddrStorage address; | |
| 75 if (!UnixDomainClientSocket::FillAddress(unix_domain_path, | |
| 76 use_abstract_namespace_, | |
| 77 &address)) { | |
| 78 return ERR_ADDRESS_INVALID; | |
| 79 } | |
| 80 | |
| 81 scoped_ptr<SocketLibevent> socket(new SocketLibevent); | |
| 82 int rv = socket->Open(AF_UNIX); | |
| 83 DCHECK_NE(ERR_IO_PENDING, rv); | |
| 84 if (rv != OK) | |
| 85 return rv; | |
| 86 | |
| 87 rv = socket->Bind(address); | |
| 88 DCHECK_NE(ERR_IO_PENDING, rv); | |
| 89 if (rv != OK) { | |
| 90 PLOG(ERROR) | |
| 91 << "Could not bind unix domain socket to " << unix_domain_path | |
| 92 << (use_abstract_namespace_ ? " (with abstract namespace)" : ""); | |
| 93 return rv; | |
| 94 } | |
| 95 | |
| 96 rv = socket->Listen(backlog); | |
| 97 DCHECK_NE(ERR_IO_PENDING, rv); | |
| 98 if (rv != OK) | |
| 99 return rv; | |
| 100 | |
| 101 listen_socket_.swap(socket); | |
| 102 return rv; | |
| 103 } | |
| 104 | |
| 105 int UnixDomainServerSocket::GetLocalAddress(IPEndPoint* address) const { | |
| 106 NOTIMPLEMENTED(); | |
| 107 return ERR_NOT_IMPLEMENTED; | |
| 108 } | |
| 109 | |
| 110 int UnixDomainServerSocket::Accept(scoped_ptr<StreamSocket>* socket, | |
| 111 const CompletionCallback& callback) { | |
| 112 DCHECK(socket); | |
| 113 | |
| 114 SetterCallback setter_callback = base::Bind(&SetStreamSocket, socket); | |
| 115 return DoAccept(setter_callback, callback); | |
| 116 } | |
| 117 | |
| 118 int UnixDomainServerSocket::AcceptSocketDescriptor( | |
| 119 SocketDescriptor* socket, | |
| 120 const CompletionCallback& callback) { | |
| 121 DCHECK(socket); | |
| 122 | |
| 123 SetterCallback setter_callback = base::Bind(&SetSocketDescriptor, socket); | |
| 124 return DoAccept(setter_callback, callback); | |
| 125 } | |
| 126 | |
| 127 int UnixDomainServerSocket::DoAccept(const SetterCallback& setter_callback, | |
| 128 const CompletionCallback& callback) { | |
| 129 DCHECK(!setter_callback.is_null()); | |
| 130 DCHECK(!callback.is_null()); | |
| 131 DCHECK(listen_socket_); | |
| 132 DCHECK(!accept_socket_); | |
| 133 | |
| 134 while (true) { | |
| 135 int rv = listen_socket_->Accept( | |
| 136 &accept_socket_, | |
| 137 base::Bind(&UnixDomainServerSocket::AcceptCompleted, | |
| 138 base::Unretained(this), | |
| 139 setter_callback, | |
| 140 callback)); | |
| 141 if (rv != OK) | |
| 142 return rv; | |
| 143 if (AuthenticateAndGetStreamSocket(setter_callback)) | |
| 144 return OK; | |
| 145 // Accept another socket because authentication error should be transparent | |
| 146 // to the caller. | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 void UnixDomainServerSocket::AcceptCompleted( | |
| 151 const SetterCallback& setter_callback, | |
| 152 const CompletionCallback& callback, | |
| 153 int rv) { | |
| 154 if (rv != OK) { | |
| 155 callback.Run(rv); | |
| 156 return; | |
| 157 } | |
| 158 | |
| 159 if (AuthenticateAndGetStreamSocket(setter_callback)) { | |
| 160 callback.Run(OK); | |
| 161 return; | |
| 162 } | |
| 163 | |
| 164 // Accept another socket because authentication error should be transparent | |
| 165 // to the caller. | |
| 166 rv = DoAccept(setter_callback, callback); | |
| 167 if (rv != ERR_IO_PENDING) | |
| 168 callback.Run(rv); | |
| 169 } | |
| 170 | |
| 171 bool UnixDomainServerSocket::AuthenticateAndGetStreamSocket( | |
| 172 const SetterCallback& setter_callback) { | |
| 173 DCHECK(accept_socket_); | |
| 174 | |
| 175 Credentials credentials; | |
| 176 if (!GetPeerCredentials(accept_socket_->socket_fd(), &credentials) || | |
| 177 !auth_callback_.Run(credentials)) { | |
| 178 accept_socket_.reset(); | |
| 179 return false; | |
| 180 } | |
| 181 | |
| 182 setter_callback.Run(accept_socket_.Pass()); | |
| 183 return true; | |
| 184 } | |
| 185 | |
| 186 } // namespace net | |
| OLD | NEW |