blob: d41f1fe6fd81be3aa53f59955aa9dfeae91a1b5c [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
31#include <android-base/stringprintf.h>
32
33Socket::Socket(cutils_socket_t sock) : sock_(sock) {}
34
35Socket::~Socket() {
36 Close();
37}
38
39int Socket::Close() {
40 int ret = 0;
41
42 if (sock_ != INVALID_SOCKET) {
43 ret = socket_close(sock_);
44 sock_ = INVALID_SOCKET;
45 }
46
47 return ret;
48}
49
50bool Socket::SetReceiveTimeout(int timeout_ms) {
51 if (timeout_ms != receive_timeout_ms_) {
52 if (socket_set_receive_timeout(sock_, timeout_ms) == 0) {
53 receive_timeout_ms_ = timeout_ms;
54 return true;
55 }
56 return false;
57 }
58
59 return true;
60}
61
62ssize_t Socket::ReceiveAll(void* data, size_t length, int timeout_ms) {
63 size_t total = 0;
64
65 while (total < length) {
66 ssize_t bytes = Receive(reinterpret_cast<char*>(data) + total, length - total, timeout_ms);
67
68 if (bytes == -1) {
69 if (total == 0) {
70 return -1;
71 }
72 break;
73 }
74 total += bytes;
75 }
76
77 return total;
78}
79
80// Implements the Socket interface for UDP.
81class UdpSocket : public Socket {
82 public:
83 enum class Type { kClient, kServer };
84
85 UdpSocket(Type type, cutils_socket_t sock);
86
87 ssize_t Send(const void* data, size_t length) override;
88 ssize_t Receive(void* data, size_t length, int timeout_ms) override;
89
90 private:
91 std::unique_ptr<sockaddr_storage> addr_;
92 socklen_t addr_size_ = 0;
93
94 DISALLOW_COPY_AND_ASSIGN(UdpSocket);
95};
96
97UdpSocket::UdpSocket(Type type, cutils_socket_t sock) : Socket(sock) {
98 // Only servers need to remember addresses; clients are connected to a server in NewClient()
99 // so will send to that server without needing to specify the address again.
100 if (type == Type::kServer) {
101 addr_.reset(new sockaddr_storage);
102 addr_size_ = sizeof(*addr_);
103 memset(addr_.get(), 0, addr_size_);
104 }
105}
106
107ssize_t UdpSocket::Send(const void* data, size_t length) {
108 return TEMP_FAILURE_RETRY(sendto(sock_, reinterpret_cast<const char*>(data), length, 0,
109 reinterpret_cast<sockaddr*>(addr_.get()), addr_size_));
110}
111
112ssize_t UdpSocket::Receive(void* data, size_t length, int timeout_ms) {
113 if (!SetReceiveTimeout(timeout_ms)) {
114 return -1;
115 }
116
117 socklen_t* addr_size_ptr = nullptr;
118 if (addr_ != nullptr) {
119 // Reset addr_size as it may have been modified by previous recvfrom() calls.
120 addr_size_ = sizeof(*addr_);
121 addr_size_ptr = &addr_size_;
122 }
123
124 return TEMP_FAILURE_RETRY(recvfrom(sock_, reinterpret_cast<char*>(data), length, 0,
125 reinterpret_cast<sockaddr*>(addr_.get()), addr_size_ptr));
126}
127
128// Implements the Socket interface for TCP.
129class TcpSocket : public Socket {
130 public:
131 TcpSocket(cutils_socket_t sock) : Socket(sock) {}
132
133 ssize_t Send(const void* data, size_t length) override;
134 ssize_t Receive(void* data, size_t length, int timeout_ms) override;
135
136 std::unique_ptr<Socket> Accept() override;
137
138 private:
139 DISALLOW_COPY_AND_ASSIGN(TcpSocket);
140};
141
142ssize_t TcpSocket::Send(const void* data, size_t length) {
143 size_t total = 0;
144
145 while (total < length) {
146 ssize_t bytes = TEMP_FAILURE_RETRY(
147 send(sock_, reinterpret_cast<const char*>(data) + total, length - total, 0));
148
149 if (bytes == -1) {
150 if (total == 0) {
151 return -1;
152 }
153 break;
154 }
155 total += bytes;
156 }
157
158 return total;
159}
160
161ssize_t TcpSocket::Receive(void* data, size_t length, int timeout_ms) {
162 if (!SetReceiveTimeout(timeout_ms)) {
163 return -1;
164 }
165
166 return TEMP_FAILURE_RETRY(recv(sock_, reinterpret_cast<char*>(data), length, 0));
167}
168
169std::unique_ptr<Socket> TcpSocket::Accept() {
170 cutils_socket_t handler = accept(sock_, nullptr, nullptr);
171 if (handler == INVALID_SOCKET) {
172 return nullptr;
173 }
174 return std::unique_ptr<TcpSocket>(new TcpSocket(handler));
175}
176
177std::unique_ptr<Socket> Socket::NewClient(Protocol protocol, const std::string& host, int port,
178 std::string* error) {
179 if (protocol == Protocol::kUdp) {
180 cutils_socket_t sock = socket_network_client(host.c_str(), port, SOCK_DGRAM);
181 if (sock != INVALID_SOCKET) {
182 return std::unique_ptr<UdpSocket>(new UdpSocket(UdpSocket::Type::kClient, sock));
183 }
184 } else {
185 cutils_socket_t sock = socket_network_client(host.c_str(), port, SOCK_STREAM);
186 if (sock != INVALID_SOCKET) {
187 return std::unique_ptr<TcpSocket>(new TcpSocket(sock));
188 }
189 }
190
191 if (error) {
192 *error = android::base::StringPrintf("Failed to connect to %s:%d", host.c_str(), port);
193 }
194 return nullptr;
195}
196
197// This functionality is currently only used by tests so we don't need any error messages.
198std::unique_ptr<Socket> Socket::NewServer(Protocol protocol, int port) {
199 if (protocol == Protocol::kUdp) {
200 cutils_socket_t sock = socket_inaddr_any_server(port, SOCK_DGRAM);
201 if (sock != INVALID_SOCKET) {
202 return std::unique_ptr<UdpSocket>(new UdpSocket(UdpSocket::Type::kServer, sock));
203 }
204 } else {
205 cutils_socket_t sock = socket_inaddr_any_server(port, SOCK_STREAM);
206 if (sock != INVALID_SOCKET) {
207 return std::unique_ptr<TcpSocket>(new TcpSocket(sock));
208 }
209 }
210
211 return nullptr;
212}