| Index: net/socket/unix_domain_server_socket_posix.cc
|
| diff --git a/net/socket/unix_domain_server_socket_posix.cc b/net/socket/unix_domain_server_socket_posix.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cd6ad1575a1e5de6454ab60b2c402686c787c1e8
|
| --- /dev/null
|
| +++ b/net/socket/unix_domain_server_socket_posix.cc
|
| @@ -0,0 +1,141 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "net/socket/unix_domain_server_socket_posix.h"
|
| +
|
| +#include <errno.h>
|
| +#include <sys/socket.h>
|
| +#include <sys/un.h>
|
| +#include <unistd.h>
|
| +
|
| +#include "base/logging.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/socket/socket_libevent.h"
|
| +#include "net/socket/unix_domain_client_socket_posix.h"
|
| +
|
| +namespace net {
|
| +
|
| +UnixDomainServerSocket::UnixDomainServerSocket(
|
| + const AuthCallback& auth_callback,
|
| + bool use_abstract_namespace)
|
| + : auth_callback_(auth_callback),
|
| + use_abstract_namespace_(use_abstract_namespace) {
|
| +}
|
| +
|
| +UnixDomainServerSocket::~UnixDomainServerSocket() {
|
| +}
|
| +
|
| +// static
|
| +bool UnixDomainServerSocket::GetPeerIds(SocketDescriptor socket,
|
| + uid_t* user_id,
|
| + gid_t* group_id) {
|
| +#if defined(OS_LINUX) || defined(OS_ANDROID)
|
| + struct ucred user_cred;
|
| + socklen_t len = sizeof(user_cred);
|
| + if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &user_cred, &len) < 0)
|
| + return false;
|
| + *user_id = user_cred.uid;
|
| + *group_id = user_cred.gid;
|
| +#else
|
| + if (getpeereid(socket, user_id, group_id) < 0)
|
| + return false;
|
| +#endif
|
| + return true;
|
| +}
|
| +
|
| +int UnixDomainServerSocket::Listen(const IPEndPoint& address, int backlog) {
|
| + NOTIMPLEMENTED();
|
| + return ERR_NOT_IMPLEMENTED;
|
| +}
|
| +
|
| +int UnixDomainServerSocket::ListenWithAddressAndPort(
|
| + const std::string& unix_domain_path,
|
| + int port_unused,
|
| + int backlog) {
|
| + DCHECK(!listen_socket_);
|
| +
|
| + SockaddrStorage address;
|
| + if (!UnixDomainClientSocket::FillAddress(unix_domain_path,
|
| + use_abstract_namespace_,
|
| + &address)) {
|
| + return ERR_ADDRESS_INVALID;
|
| + }
|
| +
|
| + listen_socket_.reset(new SocketLibevent);
|
| + int rv = listen_socket_->Open(AF_UNIX);
|
| + if (rv != OK)
|
| + return rv;
|
| +
|
| + rv = listen_socket_->Bind(address);
|
| + if (rv != OK) {
|
| + PLOG(ERROR)
|
| + << "Could not bind unix domain socket to " << unix_domain_path
|
| + << (use_abstract_namespace_ ? " (with abstract namespace)" : "");
|
| + return rv;
|
| + }
|
| +
|
| + return listen_socket_->Listen(backlog);
|
| +}
|
| +
|
| +int UnixDomainServerSocket::GetLocalAddress(IPEndPoint* address) const {
|
| + NOTIMPLEMENTED();
|
| + return ERR_NOT_IMPLEMENTED;
|
| +}
|
| +
|
| +int UnixDomainServerSocket::Accept(scoped_ptr<StreamSocket>* socket,
|
| + const CompletionCallback& callback) {
|
| + DCHECK(socket);
|
| + DCHECK(!callback.is_null());
|
| + DCHECK(listen_socket_);
|
| + DCHECK(!accept_socket_);
|
| +
|
| + while (true) {
|
| + int rv = listen_socket_->Accept(
|
| + &accept_socket_,
|
| + base::Bind(&UnixDomainServerSocket::AcceptCompleted,
|
| + base::Unretained(this), socket, callback));
|
| + if (rv != OK)
|
| + return rv;
|
| + if (AuthenticateAndGetStreamSocket(socket))
|
| + return OK;
|
| + }
|
| +}
|
| +
|
| +void UnixDomainServerSocket::AcceptCompleted(scoped_ptr<StreamSocket>* socket,
|
| + const CompletionCallback& callback,
|
| + int rv) {
|
| + if (rv != OK) {
|
| + callback.Run(rv);
|
| + return;
|
| + }
|
| +
|
| + if (AuthenticateAndGetStreamSocket(socket)) {
|
| + callback.Run(OK);
|
| + return;
|
| + }
|
| +
|
| + // Accepts another socket because authentication error should be transparent
|
| + // to the caller.
|
| + rv = Accept(socket, callback);
|
| + if (rv != ERR_IO_PENDING)
|
| + callback.Run(rv);
|
| +}
|
| +
|
| +bool UnixDomainServerSocket::AuthenticateAndGetStreamSocket(
|
| + scoped_ptr<StreamSocket>* socket) {
|
| + DCHECK(accept_socket_);
|
| +
|
| + uid_t user_id;
|
| + gid_t group_id;
|
| + if (!GetPeerIds(accept_socket_->socket_fd(), &user_id, &group_id) ||
|
| + !auth_callback_.Run(user_id, group_id)) {
|
| + accept_socket_.reset();
|
| + return false;
|
| + }
|
| +
|
| + socket->reset(new UnixDomainClientSocket(accept_socket_.Pass()));
|
| + return true;
|
| +}
|
| +
|
| +} // namespace net
|
|
|