blob: f86bb69d96a53bed5841855e245da88c46a96b0d [file] [log] [blame]
David Pursell815c7be2015-12-09 17:09:54 -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 <winsock2.h>
32#include <ws2tcpip.h>
33
34#include <memory>
35
36#include <android-base/stringprintf.h>
David Pursell0eb8e1b2016-01-14 17:18:27 -080037#include <cutils/sockets.h>
David Pursell815c7be2015-12-09 17:09:54 -080038
39// Windows UDP socket functionality.
40class WindowsUdpSocket : public UdpSocket {
41 public:
42 enum class Type { kClient, kServer };
43
44 WindowsUdpSocket(SOCKET sock, Type type);
45 ~WindowsUdpSocket() override;
46
47 ssize_t Send(const void* data, size_t len) override;
48 ssize_t Receive(void* data, size_t len, int timeout_ms) override;
49 int Close() override;
50
51 private:
52 SOCKET sock_;
53 int receive_timeout_ms_ = 0;
54 std::unique_ptr<sockaddr_storage> addr_;
55 int addr_size_ = 0;
56
57 DISALLOW_COPY_AND_ASSIGN(WindowsUdpSocket);
58};
59
60WindowsUdpSocket::WindowsUdpSocket(SOCKET sock, Type type) : sock_(sock) {
61 // Only servers need to remember addresses; clients are connected to a server in NewUdpClient()
62 // so will send to that server without needing to specify the address again.
63 if (type == Type::kServer) {
64 addr_.reset(new sockaddr_storage);
65 addr_size_ = sizeof(*addr_);
66 memset(addr_.get(), 0, addr_size_);
67 }
68}
69
70WindowsUdpSocket::~WindowsUdpSocket() {
71 Close();
72}
73
74ssize_t WindowsUdpSocket::Send(const void* data, size_t len) {
75 return sendto(sock_, reinterpret_cast<const char*>(data), len, 0,
76 reinterpret_cast<sockaddr*>(addr_.get()), addr_size_);
77}
78
79ssize_t WindowsUdpSocket::Receive(void* data, size_t len, int timeout_ms) {
80 // Only set socket timeout if it's changed.
81 if (receive_timeout_ms_ != timeout_ms) {
82 if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&timeout_ms),
83 sizeof(timeout_ms)) < 0) {
84 return -1;
85 }
86 receive_timeout_ms_ = timeout_ms;
87 }
88
89 int* addr_size_ptr = nullptr;
90 if (addr_ != nullptr) {
91 // Reset addr_size as it may have been modified by previous recvfrom() calls.
92 addr_size_ = sizeof(*addr_);
93 addr_size_ptr = &addr_size_;
94 }
95 int result = recvfrom(sock_, reinterpret_cast<char*>(data), len, 0,
96 reinterpret_cast<sockaddr*>(addr_.get()), addr_size_ptr);
97 if (result < 0 && WSAGetLastError() == WSAETIMEDOUT) {
98 errno = EAGAIN;
99 }
100 return result;
101}
102
103int WindowsUdpSocket::Close() {
104 int result = 0;
105 if (sock_ != INVALID_SOCKET) {
106 result = closesocket(sock_);
107 sock_ = INVALID_SOCKET;
108 }
109 return result;
110}
111
David Pursell815c7be2015-12-09 17:09:54 -0800112std::unique_ptr<UdpSocket> UdpSocket::NewUdpClient(const std::string& host, int port,
113 std::string* error) {
David Pursell0eb8e1b2016-01-14 17:18:27 -0800114 SOCKET sock = socket_network_client(host.c_str(), port, SOCK_DGRAM);
David Pursell815c7be2015-12-09 17:09:54 -0800115 if (sock == INVALID_SOCKET) {
116 if (error) {
117 *error = android::base::StringPrintf("Failed to connect to %s:%d (error %d)",
118 host.c_str(), port, WSAGetLastError());
119 }
120 return nullptr;
121 }
122
123 return std::unique_ptr<UdpSocket>(new WindowsUdpSocket(sock, WindowsUdpSocket::Type::kClient));
124}
125
126// This functionality is currently only used by tests so we don't need any error messages.
127std::unique_ptr<UdpSocket> UdpSocket::NewUdpServer(int port) {
David Pursell815c7be2015-12-09 17:09:54 -0800128 SOCKET sock = socket_inaddr_any_server(port, SOCK_DGRAM);
129 if (sock == INVALID_SOCKET) {
130 return nullptr;
131 }
132
133 return std::unique_ptr<UdpSocket>(new WindowsUdpSocket(sock, WindowsUdpSocket::Type::kServer));
134}