Home | History | Annotate | Download | only in posix
      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 
     27 static void set_error(std::string* error) {
     28     if (error) {
     29         *error = strerror(errno);
     30     }
     31 }
     32 
     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 
     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 
     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 
     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 
     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 
    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