blob: 0a3ddfa2f9ded1f2b092e9d4edd3996dddf18a9d [file] [log] [blame]
David Pursell572bce22016-01-15 14:19:56 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include "socket.h"
30
David Pursellc3a46692016-01-29 08:10:50 -080031#include <android-base/errors.h>
David Pursell572bce22016-01-15 14:19:56 -080032#include <android-base/stringprintf.h>
33
34Socket::Socket(cutils_socket_t sock) : sock_(sock) {}
35
36Socket::~Socket() {
37 Close();
38}
39
40int Socket::Close() {
41 int ret = 0;
42
43 if (sock_ != INVALID_SOCKET) {
44 ret = socket_close(sock_);
45 sock_ = INVALID_SOCKET;
46 }
47
48 return ret;
49}
50
51bool Socket::SetReceiveTimeout(int timeout_ms) {
52 if (timeout_ms != receive_timeout_ms_) {
53 if (socket_set_receive_timeout(sock_, timeout_ms) == 0) {
54 receive_timeout_ms_ = timeout_ms;
55 return true;
56 }
57 return false;
58 }
59
60 return true;
61}
62
63ssize_t Socket::ReceiveAll(void* data, size_t length, int timeout_ms) {
64 size_t total = 0;
65
66 while (total < length) {
67 ssize_t bytes = Receive(reinterpret_cast<char*>(data) + total, length - total, timeout_ms);
68
69 if (bytes == -1) {
70 if (total == 0) {
71 return -1;
72 }
73 break;
74 }
75 total += bytes;
76 }
77
78 return total;
79}
80
David Pursellc3a46692016-01-29 08:10:50 -080081int Socket::GetLocalPort() {
82 return socket_get_local_port(sock_);
83}
84
David Pursell572bce22016-01-15 14:19:56 -080085// Implements the Socket interface for UDP.
86class UdpSocket : public Socket {
87 public:
88 enum class Type { kClient, kServer };
89
90 UdpSocket(Type type, cutils_socket_t sock);
91
92 ssize_t Send(const void* data, size_t length) override;
93 ssize_t Receive(void* data, size_t length, int timeout_ms) override;
94
95 private:
96 std::unique_ptr<sockaddr_storage> addr_;
97 socklen_t addr_size_ = 0;
98
99 DISALLOW_COPY_AND_ASSIGN(UdpSocket);
100};
101
102UdpSocket::UdpSocket(Type type, cutils_socket_t sock) : Socket(sock) {
103 // Only servers need to remember addresses; clients are connected to a server in NewClient()
104 // so will send to that server without needing to specify the address again.
105 if (type == Type::kServer) {
106 addr_.reset(new sockaddr_storage);
107 addr_size_ = sizeof(*addr_);
108 memset(addr_.get(), 0, addr_size_);
109 }
110}
111
112ssize_t UdpSocket::Send(const void* data, size_t length) {
113 return TEMP_FAILURE_RETRY(sendto(sock_, reinterpret_cast<const char*>(data), length, 0,
114 reinterpret_cast<sockaddr*>(addr_.get()), addr_size_));
115}
116
117ssize_t UdpSocket::Receive(void* data, size_t length, int timeout_ms) {
118 if (!SetReceiveTimeout(timeout_ms)) {
119 return -1;
120 }
121
122 socklen_t* addr_size_ptr = nullptr;
123 if (addr_ != nullptr) {
124 // Reset addr_size as it may have been modified by previous recvfrom() calls.
125 addr_size_ = sizeof(*addr_);
126 addr_size_ptr = &addr_size_;
127 }
128
129 return TEMP_FAILURE_RETRY(recvfrom(sock_, reinterpret_cast<char*>(data), length, 0,
130 reinterpret_cast<sockaddr*>(addr_.get()), addr_size_ptr));
131}
132
133// Implements the Socket interface for TCP.
134class TcpSocket : public Socket {
135 public:
136 TcpSocket(cutils_socket_t sock) : Socket(sock) {}
137
138 ssize_t Send(const void* data, size_t length) override;
139 ssize_t Receive(void* data, size_t length, int timeout_ms) override;
140
141 std::unique_ptr<Socket> Accept() override;
142
143 private:
144 DISALLOW_COPY_AND_ASSIGN(TcpSocket);
145};
146
147ssize_t TcpSocket::Send(const void* data, size_t length) {
148 size_t total = 0;
149
150 while (total < length) {
151 ssize_t bytes = TEMP_FAILURE_RETRY(
152 send(sock_, reinterpret_cast<const char*>(data) + total, length - total, 0));
153
154 if (bytes == -1) {
155 if (total == 0) {
156 return -1;
157 }
158 break;
159 }
160 total += bytes;
161 }
162
163 return total;
164}
165
166ssize_t TcpSocket::Receive(void* data, size_t length, int timeout_ms) {
167 if (!SetReceiveTimeout(timeout_ms)) {
168 return -1;
169 }
170
171 return TEMP_FAILURE_RETRY(recv(sock_, reinterpret_cast<char*>(data), length, 0));
172}
173
174std::unique_ptr<Socket> TcpSocket::Accept() {
175 cutils_socket_t handler = accept(sock_, nullptr, nullptr);
176 if (handler == INVALID_SOCKET) {
177 return nullptr;
178 }
179 return std::unique_ptr<TcpSocket>(new TcpSocket(handler));
180}
181
182std::unique_ptr<Socket> Socket::NewClient(Protocol protocol, const std::string& host, int port,
183 std::string* error) {
184 if (protocol == Protocol::kUdp) {
185 cutils_socket_t sock = socket_network_client(host.c_str(), port, SOCK_DGRAM);
186 if (sock != INVALID_SOCKET) {
187 return std::unique_ptr<UdpSocket>(new UdpSocket(UdpSocket::Type::kClient, sock));
188 }
189 } else {
190 cutils_socket_t sock = socket_network_client(host.c_str(), port, SOCK_STREAM);
191 if (sock != INVALID_SOCKET) {
192 return std::unique_ptr<TcpSocket>(new TcpSocket(sock));
193 }
194 }
195
196 if (error) {
197 *error = android::base::StringPrintf("Failed to connect to %s:%d", host.c_str(), port);
198 }
199 return nullptr;
200}
201
202// This functionality is currently only used by tests so we don't need any error messages.
203std::unique_ptr<Socket> Socket::NewServer(Protocol protocol, int port) {
204 if (protocol == Protocol::kUdp) {
205 cutils_socket_t sock = socket_inaddr_any_server(port, SOCK_DGRAM);
206 if (sock != INVALID_SOCKET) {
207 return std::unique_ptr<UdpSocket>(new UdpSocket(UdpSocket::Type::kServer, sock));
208 }
209 } else {
210 cutils_socket_t sock = socket_inaddr_any_server(port, SOCK_STREAM);
211 if (sock != INVALID_SOCKET) {
212 return std::unique_ptr<TcpSocket>(new TcpSocket(sock));
213 }
214 }
215
216 return nullptr;
217}
David Pursellc3a46692016-01-29 08:10:50 -0800218
219std::string Socket::GetErrorMessage() {
220#if defined(_WIN32)
221 DWORD error_code = WSAGetLastError();
222#else
223 int error_code = errno;
224#endif
225 return android::base::SystemErrorCodeToString(error_code);
226}