• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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