mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2025-02-28 04:43:20 +03:00
217 lines
5.7 KiB
C++
217 lines
5.7 KiB
C++
// Copyright 2014 The Chromium Authors
|
|
// 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/functional/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,
|
|
absl::optional<bool> ipv6_only) {
|
|
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
|