OLD | NEW |
| (Empty) |
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. | |
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> | |
11 | |
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" | |
16 | |
17 namespace net { | |
18 | |
19 namespace { | |
20 | |
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())); | |
25 } | |
26 | |
27 void SetSocketDescriptor(SocketDescriptor* socket, | |
28 scoped_ptr<SocketLibevent> accepted_socket) { | |
29 *socket = accepted_socket->ReleaseConnectedSocket(); | |
30 } | |
31 | |
32 } // anonymous namespace | |
33 | |
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()); | |
40 } | |
41 | |
42 UnixDomainServerSocket::~UnixDomainServerSocket() { | |
43 } | |
44 | |
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 | |
61 } | |
62 | |
63 int UnixDomainServerSocket::Listen(const IPEndPoint& address, int backlog) { | |
64 NOTIMPLEMENTED(); | |
65 return ERR_NOT_IMPLEMENTED; | |
66 } | |
67 | |
68 int UnixDomainServerSocket::ListenWithAddressAndPort( | |
69 const std::string& unix_domain_path, | |
70 uint16 port_unused, | |
71 int backlog) { | |
72 DCHECK(!listen_socket_); | |
73 | |
74 SockaddrStorage address; | |
75 if (!UnixDomainClientSocket::FillAddress(unix_domain_path, | |
76 use_abstract_namespace_, | |
77 &address)) { | |
78 return ERR_ADDRESS_INVALID; | |
79 } | |
80 | |
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; | |
86 | |
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; | |
94 } | |
95 | |
96 rv = socket->Listen(backlog); | |
97 DCHECK_NE(ERR_IO_PENDING, rv); | |
98 if (rv != OK) | |
99 return rv; | |
100 | |
101 listen_socket_.swap(socket); | |
102 return rv; | |
103 } | |
104 | |
105 int UnixDomainServerSocket::GetLocalAddress(IPEndPoint* address) const { | |
106 NOTIMPLEMENTED(); | |
107 return ERR_NOT_IMPLEMENTED; | |
108 } | |
109 | |
110 int UnixDomainServerSocket::Accept(scoped_ptr<StreamSocket>* socket, | |
111 const CompletionCallback& callback) { | |
112 DCHECK(socket); | |
113 | |
114 SetterCallback setter_callback = base::Bind(&SetStreamSocket, socket); | |
115 return DoAccept(setter_callback, callback); | |
116 } | |
117 | |
118 int UnixDomainServerSocket::AcceptSocketDescriptor( | |
119 SocketDescriptor* socket, | |
120 const CompletionCallback& callback) { | |
121 DCHECK(socket); | |
122 | |
123 SetterCallback setter_callback = base::Bind(&SetSocketDescriptor, socket); | |
124 return DoAccept(setter_callback, callback); | |
125 } | |
126 | |
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_); | |
133 | |
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. | |
147 } | |
148 } | |
149 | |
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; | |
157 } | |
158 | |
159 if (AuthenticateAndGetStreamSocket(setter_callback)) { | |
160 callback.Run(OK); | |
161 return; | |
162 } | |
163 | |
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); | |
169 } | |
170 | |
171 bool UnixDomainServerSocket::AuthenticateAndGetStreamSocket( | |
172 const SetterCallback& setter_callback) { | |
173 DCHECK(accept_socket_); | |
174 | |
175 Credentials credentials; | |
176 if (!GetPeerCredentials(accept_socket_->socket_fd(), &credentials) || | |
177 !auth_callback_.Run(credentials)) { | |
178 accept_socket_.reset(); | |
179 return false; | |
180 } | |
181 | |
182 setter_callback.Run(accept_socket_.Pass()); | |
183 return true; | |
184 } | |
185 | |
186 } // namespace net | |
OLD | NEW |