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_listen_socket_posix.h"
6
7#include <errno.h>
8#include <sys/socket.h>
9#include <sys/stat.h>
10#include <sys/types.h>
11#include <sys/un.h>
12#include <unistd.h>
13
14#include <cstring>
15#include <string>
16
17#include "base/bind.h"
18#include "base/callback.h"
19#include "base/posix/eintr_wrapper.h"
20#include "base/threading/platform_thread.h"
21#include "build/build_config.h"
22#include "net/base/net_errors.h"
23#include "net/base/net_util.h"
24#include "net/socket/socket_descriptor.h"
25#include "net/socket/unix_domain_client_socket_posix.h"
26
27namespace net {
28namespace deprecated {
29
30namespace {
31
32int CreateAndBind(const std::string& socket_path,
33                  bool use_abstract_namespace,
34                  SocketDescriptor* socket_fd) {
35  DCHECK(socket_fd);
36
37  SockaddrStorage address;
38  if (!UnixDomainClientSocket::FillAddress(socket_path,
39                                           use_abstract_namespace,
40                                           &address)) {
41    return ERR_ADDRESS_INVALID;
42  }
43
44  SocketDescriptor fd = CreatePlatformSocket(PF_UNIX, SOCK_STREAM, 0);
45  if (fd == kInvalidSocket)
46    return errno ? MapSystemError(errno) : ERR_UNEXPECTED;
47
48  if (bind(fd, address.addr, address.addr_len) < 0) {
49    int rv = MapSystemError(errno);
50    close(fd);
51    PLOG(ERROR) << "Could not bind unix domain socket to " << socket_path
52                << (use_abstract_namespace ? " (with abstract namespace)" : "");
53    return rv;
54  }
55
56  *socket_fd = fd;
57  return OK;
58}
59
60}  // namespace
61
62// static
63scoped_ptr<UnixDomainListenSocket>
64UnixDomainListenSocket::CreateAndListenInternal(
65    const std::string& path,
66    const std::string& fallback_path,
67    StreamListenSocket::Delegate* del,
68    const AuthCallback& auth_callback,
69    bool use_abstract_namespace) {
70  SocketDescriptor socket_fd = kInvalidSocket;
71  int rv = CreateAndBind(path, use_abstract_namespace, &socket_fd);
72  if (rv != OK && !fallback_path.empty())
73    rv = CreateAndBind(fallback_path, use_abstract_namespace, &socket_fd);
74  if (rv != OK)
75    return scoped_ptr<UnixDomainListenSocket>();
76  scoped_ptr<UnixDomainListenSocket> sock(
77      new UnixDomainListenSocket(socket_fd, del, auth_callback));
78  sock->Listen();
79  return sock.Pass();
80}
81
82// static
83scoped_ptr<UnixDomainListenSocket> UnixDomainListenSocket::CreateAndListen(
84    const std::string& path,
85    StreamListenSocket::Delegate* del,
86    const AuthCallback& auth_callback) {
87  return CreateAndListenInternal(path, "", del, auth_callback, false);
88}
89
90#if defined(SOCKET_ABSTRACT_NAMESPACE_SUPPORTED)
91// static
92scoped_ptr<UnixDomainListenSocket>
93UnixDomainListenSocket::CreateAndListenWithAbstractNamespace(
94    const std::string& path,
95    const std::string& fallback_path,
96    StreamListenSocket::Delegate* del,
97    const AuthCallback& auth_callback) {
98  return
99      CreateAndListenInternal(path, fallback_path, del, auth_callback, true);
100}
101#endif
102
103UnixDomainListenSocket::UnixDomainListenSocket(
104    SocketDescriptor s,
105    StreamListenSocket::Delegate* del,
106    const AuthCallback& auth_callback)
107    : StreamListenSocket(s, del),
108      auth_callback_(auth_callback) {}
109
110UnixDomainListenSocket::~UnixDomainListenSocket() {}
111
112void UnixDomainListenSocket::Accept() {
113  SocketDescriptor conn = StreamListenSocket::AcceptSocket();
114  if (conn == kInvalidSocket)
115    return;
116  UnixDomainServerSocket::Credentials credentials;
117  if (!UnixDomainServerSocket::GetPeerCredentials(conn, &credentials) ||
118      !auth_callback_.Run(credentials)) {
119    if (IGNORE_EINTR(close(conn)) < 0)
120      LOG(ERROR) << "close() error";
121    return;
122  }
123  scoped_ptr<UnixDomainListenSocket> sock(
124      new UnixDomainListenSocket(conn, socket_delegate_, auth_callback_));
125  // It's up to the delegate to AddRef if it wants to keep it around.
126  sock->WatchSocket(WAITING_READ);
127  socket_delegate_->DidAccept(this, sock.PassAs<StreamListenSocket>());
128}
129
130UnixDomainListenSocketFactory::UnixDomainListenSocketFactory(
131    const std::string& path,
132    const UnixDomainListenSocket::AuthCallback& auth_callback)
133    : path_(path),
134      auth_callback_(auth_callback) {}
135
136UnixDomainListenSocketFactory::~UnixDomainListenSocketFactory() {}
137
138scoped_ptr<StreamListenSocket> UnixDomainListenSocketFactory::CreateAndListen(
139    StreamListenSocket::Delegate* delegate) const {
140  return UnixDomainListenSocket::CreateAndListen(
141      path_, delegate, auth_callback_).PassAs<StreamListenSocket>();
142}
143
144#if defined(SOCKET_ABSTRACT_NAMESPACE_SUPPORTED)
145
146UnixDomainListenSocketWithAbstractNamespaceFactory::
147UnixDomainListenSocketWithAbstractNamespaceFactory(
148    const std::string& path,
149    const std::string& fallback_path,
150    const UnixDomainListenSocket::AuthCallback& auth_callback)
151    : UnixDomainListenSocketFactory(path, auth_callback),
152      fallback_path_(fallback_path) {}
153
154UnixDomainListenSocketWithAbstractNamespaceFactory::
155~UnixDomainListenSocketWithAbstractNamespaceFactory() {}
156
157scoped_ptr<StreamListenSocket>
158UnixDomainListenSocketWithAbstractNamespaceFactory::CreateAndListen(
159    StreamListenSocket::Delegate* delegate) const {
160  return UnixDomainListenSocket::CreateAndListenWithAbstractNamespace(
161             path_, fallback_path_, delegate, auth_callback_)
162         .PassAs<StreamListenSocket>();
163}
164
165#endif
166
167}  // namespace deprecated
168}  // namespace net
169