blob: 2bea30eb31e94a53e9eeb1a37569b9e81d5ba936 [file] [log] [blame]
[email protected]518c63a2014-07-24 03:51:231// 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>
dchengc7eeda422015-12-26 03:56:4811#include <utility>
[email protected]518c63a2014-07-24 03:51:2312
13#include "base/logging.h"
Sergey Ulanov49085572017-07-10 23:25:4614#include "build/build_config.h"
[email protected]518c63a2014-07-24 03:51:2315#include "net/base/net_errors.h"
tfarina3d87d7cd2016-01-13 02:26:5916#include "net/base/sockaddr_storage.h"
tfarina4eb7aad82015-09-14 17:10:3417#include "net/socket/socket_posix.h"
[email protected]518c63a2014-07-24 03:51:2318#include "net/socket/unix_domain_client_socket_posix.h"
19
20namespace net {
21
cmasoneca100d52014-09-03 18:11:1122namespace {
23
24// Intended for use as SetterCallbacks in Accept() helper methods.
danakj655b66c2016-04-16 00:51:3825void SetStreamSocket(std::unique_ptr<StreamSocket>* socket,
26 std::unique_ptr<SocketPosix> accepted_socket) {
dchengc7eeda422015-12-26 03:56:4827 socket->reset(new UnixDomainClientSocket(std::move(accepted_socket)));
cmasoneca100d52014-09-03 18:11:1128}
29
30void SetSocketDescriptor(SocketDescriptor* socket,
danakj655b66c2016-04-16 00:51:3831 std::unique_ptr<SocketPosix> accepted_socket) {
cmasoneca100d52014-09-03 18:11:1132 *socket = accepted_socket->ReleaseConnectedSocket();
33}
34
35} // anonymous namespace
36
[email protected]518c63a2014-07-24 03:51:2337UnixDomainServerSocket::UnixDomainServerSocket(
38 const AuthCallback& auth_callback,
39 bool use_abstract_namespace)
40 : auth_callback_(auth_callback),
41 use_abstract_namespace_(use_abstract_namespace) {
42 DCHECK(!auth_callback_.is_null());
43}
44
Chris Watkins7a41d3552017-12-01 02:13:2745UnixDomainServerSocket::~UnixDomainServerSocket() = default;
[email protected]518c63a2014-07-24 03:51:2346
47// static
[email protected]fe928be92014-08-08 09:17:4148bool UnixDomainServerSocket::GetPeerCredentials(SocketDescriptor socket,
49 Credentials* credentials) {
Sergey Ulanov49085572017-07-10 23:25:4650#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
[email protected]518c63a2014-07-24 03:51:2351 struct ucred user_cred;
52 socklen_t len = sizeof(user_cred);
53 if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &user_cred, &len) < 0)
54 return false;
[email protected]fe928be92014-08-08 09:17:4155 credentials->process_id = user_cred.pid;
56 credentials->user_id = user_cred.uid;
57 credentials->group_id = user_cred.gid;
[email protected]518c63a2014-07-24 03:51:2358 return true;
59#else
[email protected]fe928be92014-08-08 09:17:4160 return getpeereid(
61 socket, &credentials->user_id, &credentials->group_id) == 0;
[email protected]518c63a2014-07-24 03:51:2362#endif
63}
64
65int UnixDomainServerSocket::Listen(const IPEndPoint& address, int backlog) {
66 NOTIMPLEMENTED();
67 return ERR_NOT_IMPLEMENTED;
68}
69
bcf5cbaa772016-02-24 02:22:3070int UnixDomainServerSocket::ListenWithAddressAndPort(
71 const std::string& address_string,
72 uint16_t port,
73 int backlog) {
74 NOTIMPLEMENTED();
75 return ERR_NOT_IMPLEMENTED;
76}
77
tfarinaa7b245d2016-02-02 02:03:4978int UnixDomainServerSocket::BindAndListen(const std::string& socket_path,
79 int backlog) {
[email protected]518c63a2014-07-24 03:51:2380 DCHECK(!listen_socket_);
81
82 SockaddrStorage address;
tfarinaa7b245d2016-02-02 02:03:4983 if (!UnixDomainClientSocket::FillAddress(socket_path,
[email protected]518c63a2014-07-24 03:51:2384 use_abstract_namespace_,
85 &address)) {
86 return ERR_ADDRESS_INVALID;
87 }
88
danakj655b66c2016-04-16 00:51:3889 std::unique_ptr<SocketPosix> socket(new SocketPosix);
byungchul14ac2482014-08-27 23:04:2690 int rv = socket->Open(AF_UNIX);
[email protected]518c63a2014-07-24 03:51:2391 DCHECK_NE(ERR_IO_PENDING, rv);
92 if (rv != OK)
93 return rv;
94
byungchul14ac2482014-08-27 23:04:2695 rv = socket->Bind(address);
[email protected]518c63a2014-07-24 03:51:2396 DCHECK_NE(ERR_IO_PENDING, rv);
97 if (rv != OK) {
98 PLOG(ERROR)
tfarinaa7b245d2016-02-02 02:03:4999 << "Could not bind unix domain socket to " << socket_path
[email protected]518c63a2014-07-24 03:51:23100 << (use_abstract_namespace_ ? " (with abstract namespace)" : "");
101 return rv;
102 }
103
byungchul14ac2482014-08-27 23:04:26104 rv = socket->Listen(backlog);
105 DCHECK_NE(ERR_IO_PENDING, rv);
106 if (rv != OK)
107 return rv;
108
109 listen_socket_.swap(socket);
110 return rv;
[email protected]518c63a2014-07-24 03:51:23111}
112
113int UnixDomainServerSocket::GetLocalAddress(IPEndPoint* address) const {
tobiasjs72395bd2015-07-06 10:06:53114 DCHECK(address);
115
116 // Unix domain sockets have no valid associated addr/port;
117 // return address invalid.
118 return ERR_ADDRESS_INVALID;
[email protected]518c63a2014-07-24 03:51:23119}
120
danakj655b66c2016-04-16 00:51:38121int UnixDomainServerSocket::Accept(std::unique_ptr<StreamSocket>* socket,
[email protected]518c63a2014-07-24 03:51:23122 const CompletionCallback& callback) {
123 DCHECK(socket);
cmasoneca100d52014-09-03 18:11:11124
125 SetterCallback setter_callback = base::Bind(&SetStreamSocket, socket);
126 return DoAccept(setter_callback, callback);
127}
128
129int UnixDomainServerSocket::AcceptSocketDescriptor(
130 SocketDescriptor* socket,
131 const CompletionCallback& callback) {
132 DCHECK(socket);
133
134 SetterCallback setter_callback = base::Bind(&SetSocketDescriptor, socket);
135 return DoAccept(setter_callback, callback);
136}
137
138int UnixDomainServerSocket::DoAccept(const SetterCallback& setter_callback,
139 const CompletionCallback& callback) {
140 DCHECK(!setter_callback.is_null());
[email protected]518c63a2014-07-24 03:51:23141 DCHECK(!callback.is_null());
142 DCHECK(listen_socket_);
143 DCHECK(!accept_socket_);
144
145 while (true) {
146 int rv = listen_socket_->Accept(
147 &accept_socket_,
148 base::Bind(&UnixDomainServerSocket::AcceptCompleted,
cmasoneca100d52014-09-03 18:11:11149 base::Unretained(this),
150 setter_callback,
151 callback));
[email protected]518c63a2014-07-24 03:51:23152 if (rv != OK)
153 return rv;
cmasoneca100d52014-09-03 18:11:11154 if (AuthenticateAndGetStreamSocket(setter_callback))
[email protected]518c63a2014-07-24 03:51:23155 return OK;
156 // Accept another socket because authentication error should be transparent
157 // to the caller.
158 }
159}
160
cmasoneca100d52014-09-03 18:11:11161void UnixDomainServerSocket::AcceptCompleted(
162 const SetterCallback& setter_callback,
163 const CompletionCallback& callback,
164 int rv) {
[email protected]518c63a2014-07-24 03:51:23165 if (rv != OK) {
166 callback.Run(rv);
167 return;
168 }
169
cmasoneca100d52014-09-03 18:11:11170 if (AuthenticateAndGetStreamSocket(setter_callback)) {
[email protected]518c63a2014-07-24 03:51:23171 callback.Run(OK);
172 return;
173 }
174
175 // Accept another socket because authentication error should be transparent
176 // to the caller.
cmasoneca100d52014-09-03 18:11:11177 rv = DoAccept(setter_callback, callback);
[email protected]518c63a2014-07-24 03:51:23178 if (rv != ERR_IO_PENDING)
179 callback.Run(rv);
180}
181
182bool UnixDomainServerSocket::AuthenticateAndGetStreamSocket(
cmasoneca100d52014-09-03 18:11:11183 const SetterCallback& setter_callback) {
[email protected]518c63a2014-07-24 03:51:23184 DCHECK(accept_socket_);
185
[email protected]fe928be92014-08-08 09:17:41186 Credentials credentials;
187 if (!GetPeerCredentials(accept_socket_->socket_fd(), &credentials) ||
188 !auth_callback_.Run(credentials)) {
[email protected]518c63a2014-07-24 03:51:23189 accept_socket_.reset();
190 return false;
191 }
192
dchengc7eeda422015-12-26 03:56:48193 setter_callback.Run(std::move(accept_socket_));
[email protected]518c63a2014-07-24 03:51:23194 return true;
195}
196
197} // namespace net