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.c_str())) { 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.c_str())) { 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.c_str())) { 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.c_str())) { 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