summaryrefslogtreecommitdiffstats
path: root/net/socket/unix_domain_client_socket_posix.cc
blob: 792cfac9bd299c63b530559561219728dd385293 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// 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_client_socket_posix.h"

#include <sys/socket.h>
#include <sys/un.h>
#include <utility>

#include "base/logging.h"
#include "net/base/net_errors.h"
#include "net/base/sockaddr_storage.h"
#include "net/socket/socket_posix.h"

namespace net {

UnixDomainClientSocket::UnixDomainClientSocket(const std::string& socket_path,
                                               bool use_abstract_namespace)
    : socket_path_(socket_path),
      use_abstract_namespace_(use_abstract_namespace) {
}

UnixDomainClientSocket::UnixDomainClientSocket(scoped_ptr<SocketPosix> socket)
    : use_abstract_namespace_(false), socket_(std::move(socket)) {}

UnixDomainClientSocket::~UnixDomainClientSocket() {
  Disconnect();
}

// static
bool UnixDomainClientSocket::FillAddress(const std::string& socket_path,
                                         bool use_abstract_namespace,
                                         SockaddrStorage* address) {
  // Caller should provide a non-empty path for the socket address.
  if (socket_path.empty())
    return false;

  size_t path_max = address->addr_len - offsetof(struct sockaddr_un, sun_path);
  // Non abstract namespace pathname should be null-terminated. Abstract
  // namespace pathname must start with '\0'. So, the size is always greater
  // than socket_path size by 1.
  size_t path_size = socket_path.size() + 1;
  if (path_size > path_max)
    return false;

  struct sockaddr_un* socket_addr =
      reinterpret_cast<struct sockaddr_un*>(address->addr);
  memset(socket_addr, 0, address->addr_len);
  socket_addr->sun_family = AF_UNIX;
  address->addr_len = path_size + offsetof(struct sockaddr_un, sun_path);
  if (!use_abstract_namespace) {
    memcpy(socket_addr->sun_path, socket_path.c_str(), socket_path.size());
    return true;
  }

#if defined(OS_ANDROID) || defined(OS_LINUX)
  // Convert the path given into abstract socket name. It must start with
  // the '\0' character, so we are adding it. |addr_len| must specify the
  // length of the structure exactly, as potentially the socket name may
  // have '\0' characters embedded (although we don't support this).
  // Note that addr.sun_path is already zero initialized.
  memcpy(socket_addr->sun_path + 1, socket_path.c_str(), socket_path.size());
  return true;
#else
  return false;
#endif
}

int UnixDomainClientSocket::Connect(const CompletionCallback& callback) {
  DCHECK(!socket_);

  SockaddrStorage address;
  if (!FillAddress(socket_path_, use_abstract_namespace_, &address))
    return ERR_ADDRESS_INVALID;

  socket_.reset(new SocketPosix);
  int rv = socket_->Open(AF_UNIX);
  DCHECK_NE(ERR_IO_PENDING, rv);
  if (rv != OK)
    return rv;

  return socket_->Connect(address, callback);
}

void UnixDomainClientSocket::Disconnect() {
  socket_.reset();
}

bool UnixDomainClientSocket::IsConnected() const {
  return socket_ && socket_->IsConnected();
}

bool UnixDomainClientSocket::IsConnectedAndIdle() const {
  return socket_ && socket_->IsConnectedAndIdle();
}

int UnixDomainClientSocket::GetPeerAddress(IPEndPoint* address) const {
  // Unix domain sockets have no valid associated addr/port;
  // return either not connected or address invalid.
  DCHECK(address);

  if (!IsConnected())
    return ERR_SOCKET_NOT_CONNECTED;

  return ERR_ADDRESS_INVALID;
}

int UnixDomainClientSocket::GetLocalAddress(IPEndPoint* address) const {
  // Unix domain sockets have no valid associated addr/port;
  // return either not connected or address invalid.
  DCHECK(address);

  if (!socket_)
    return ERR_SOCKET_NOT_CONNECTED;

  return ERR_ADDRESS_INVALID;
}

const BoundNetLog& UnixDomainClientSocket::NetLog() const {
  return net_log_;
}

void UnixDomainClientSocket::SetSubresourceSpeculation() {
}

void UnixDomainClientSocket::SetOmniboxSpeculation() {
}

bool UnixDomainClientSocket::WasEverUsed() const {
  return true;  // We don't care.
}

bool UnixDomainClientSocket::WasNpnNegotiated() const {
  return false;
}

NextProto UnixDomainClientSocket::GetNegotiatedProtocol() const {
  return kProtoUnknown;
}

bool UnixDomainClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
  return false;
}

void UnixDomainClientSocket::GetConnectionAttempts(
    ConnectionAttempts* out) const {
  out->clear();
}

int64_t UnixDomainClientSocket::GetTotalReceivedBytes() const {
  NOTIMPLEMENTED();
  return 0;
}

int UnixDomainClientSocket::Read(IOBuffer* buf, int buf_len,
                                 const CompletionCallback& callback) {
  DCHECK(socket_);
  return socket_->Read(buf, buf_len, callback);
}

int UnixDomainClientSocket::Write(IOBuffer* buf, int buf_len,
                                  const CompletionCallback& callback) {
  DCHECK(socket_);
  return socket_->Write(buf, buf_len, callback);
}

int UnixDomainClientSocket::SetReceiveBufferSize(int32_t size) {
  NOTIMPLEMENTED();
  return ERR_NOT_IMPLEMENTED;
}

int UnixDomainClientSocket::SetSendBufferSize(int32_t size) {
  NOTIMPLEMENTED();
  return ERR_NOT_IMPLEMENTED;
}

SocketDescriptor UnixDomainClientSocket::ReleaseConnectedSocket() {
  DCHECK(socket_);
  DCHECK(socket_->IsConnected());

  SocketDescriptor socket_fd = socket_->ReleaseConnectedSocket();
  socket_.reset();
  return socket_fd;
}

}  // namespace net