blob: bd6e2484e8fbc0168d8e7edaab21bcad6eb048ec [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
Garrick Evans3388a032020-03-24 11:25:55 +09005#include "patchpanel/socket.h"
Garrick Evans3cbac7c2019-04-18 15:31:31 +09006
7#include <arpa/inet.h>
8#include <errno.h>
Garrick Evans3cbac7c2019-04-18 15:31:31 +09009#include <net/if.h>
10#include <string.h>
11#include <sys/ioctl.h>
Garrick Evans3cbac7c2019-04-18 15:31:31 +090012#include <unistd.h>
13
14#include <utility>
15
16#include <base/logging.h>
17#include <base/memory/ptr_util.h>
18
Garrick Evans3388a032020-03-24 11:25:55 +090019#include "patchpanel/net_util.h"
Hugo Benichidcc32392020-02-27 09:14:40 +090020
Garrick Evans3388a032020-03-24 11:25:55 +090021namespace patchpanel {
Garrick Evans3cbac7c2019-04-18 15:31:31 +090022namespace {
23
24bool WouldBlock() {
25 return errno == EAGAIN || errno == EWOULDBLOCK;
26}
Garrick Evans3cbac7c2019-04-18 15:31:31 +090027} // namespace
28
29Socket::Socket(int family, int type) : fd_(socket(family, type, 0)) {
30 if (!fd_.is_valid())
31 PLOG(ERROR) << "socket failed (" << family << ", " << type << ")";
32}
33
34Socket::Socket(base::ScopedFD fd) : fd_(std::move(fd)) {
35 if (!fd_.is_valid())
36 LOG(ERROR) << "invalid fd";
37}
38
Garrick Evansfa872f62019-05-28 16:49:25 +090039bool Socket::Bind(const struct sockaddr* addr, socklen_t addrlen) {
40 if (bind(fd_.get(), addr, addrlen) < 0) {
Garrick Evans3cbac7c2019-04-18 15:31:31 +090041 PLOG(WARNING) << "bind failed: " << *addr;
42 return false;
43 }
44 return true;
45}
46
Garrick Evansfa872f62019-05-28 16:49:25 +090047bool Socket::Connect(const struct sockaddr* addr, socklen_t addrlen) {
48 if (connect(fd_.get(), addr, addrlen) < 0) {
Garrick Evans3cbac7c2019-04-18 15:31:31 +090049 PLOG(WARNING) << "connect failed: " << *addr;
50 return false;
51 }
52 return true;
53}
54
55bool Socket::Listen(int backlog) const {
56 if (listen(fd_.get(), backlog) != 0) {
57 PLOG(WARNING) << "listen failed";
58 return false;
59 }
60 return true;
61}
62
63std::unique_ptr<Socket> Socket::Accept(struct sockaddr* addr,
64 socklen_t* addrlen) const {
65 base::ScopedFD fd(accept(fd_.get(), addr, addrlen));
66 if (!fd.is_valid()) {
67 if (!WouldBlock())
68 PLOG(WARNING) << "accept failed";
69 return nullptr;
70 }
71 return std::make_unique<Socket>(std::move(fd));
72}
73
Garrick Evans1cce71a2019-06-21 10:43:14 +090074ssize_t Socket::SendTo(const void* data,
75 size_t len,
76 const struct sockaddr* addr,
77 socklen_t addrlen) {
Garrick Evans3cbac7c2019-04-18 15:31:31 +090078 if (!fd_.is_valid()) {
79 return -1;
80 }
Garrick Evans1cce71a2019-06-21 10:43:14 +090081 if (!addr) {
82 addrlen = 0;
83 } else if (addrlen == 0) {
84 addrlen = sizeof(*addr);
85 }
86
Garrick Evans3cbac7c2019-04-18 15:31:31 +090087 ssize_t bytes = sendto(fd_.get(), data, len, MSG_NOSIGNAL, addr, addrlen);
88 if (bytes >= 0)
89 return bytes;
90
91 if (WouldBlock())
92 return 0;
93
94 PLOG(WARNING) << "sendto failed";
95 return bytes;
96}
97
98ssize_t Socket::RecvFrom(void* data,
99 size_t len,
100 struct sockaddr* addr,
101 socklen_t addrlen) {
102 socklen_t recvlen = addrlen;
103 ssize_t bytes = recvfrom(fd_.get(), data, len, 0, addr, &recvlen);
104 if (bytes >= 0) {
105 if (recvlen != addrlen)
106 PLOG(WARNING) << "recvfrom failed: unexpected src addr length "
107 << recvlen;
108 return bytes;
109 }
110
111 if (WouldBlock())
112 return 0;
113
114 PLOG(WARNING) << "recvfrom failed";
115 return bytes;
116}
117
118std::ostream& operator<<(std::ostream& stream, const Socket& socket) {
119 stream << "{fd: " << socket.fd() << "}";
120 return stream;
121}
122
Garrick Evans3388a032020-03-24 11:25:55 +0900123} // namespace patchpanel