Home | History | Annotate | Download | only in adb
      1 /*
      2  * Copyright (C) 2016 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 "socket_spec.h"
     18 
     19 #include <string>
     20 #include <unordered_map>
     21 #include <vector>
     22 
     23 #include <android-base/parseint.h>
     24 #include <android-base/parsenetaddress.h>
     25 #include <android-base/stringprintf.h>
     26 #include <android-base/strings.h>
     27 #include <cutils/sockets.h>
     28 
     29 #include "adb.h"
     30 #include "sysdeps.h"
     31 
     32 using android::base::StartsWith;
     33 using android::base::StringPrintf;
     34 
     35 #if defined(__linux__)
     36 #define ADB_LINUX 1
     37 #else
     38 #define ADB_LINUX 0
     39 #endif
     40 
     41 #if defined(_WIN32)
     42 #define ADB_WINDOWS 1
     43 #else
     44 #define ADB_WINDOWS 0
     45 #endif
     46 
     47 // Not static because it is used in commandline.c.
     48 int gListenAll = 0;
     49 
     50 struct LocalSocketType {
     51     int socket_namespace;
     52     bool available;
     53 };
     54 
     55 static auto& kLocalSocketTypes = *new std::unordered_map<std::string, LocalSocketType>({
     56 #if ADB_HOST
     57     { "local", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } },
     58 #else
     59     { "local", { ANDROID_SOCKET_NAMESPACE_RESERVED, !ADB_WINDOWS } },
     60 #endif
     61 
     62     { "localreserved", { ANDROID_SOCKET_NAMESPACE_RESERVED, !ADB_HOST } },
     63     { "localabstract", { ANDROID_SOCKET_NAMESPACE_ABSTRACT, ADB_LINUX } },
     64     { "localfilesystem", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } },
     65 });
     66 
     67 bool parse_tcp_socket_spec(const std::string& spec, std::string* hostname, int* port,
     68                            std::string* error) {
     69     if (!StartsWith(spec, "tcp:")) {
     70         *error = StringPrintf("specification is not tcp: '%s'", spec.c_str());
     71         return false;
     72     }
     73 
     74     std::string hostname_value;
     75     int port_value;
     76 
     77     // If the spec is tcp:<port>, parse it ourselves.
     78     // Otherwise, delegate to android::base::ParseNetAddress.
     79     if (android::base::ParseInt(&spec[4], &port_value)) {
     80         // Do the range checking ourselves, because ParseInt rejects 'tcp:65536' and 'tcp:foo:1234'
     81         // identically.
     82         if (port_value < 0 || port_value > 65535) {
     83             *error = StringPrintf("bad port number '%d'", port_value);
     84             return false;
     85         }
     86     } else {
     87         std::string addr = spec.substr(4);
     88         port_value = -1;
     89 
     90         // FIXME: ParseNetAddress rejects port 0. This currently doesn't hurt, because listening
     91         //        on an address that isn't 'localhost' is unsupported.
     92         if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, nullptr, error)) {
     93             return false;
     94         }
     95 
     96         if (port_value == -1) {
     97             *error = StringPrintf("missing port in specification: '%s'", spec.c_str());
     98             return false;
     99         }
    100     }
    101 
    102     if (hostname) {
    103         *hostname = std::move(hostname_value);
    104     }
    105 
    106     if (port) {
    107         *port = port_value;
    108     }
    109 
    110     return true;
    111 }
    112 
    113 static bool tcp_host_is_local(const std::string& hostname) {
    114     // FIXME
    115     return hostname.empty() || hostname == "localhost";
    116 }
    117 
    118 bool is_socket_spec(const std::string& spec) {
    119     for (const auto& it : kLocalSocketTypes) {
    120         std::string prefix = it.first + ":";
    121         if (StartsWith(spec, prefix)) {
    122             return true;
    123         }
    124     }
    125     return StartsWith(spec, "tcp:");
    126 }
    127 
    128 bool is_local_socket_spec(const std::string& spec) {
    129     for (const auto& it : kLocalSocketTypes) {
    130         std::string prefix = it.first + ":";
    131         if (StartsWith(spec, prefix)) {
    132             return true;
    133         }
    134     }
    135 
    136     std::string error;
    137     std::string hostname;
    138     if (!parse_tcp_socket_spec(spec, &hostname, nullptr, &error)) {
    139         return false;
    140     }
    141     return tcp_host_is_local(hostname);
    142 }
    143 
    144 int socket_spec_connect(const std::string& spec, std::string* error) {
    145     if (StartsWith(spec, "tcp:")) {
    146         std::string hostname;
    147         int port;
    148         if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) {
    149             return -1;
    150         }
    151 
    152         int result;
    153         if (tcp_host_is_local(hostname)) {
    154             result = network_loopback_client(port, SOCK_STREAM, error);
    155         } else {
    156 #if ADB_HOST
    157             result = network_connect(hostname, port, SOCK_STREAM, 0, error);
    158 #else
    159             // Disallow arbitrary connections in adbd.
    160             *error = "adbd does not support arbitrary tcp connections";
    161             return -1;
    162 #endif
    163         }
    164 
    165         if (result >= 0) {
    166             disable_tcp_nagle(result);
    167         }
    168         return result;
    169     }
    170 
    171     for (const auto& it : kLocalSocketTypes) {
    172         std::string prefix = it.first + ":";
    173         if (StartsWith(spec, prefix)) {
    174             if (!it.second.available) {
    175                 *error = StringPrintf("socket type %s is unavailable on this platform",
    176                                       it.first.c_str());
    177                 return -1;
    178             }
    179 
    180             return network_local_client(&spec[prefix.length()], it.second.socket_namespace,
    181                                         SOCK_STREAM, error);
    182         }
    183     }
    184 
    185     *error = StringPrintf("unknown socket specification '%s'", spec.c_str());
    186     return -1;
    187 }
    188 
    189 int socket_spec_listen(const std::string& spec, std::string* error, int* resolved_tcp_port) {
    190     if (StartsWith(spec, "tcp:")) {
    191         std::string hostname;
    192         int port;
    193         if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) {
    194             return -1;
    195         }
    196 
    197         int result;
    198         if (hostname.empty() && gListenAll) {
    199             result = network_inaddr_any_server(port, SOCK_STREAM, error);
    200         } else if (tcp_host_is_local(hostname)) {
    201             result = network_loopback_server(port, SOCK_STREAM, error);
    202         } else {
    203             // TODO: Implement me.
    204             *error = "listening on specified hostname currently unsupported";
    205             return -1;
    206         }
    207 
    208         if (result >= 0 && port == 0 && resolved_tcp_port) {
    209             *resolved_tcp_port = adb_socket_get_local_port(result);
    210         }
    211         return result;
    212     }
    213 
    214     for (const auto& it : kLocalSocketTypes) {
    215         std::string prefix = it.first + ":";
    216         if (StartsWith(spec, prefix)) {
    217             if (!it.second.available) {
    218                 *error = StringPrintf("attempted to listen on unavailable socket type: '%s'",
    219                                       spec.c_str());
    220                 return -1;
    221             }
    222 
    223             return network_local_server(&spec[prefix.length()], it.second.socket_namespace,
    224                                         SOCK_STREAM, error);
    225         }
    226     }
    227 
    228     *error = StringPrintf("unknown socket specification '%s'", spec.c_str());
    229     return -1;
    230 }
    231