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"
8 #include <sys/socket.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"
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() {
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)
53 credentials
->process_id
= user_cred
.pid
;
54 credentials
->user_id
= user_cred
.uid
;
55 credentials
->group_id
= user_cred
.gid
;
59 socket
, &credentials
->user_id
, &credentials
->group_id
) == 0;
63 int UnixDomainServerSocket::Listen(const IPEndPoint
& address
, int backlog
) {
65 return ERR_NOT_IMPLEMENTED
;
68 int UnixDomainServerSocket::ListenWithAddressAndPort(
69 const std::string
& unix_domain_path
,
72 DCHECK(!listen_socket_
);
74 SockaddrStorage address
;
75 if (!UnixDomainClientSocket::FillAddress(unix_domain_path
,
76 use_abstract_namespace_
,
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
);
87 rv
= socket
->Bind(address
);
88 DCHECK_NE(ERR_IO_PENDING
, rv
);
91 << "Could not bind unix domain socket to " << unix_domain_path
92 << (use_abstract_namespace_
? " (with abstract namespace)" : "");
96 rv
= socket
->Listen(backlog
);
97 DCHECK_NE(ERR_IO_PENDING
, rv
);
101 listen_socket_
.swap(socket
);
105 int UnixDomainServerSocket::GetLocalAddress(IPEndPoint
* address
) const {
107 return ERR_NOT_IMPLEMENTED
;
110 int UnixDomainServerSocket::Accept(scoped_ptr
<StreamSocket
>* socket
,
111 const CompletionCallback
& callback
) {
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
) {
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_
);
135 int rv
= listen_socket_
->Accept(
137 base::Bind(&UnixDomainServerSocket::AcceptCompleted
,
138 base::Unretained(this),
143 if (AuthenticateAndGetStreamSocket(setter_callback
))
145 // Accept another socket because authentication error should be transparent
150 void UnixDomainServerSocket::AcceptCompleted(
151 const SetterCallback
& setter_callback
,
152 const CompletionCallback
& callback
,
159 if (AuthenticateAndGetStreamSocket(setter_callback
)) {
164 // Accept another socket because authentication error should be transparent
166 rv
= DoAccept(setter_callback
, callback
);
167 if (rv
!= ERR_IO_PENDING
)
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();
182 setter_callback
.Run(accept_socket_
.Pass());