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"
19 UnixDomainServerSocket::UnixDomainServerSocket(
20 const AuthCallback
& auth_callback
,
21 bool use_abstract_namespace
)
22 : auth_callback_(auth_callback
),
23 use_abstract_namespace_(use_abstract_namespace
) {
24 DCHECK(!auth_callback_
.is_null());
27 UnixDomainServerSocket::~UnixDomainServerSocket() {
31 bool UnixDomainServerSocket::GetPeerCredentials(SocketDescriptor socket
,
32 Credentials
* credentials
) {
33 #if defined(OS_LINUX) || defined(OS_ANDROID)
34 struct ucred user_cred
;
35 socklen_t len
= sizeof(user_cred
);
36 if (getsockopt(socket
, SOL_SOCKET
, SO_PEERCRED
, &user_cred
, &len
) < 0)
38 credentials
->process_id
= user_cred
.pid
;
39 credentials
->user_id
= user_cred
.uid
;
40 credentials
->group_id
= user_cred
.gid
;
44 socket
, &credentials
->user_id
, &credentials
->group_id
) == 0;
48 int UnixDomainServerSocket::Listen(const IPEndPoint
& address
, int backlog
) {
50 return ERR_NOT_IMPLEMENTED
;
53 int UnixDomainServerSocket::ListenWithAddressAndPort(
54 const std::string
& unix_domain_path
,
57 DCHECK(!listen_socket_
);
59 SockaddrStorage address
;
60 if (!UnixDomainClientSocket::FillAddress(unix_domain_path
,
61 use_abstract_namespace_
,
63 return ERR_ADDRESS_INVALID
;
66 scoped_ptr
<SocketLibevent
> socket(new SocketLibevent
);
67 int rv
= socket
->Open(AF_UNIX
);
68 DCHECK_NE(ERR_IO_PENDING
, rv
);
72 rv
= socket
->Bind(address
);
73 DCHECK_NE(ERR_IO_PENDING
, rv
);
76 << "Could not bind unix domain socket to " << unix_domain_path
77 << (use_abstract_namespace_
? " (with abstract namespace)" : "");
81 rv
= socket
->Listen(backlog
);
82 DCHECK_NE(ERR_IO_PENDING
, rv
);
86 listen_socket_
.swap(socket
);
90 int UnixDomainServerSocket::GetLocalAddress(IPEndPoint
* address
) const {
92 return ERR_NOT_IMPLEMENTED
;
95 int UnixDomainServerSocket::Accept(scoped_ptr
<StreamSocket
>* socket
,
96 const CompletionCallback
& callback
) {
98 DCHECK(!callback
.is_null());
99 DCHECK(listen_socket_
);
100 DCHECK(!accept_socket_
);
103 int rv
= listen_socket_
->Accept(
105 base::Bind(&UnixDomainServerSocket::AcceptCompleted
,
106 base::Unretained(this), socket
, callback
));
109 if (AuthenticateAndGetStreamSocket(socket
))
111 // Accept another socket because authentication error should be transparent
116 void UnixDomainServerSocket::AcceptCompleted(scoped_ptr
<StreamSocket
>* socket
,
117 const CompletionCallback
& callback
,
124 if (AuthenticateAndGetStreamSocket(socket
)) {
129 // Accept another socket because authentication error should be transparent
131 rv
= Accept(socket
, callback
);
132 if (rv
!= ERR_IO_PENDING
)
136 bool UnixDomainServerSocket::AuthenticateAndGetStreamSocket(
137 scoped_ptr
<StreamSocket
>* socket
) {
138 DCHECK(accept_socket_
);
140 Credentials credentials
;
141 if (!GetPeerCredentials(accept_socket_
->socket_fd(), &credentials
) ||
142 !auth_callback_
.Run(credentials
)) {
143 accept_socket_
.reset();
147 socket
->reset(new UnixDomainClientSocket(accept_socket_
.Pass()));