Roll src/third_party/skia e1a828c:3e3b58d
[chromium-blink-merge.git] / net / socket / unix_domain_server_socket_posix.cc
blob6866d3632c7a805c8168c7081076a0db56051e18
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.
5 #include "net/socket/unix_domain_server_socket_posix.h"
7 #include <errno.h>
8 #include <sys/socket.h>
9 #include <sys/un.h>
10 #include <unistd.h>
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"
17 namespace net {
19 namespace {
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()));
27 void SetSocketDescriptor(SocketDescriptor* socket,
28 scoped_ptr<SocketLibevent> accepted_socket) {
29 *socket = accepted_socket->ReleaseConnectedSocket();
32 } // anonymous namespace
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());
42 UnixDomainServerSocket::~UnixDomainServerSocket() {
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
63 int UnixDomainServerSocket::Listen(const IPEndPoint& address, int backlog) {
64 NOTIMPLEMENTED();
65 return ERR_NOT_IMPLEMENTED;
68 int UnixDomainServerSocket::ListenWithAddressAndPort(
69 const std::string& unix_domain_path,
70 uint16 port_unused,
71 int backlog) {
72 DCHECK(!listen_socket_);
74 SockaddrStorage address;
75 if (!UnixDomainClientSocket::FillAddress(unix_domain_path,
76 use_abstract_namespace_,
77 &address)) {
78 return ERR_ADDRESS_INVALID;
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;
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;
96 rv = socket->Listen(backlog);
97 DCHECK_NE(ERR_IO_PENDING, rv);
98 if (rv != OK)
99 return rv;
101 listen_socket_.swap(socket);
102 return rv;
105 int UnixDomainServerSocket::GetLocalAddress(IPEndPoint* address) const {
106 NOTIMPLEMENTED();
107 return ERR_NOT_IMPLEMENTED;
110 int UnixDomainServerSocket::Accept(scoped_ptr<StreamSocket>* socket,
111 const CompletionCallback& callback) {
112 DCHECK(socket);
114 SetterCallback setter_callback = base::Bind(&SetStreamSocket, socket);
115 return DoAccept(setter_callback, callback);
118 int UnixDomainServerSocket::AcceptSocketDescriptor(
119 SocketDescriptor* socket,
120 const CompletionCallback& callback) {
121 DCHECK(socket);
123 SetterCallback setter_callback = base::Bind(&SetSocketDescriptor, socket);
124 return DoAccept(setter_callback, callback);
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_);
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.
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;
159 if (AuthenticateAndGetStreamSocket(setter_callback)) {
160 callback.Run(OK);
161 return;
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);
171 bool UnixDomainServerSocket::AuthenticateAndGetStreamSocket(
172 const SetterCallback& setter_callback) {
173 DCHECK(accept_socket_);
175 Credentials credentials;
176 if (!GetPeerCredentials(accept_socket_->socket_fd(), &credentials) ||
177 !auth_callback_.Run(credentials)) {
178 accept_socket_.reset();
179 return false;
182 setter_callback.Run(accept_socket_.Pass());
183 return true;
186 } // namespace net