123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- // 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 <utility>
- #include "base/bind.h"
- #include "base/logging.h"
- #include "build/build_config.h"
- #include "net/base/net_errors.h"
- #include "net/base/sockaddr_storage.h"
- #include "net/base/sockaddr_util_posix.h"
- #include "net/socket/socket_posix.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) {
- DCHECK(!auth_callback_.is_null());
- }
- UnixDomainServerSocket::~UnixDomainServerSocket() = default;
- // static
- bool UnixDomainServerSocket::GetPeerCredentials(SocketDescriptor socket,
- Credentials* credentials) {
- #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
- BUILDFLAG(IS_FUCHSIA)
- struct ucred user_cred;
- socklen_t len = sizeof(user_cred);
- if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &user_cred, &len) < 0)
- return false;
- credentials->process_id = user_cred.pid;
- credentials->user_id = user_cred.uid;
- credentials->group_id = user_cred.gid;
- return true;
- #else
- return getpeereid(
- socket, &credentials->user_id, &credentials->group_id) == 0;
- #endif
- }
- int UnixDomainServerSocket::Listen(const IPEndPoint& address, int backlog) {
- NOTIMPLEMENTED();
- return ERR_NOT_IMPLEMENTED;
- }
- int UnixDomainServerSocket::ListenWithAddressAndPort(
- const std::string& address_string,
- uint16_t port,
- int backlog) {
- NOTIMPLEMENTED();
- return ERR_NOT_IMPLEMENTED;
- }
- int UnixDomainServerSocket::BindAndListen(const std::string& socket_path,
- int backlog) {
- DCHECK(!listen_socket_);
- SockaddrStorage address;
- if (!FillUnixAddress(socket_path, use_abstract_namespace_, &address)) {
- return ERR_ADDRESS_INVALID;
- }
- auto socket = std::make_unique<SocketPosix>();
- int rv = socket->Open(AF_UNIX);
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv != OK)
- return rv;
- rv = socket->Bind(address);
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv != OK) {
- PLOG(ERROR)
- << "Could not bind unix domain socket to " << socket_path
- << (use_abstract_namespace_ ? " (with abstract namespace)" : "");
- return rv;
- }
- rv = socket->Listen(backlog);
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv != OK)
- return rv;
- listen_socket_.swap(socket);
- return rv;
- }
- int UnixDomainServerSocket::GetLocalAddress(IPEndPoint* address) const {
- DCHECK(address);
- // Unix domain sockets have no valid associated addr/port;
- // return address invalid.
- return ERR_ADDRESS_INVALID;
- }
- int UnixDomainServerSocket::Accept(std::unique_ptr<StreamSocket>* socket,
- CompletionOnceCallback callback) {
- DCHECK(socket);
- DCHECK(callback);
- DCHECK(!callback_ && !out_socket_.stream && !out_socket_.descriptor);
- out_socket_ = {socket, nullptr};
- int rv = DoAccept();
- if (rv == ERR_IO_PENDING)
- callback_ = std::move(callback);
- else
- CancelCallback();
- return rv;
- }
- int UnixDomainServerSocket::AcceptSocketDescriptor(
- SocketDescriptor* socket,
- CompletionOnceCallback callback) {
- DCHECK(socket);
- DCHECK(callback);
- DCHECK(!callback_ && !out_socket_.stream && !out_socket_.descriptor);
- out_socket_ = {nullptr, socket};
- int rv = DoAccept();
- if (rv == ERR_IO_PENDING)
- callback_ = std::move(callback);
- else
- CancelCallback();
- return rv;
- }
- int UnixDomainServerSocket::DoAccept() {
- DCHECK(listen_socket_);
- DCHECK(!accept_socket_);
- while (true) {
- int rv = listen_socket_->Accept(
- &accept_socket_,
- base::BindOnce(&UnixDomainServerSocket::AcceptCompleted,
- base::Unretained(this)));
- if (rv != OK)
- return rv;
- if (AuthenticateAndGetStreamSocket())
- return OK;
- // Accept another socket because authentication error should be transparent
- // to the caller.
- }
- }
- void UnixDomainServerSocket::AcceptCompleted(int rv) {
- DCHECK(!callback_.is_null());
- if (rv != OK) {
- RunCallback(rv);
- return;
- }
- if (AuthenticateAndGetStreamSocket()) {
- RunCallback(OK);
- return;
- }
- // Accept another socket because authentication error should be transparent
- // to the caller.
- rv = DoAccept();
- if (rv != ERR_IO_PENDING)
- RunCallback(rv);
- }
- bool UnixDomainServerSocket::AuthenticateAndGetStreamSocket() {
- DCHECK(accept_socket_);
- Credentials credentials;
- if (!GetPeerCredentials(accept_socket_->socket_fd(), &credentials) ||
- !auth_callback_.Run(credentials)) {
- accept_socket_.reset();
- return false;
- }
- SetSocketResult(std::move(accept_socket_));
- return true;
- }
- void UnixDomainServerSocket::SetSocketResult(
- std::unique_ptr<SocketPosix> accepted_socket) {
- // Exactly one of the output pointers should be set.
- DCHECK_NE(!!out_socket_.stream, !!out_socket_.descriptor);
- // Pass ownership of |accepted_socket|.
- if (out_socket_.descriptor) {
- *out_socket_.descriptor = accepted_socket->ReleaseConnectedSocket();
- return;
- }
- *out_socket_.stream =
- std::make_unique<UnixDomainClientSocket>(std::move(accepted_socket));
- }
- void UnixDomainServerSocket::RunCallback(int rv) {
- out_socket_ = SocketDestination();
- std::move(callback_).Run(rv);
- }
- void UnixDomainServerSocket::CancelCallback() {
- out_socket_ = SocketDestination();
- callback_.Reset();
- }
- } // namespace net
|