Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / socket / unix_domain_server_socket_posix.cc
blobee327ac0eb5162c5f20f43a184ffad6f38a344f3
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 DCHECK(address);
108 // Unix domain sockets have no valid associated addr/port;
109 // return address invalid.
110 return ERR_ADDRESS_INVALID;
113 int UnixDomainServerSocket::Accept(scoped_ptr<StreamSocket>* socket,
114 const CompletionCallback& callback) {
115 DCHECK(socket);
117 SetterCallback setter_callback = base::Bind(&SetStreamSocket, socket);
118 return DoAccept(setter_callback, callback);
121 int UnixDomainServerSocket::AcceptSocketDescriptor(
122 SocketDescriptor* socket,
123 const CompletionCallback& callback) {
124 DCHECK(socket);
126 SetterCallback setter_callback = base::Bind(&SetSocketDescriptor, socket);
127 return DoAccept(setter_callback, callback);
130 int UnixDomainServerSocket::DoAccept(const SetterCallback& setter_callback,
131 const CompletionCallback& callback) {
132 DCHECK(!setter_callback.is_null());
133 DCHECK(!callback.is_null());
134 DCHECK(listen_socket_);
135 DCHECK(!accept_socket_);
137 while (true) {
138 int rv = listen_socket_->Accept(
139 &accept_socket_,
140 base::Bind(&UnixDomainServerSocket::AcceptCompleted,
141 base::Unretained(this),
142 setter_callback,
143 callback));
144 if (rv != OK)
145 return rv;
146 if (AuthenticateAndGetStreamSocket(setter_callback))
147 return OK;
148 // Accept another socket because authentication error should be transparent
149 // to the caller.
153 void UnixDomainServerSocket::AcceptCompleted(
154 const SetterCallback& setter_callback,
155 const CompletionCallback& callback,
156 int rv) {
157 if (rv != OK) {
158 callback.Run(rv);
159 return;
162 if (AuthenticateAndGetStreamSocket(setter_callback)) {
163 callback.Run(OK);
164 return;
167 // Accept another socket because authentication error should be transparent
168 // to the caller.
169 rv = DoAccept(setter_callback, callback);
170 if (rv != ERR_IO_PENDING)
171 callback.Run(rv);
174 bool UnixDomainServerSocket::AuthenticateAndGetStreamSocket(
175 const SetterCallback& setter_callback) {
176 DCHECK(accept_socket_);
178 Credentials credentials;
179 if (!GetPeerCredentials(accept_socket_->socket_fd(), &credentials) ||
180 !auth_callback_.Run(credentials)) {
181 accept_socket_.reset();
182 return false;
185 setter_callback.Run(accept_socket_.Pass());
186 return true;
189 } // namespace net