blob: 6f8cf65e86730d9264478484d1951c78a237d78f [file] [log] [blame]
Garrick Evans3cbac7c2019-04-18 15:31:31 +09001// Copyright 2019 The Chromium OS 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 "arc/network/socket.h"
6
7#include <arpa/inet.h>
8#include <errno.h>
9#include <linux/vm_sockets.h>
10#include <net/if.h>
11#include <string.h>
12#include <sys/ioctl.h>
13#include <sys/un.h>
14#include <unistd.h>
15
16#include <utility>
17
18#include <base/logging.h>
19#include <base/memory/ptr_util.h>
20
21namespace arc_networkd {
22namespace {
23
24bool WouldBlock() {
25 return errno == EAGAIN || errno == EWOULDBLOCK;
26}
27
28std::ostream& operator<<(std::ostream& stream, const struct sockaddr& addr) {
29 stream << "{family: " << addr.sa_family;
30 switch (addr.sa_family) {
31 case AF_INET: {
32 struct sockaddr_in* in = (struct sockaddr_in*)&addr;
33 char buf[INET_ADDRSTRLEN] = {0};
34 inet_ntop(AF_INET, &in->sin_addr, buf, sizeof(buf));
35 stream << ", port: " << ntohs(in->sin_port) << ", addr: " << buf;
36 break;
37 }
38 case AF_INET6: {
39 struct sockaddr_in6* in = (struct sockaddr_in6*)&addr;
40 char buf[INET6_ADDRSTRLEN] = {0};
41 inet_ntop(AF_INET6, &in->sin6_addr, buf, sizeof(buf));
42 stream << ", port: " << ntohs(in->sin6_port) << ", addr: " << buf;
43 break;
44 }
45 case AF_UNIX: {
46 struct sockaddr_un* in = (struct sockaddr_un*)&addr;
47 size_t addrlen = sizeof(*in);
48 if (addrlen == sizeof(sa_family_t)) {
49 stream << ", (unnamed)";
50 } else if (in->sun_path[0] == '\0') {
51 stream << ", path: @";
52 stream.write(&in->sun_path[1], addrlen - sizeof(sa_family_t) - 1);
53 } else {
54 stream << ", path: " << std::string(in->sun_path);
55 }
56 break;
57 }
58 case AF_VSOCK: {
59 struct sockaddr_vm* in = (struct sockaddr_vm*)&addr;
60 stream << ", port: " << in->svm_port << ", cid: " << in->svm_cid;
61 break;
62 }
63 default:
64 stream << ", (unknown)";
65 }
66 stream << "}";
67 return stream;
68}
69
70} // namespace
71
72Socket::Socket(int family, int type) : fd_(socket(family, type, 0)) {
73 if (!fd_.is_valid())
74 PLOG(ERROR) << "socket failed (" << family << ", " << type << ")";
75}
76
77Socket::Socket(base::ScopedFD fd) : fd_(std::move(fd)) {
78 if (!fd_.is_valid())
79 LOG(ERROR) << "invalid fd";
80}
81
Garrick Evansfa872f62019-05-28 16:49:25 +090082bool Socket::Bind(const struct sockaddr* addr, socklen_t addrlen) {
83 if (bind(fd_.get(), addr, addrlen) < 0) {
Garrick Evans3cbac7c2019-04-18 15:31:31 +090084 PLOG(WARNING) << "bind failed: " << *addr;
85 return false;
86 }
87 return true;
88}
89
Garrick Evansfa872f62019-05-28 16:49:25 +090090bool Socket::Connect(const struct sockaddr* addr, socklen_t addrlen) {
91 if (connect(fd_.get(), addr, addrlen) < 0) {
Garrick Evans3cbac7c2019-04-18 15:31:31 +090092 PLOG(WARNING) << "connect failed: " << *addr;
93 return false;
94 }
95 return true;
96}
97
98bool Socket::Listen(int backlog) const {
99 if (listen(fd_.get(), backlog) != 0) {
100 PLOG(WARNING) << "listen failed";
101 return false;
102 }
103 return true;
104}
105
106std::unique_ptr<Socket> Socket::Accept(struct sockaddr* addr,
107 socklen_t* addrlen) const {
108 base::ScopedFD fd(accept(fd_.get(), addr, addrlen));
109 if (!fd.is_valid()) {
110 if (!WouldBlock())
111 PLOG(WARNING) << "accept failed";
112 return nullptr;
113 }
114 return std::make_unique<Socket>(std::move(fd));
115}
116
Garrick Evans1cce71a2019-06-21 10:43:14 +0900117ssize_t Socket::SendTo(const void* data,
118 size_t len,
119 const struct sockaddr* addr,
120 socklen_t addrlen) {
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900121 if (!fd_.is_valid()) {
122 return -1;
123 }
Garrick Evans1cce71a2019-06-21 10:43:14 +0900124 if (!addr) {
125 addrlen = 0;
126 } else if (addrlen == 0) {
127 addrlen = sizeof(*addr);
128 }
129
Garrick Evans3cbac7c2019-04-18 15:31:31 +0900130 ssize_t bytes = sendto(fd_.get(), data, len, MSG_NOSIGNAL, addr, addrlen);
131 if (bytes >= 0)
132 return bytes;
133
134 if (WouldBlock())
135 return 0;
136
137 PLOG(WARNING) << "sendto failed";
138 return bytes;
139}
140
141ssize_t Socket::RecvFrom(void* data,
142 size_t len,
143 struct sockaddr* addr,
144 socklen_t addrlen) {
145 socklen_t recvlen = addrlen;
146 ssize_t bytes = recvfrom(fd_.get(), data, len, 0, addr, &recvlen);
147 if (bytes >= 0) {
148 if (recvlen != addrlen)
149 PLOG(WARNING) << "recvfrom failed: unexpected src addr length "
150 << recvlen;
151 return bytes;
152 }
153
154 if (WouldBlock())
155 return 0;
156
157 PLOG(WARNING) << "recvfrom failed";
158 return bytes;
159}
160
161std::ostream& operator<<(std::ostream& stream, const Socket& socket) {
162 stream << "{fd: " << socket.fd() << "}";
163 return stream;
164}
165
166} // namespace arc_networkd