1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "sysdeps/network.h"
18
19 #include <errno.h>
20 #include <netinet/in.h>
21 #include <sys/socket.h>
22
23 #include <string>
24
25 #include "adb_unique_fd.h"
26
set_error(std::string * error)27 static void set_error(std::string* error) {
28 if (error) {
29 *error = strerror(errno);
30 }
31 }
32
loopback_addr4(sockaddr_storage * addr,socklen_t * addrlen,int port)33 static sockaddr* loopback_addr4(sockaddr_storage* addr, socklen_t* addrlen, int port) {
34 struct sockaddr_in* addr4 = reinterpret_cast<sockaddr_in*>(addr);
35 *addrlen = sizeof(*addr4);
36
37 addr4->sin_family = AF_INET;
38 addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
39 addr4->sin_port = htons(port);
40 return reinterpret_cast<sockaddr*>(addr);
41 }
42
loopback_addr6(sockaddr_storage * addr,socklen_t * addrlen,int port)43 static sockaddr* loopback_addr6(sockaddr_storage* addr, socklen_t* addrlen, int port) {
44 struct sockaddr_in6* addr6 = reinterpret_cast<sockaddr_in6*>(addr);
45 *addrlen = sizeof(*addr6);
46
47 addr6->sin6_family = AF_INET6;
48 addr6->sin6_addr = in6addr_loopback;
49 addr6->sin6_port = htons(port);
50 return reinterpret_cast<sockaddr*>(addr);
51 }
52
_network_loopback_client(bool ipv6,int port,int type,std::string * error)53 static int _network_loopback_client(bool ipv6, int port, int type, std::string* error) {
54 unique_fd s(socket(ipv6 ? AF_INET6 : AF_INET, type, 0));
55 if (s == -1) {
56 set_error(error);
57 return -1;
58 }
59
60 struct sockaddr_storage addr_storage = {};
61 socklen_t addrlen = sizeof(addr_storage);
62 sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, 0);
63
64 if (bind(s.get(), addr, addrlen) != 0) {
65 set_error(error);
66 return -1;
67 }
68
69 addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port);
70
71 if (connect(s.get(), addr, addrlen) != 0) {
72 set_error(error);
73 return -1;
74 }
75
76 return s.release();
77 }
78
network_loopback_client(int port,int type,std::string * error)79 int network_loopback_client(int port, int type, std::string* error) {
80 // Try IPv4 first, use IPv6 as a fallback.
81 int rc = _network_loopback_client(false, port, type, error);
82 if (rc == -1) {
83 return _network_loopback_client(true, port, type, error);
84 }
85 return rc;
86 }
87
_network_loopback_server(bool ipv6,int port,int type,std::string * error)88 static int _network_loopback_server(bool ipv6, int port, int type, std::string* error) {
89 unique_fd s(socket(ipv6 ? AF_INET6 : AF_INET, type, 0));
90 if (s == -1) {
91 set_error(error);
92 return -1;
93 }
94
95 int n = 1;
96 setsockopt(s.get(), SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
97
98 struct sockaddr_storage addr_storage = {};
99 socklen_t addrlen = sizeof(addr_storage);
100 sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port);
101
102 if (bind(s, addr, addrlen) != 0) {
103 set_error(error);
104 return -1;
105 }
106
107 if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
108 // Arbitrarily selected value, ported from libcutils.
109 if (listen(s, 4) != 0) {
110 set_error(error);
111 return -1;
112 }
113 }
114
115 return s.release();
116 }
117
network_loopback_server(int port,int type,std::string * error)118 int network_loopback_server(int port, int type, std::string* error) {
119 int rc = _network_loopback_server(false, port, type, error);
120
121 // Only attempt to listen on IPv6 if IPv4 is unavailable.
122 // We don't want to start an IPv6 server if there's already an IPv4 one running.
123 if (rc == -1 && (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)) {
124 return _network_loopback_server(true, port, type, error);
125 }
126 return rc;
127 }
128