1cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao/* 2cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * Copyright (C) 2016 The Android Open Source Project 3cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * 4cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * Licensed under the Apache License, Version 2.0 (the "License"); 5cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * you may not use this file except in compliance with the License. 6cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * You may obtain a copy of the License at 7cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * 8cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * http://www.apache.org/licenses/LICENSE-2.0 9cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * 10cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * Unless required by applicable law or agreed to in writing, software 11cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * distributed under the License is distributed on an "AS IS" BASIS, 12cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * See the License for the specific language governing permissions and 14cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao * limitations under the License. 15cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao */ 16cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 17cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#include "socket_spec.h" 18cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 19cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#include <string> 20cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#include <unordered_map> 21cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#include <vector> 22cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 231099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao#include <android-base/parseint.h> 241099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao#include <android-base/parsenetaddress.h> 25cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#include <android-base/stringprintf.h> 26cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#include <android-base/strings.h> 27cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#include <cutils/sockets.h> 28cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 29cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#include "adb.h" 30cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#include "sysdeps.h" 31cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 32cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gaousing android::base::StartsWith; 33cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gaousing android::base::StringPrintf; 34cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 35cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#if defined(__linux__) 36cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#define ADB_LINUX 1 37cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#else 38cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#define ADB_LINUX 0 39cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#endif 40cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 41cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#if defined(_WIN32) 42cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#define ADB_WINDOWS 1 43cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#else 44cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#define ADB_WINDOWS 0 45cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#endif 46cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 47cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao// Not static because it is used in commandline.c. 48cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gaoint gListenAll = 0; 49cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 50cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gaostruct LocalSocketType { 51cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao int socket_namespace; 52cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao bool available; 53cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao}; 54cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 55cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gaostatic auto& kLocalSocketTypes = *new std::unordered_map<std::string, LocalSocketType>({ 56cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#if ADB_HOST 57cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao { "local", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } }, 58cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#else 59cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao { "local", { ANDROID_SOCKET_NAMESPACE_RESERVED, !ADB_WINDOWS } }, 60cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#endif 61cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 62cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao { "localreserved", { ANDROID_SOCKET_NAMESPACE_RESERVED, !ADB_HOST } }, 63cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao { "localabstract", { ANDROID_SOCKET_NAMESPACE_ABSTRACT, ADB_LINUX } }, 64cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao { "localfilesystem", { ANDROID_SOCKET_NAMESPACE_FILESYSTEM, !ADB_WINDOWS } }, 65cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao}); 66cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 671099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gaobool parse_tcp_socket_spec(const std::string& spec, std::string* hostname, int* port, 68cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao std::string* error) { 691099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao if (!StartsWith(spec, "tcp:")) { 70cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao *error = StringPrintf("specification is not tcp: '%s'", spec.c_str()); 71cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return false; 72cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 73cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 741099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao std::string hostname_value; 751099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao int port_value; 76cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 771099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao // If the spec is tcp:<port>, parse it ourselves. 781099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao // Otherwise, delegate to android::base::ParseNetAddress. 791099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao if (android::base::ParseInt(&spec[4], &port_value)) { 801099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao // Do the range checking ourselves, because ParseInt rejects 'tcp:65536' and 'tcp:foo:1234' 811099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao // identically. 821099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao if (port_value < 0 || port_value > 65535) { 831099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao *error = StringPrintf("bad port number '%d'", port_value); 841099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao return false; 85cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 86cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } else { 871099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao std::string addr = spec.substr(4); 881099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao port_value = -1; 891099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao 901099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao // FIXME: ParseNetAddress rejects port 0. This currently doesn't hurt, because listening 911099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao // on an address that isn't 'localhost' is unsupported. 921099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, nullptr, error)) { 93cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return false; 94cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 951099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao 961099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao if (port_value == -1) { 971099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao *error = StringPrintf("missing port in specification: '%s'", spec.c_str()); 981099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao return false; 99cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 100cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 101cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 1021099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao if (hostname) { 1031099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao *hostname = std::move(hostname_value); 1041099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao } 1051099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao 106cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (port) { 1071099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao *port = port_value; 108cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 109cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 110cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return true; 111cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao} 112cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 113cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gaostatic bool tcp_host_is_local(const std::string& hostname) { 114cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao // FIXME 115cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return hostname.empty() || hostname == "localhost"; 116cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao} 117cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 118cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gaobool is_socket_spec(const std::string& spec) { 119cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao for (const auto& it : kLocalSocketTypes) { 120cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao std::string prefix = it.first + ":"; 121cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (StartsWith(spec, prefix.c_str())) { 122cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return true; 123cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 124cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 125cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return StartsWith(spec, "tcp:"); 126cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao} 127cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 1289c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gaobool is_local_socket_spec(const std::string& spec) { 1299c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao for (const auto& it : kLocalSocketTypes) { 1309c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao std::string prefix = it.first + ":"; 1319c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao if (StartsWith(spec, prefix.c_str())) { 1329c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao return true; 1339c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao } 1349c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao } 1359c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao 1369c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao std::string error; 1379c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao std::string hostname; 1381099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao if (!parse_tcp_socket_spec(spec, &hostname, nullptr, &error)) { 1399c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao return false; 1409c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao } 1419c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao return tcp_host_is_local(hostname); 1429c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao} 1439c869b58a8cf4f7c3bc88931fbd27d3f5187b2dbJosh Gao 144cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gaoint socket_spec_connect(const std::string& spec, std::string* error) { 145cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (StartsWith(spec, "tcp:")) { 146cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao std::string hostname; 147cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao int port; 1481099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) { 149cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return -1; 150cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 151cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 152cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao int result; 153cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (tcp_host_is_local(hostname)) { 154cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao result = network_loopback_client(port, SOCK_STREAM, error); 155cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } else { 156cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#if ADB_HOST 157cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao result = network_connect(hostname, port, SOCK_STREAM, 0, error); 158cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#else 159cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao // Disallow arbitrary connections in adbd. 160cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao *error = "adbd does not support arbitrary tcp connections"; 161cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return -1; 162cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao#endif 163cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 164cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 165cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (result >= 0) { 166cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao disable_tcp_nagle(result); 167cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 168cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return result; 169cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 170cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 171cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao for (const auto& it : kLocalSocketTypes) { 172cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao std::string prefix = it.first + ":"; 173cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (StartsWith(spec, prefix.c_str())) { 174cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (!it.second.available) { 175cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao *error = StringPrintf("socket type %s is unavailable on this platform", 176cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao it.first.c_str()); 177cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return -1; 178cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 179cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 180cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return network_local_client(&spec[prefix.length()], it.second.socket_namespace, 181cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao SOCK_STREAM, error); 182cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 183cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 184cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 185cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao *error = StringPrintf("unknown socket specification '%s'", spec.c_str()); 186cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return -1; 187cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao} 188cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 189cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gaoint socket_spec_listen(const std::string& spec, std::string* error, int* resolved_tcp_port) { 190cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (StartsWith(spec, "tcp:")) { 191cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao std::string hostname; 192cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao int port; 1931099215e30c3b09dfa390c638a45487c43b2b1e1Josh Gao if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) { 194cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return -1; 195cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 196cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 197cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao int result; 198cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (hostname.empty() && gListenAll) { 199cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao result = network_inaddr_any_server(port, SOCK_STREAM, error); 200cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } else if (tcp_host_is_local(hostname)) { 201cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao result = network_loopback_server(port, SOCK_STREAM, error); 202cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } else { 203cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao // TODO: Implement me. 204cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao *error = "listening on specified hostname currently unsupported"; 205cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return -1; 206cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 207cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 208cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (result >= 0 && port == 0 && resolved_tcp_port) { 209cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao *resolved_tcp_port = adb_socket_get_local_port(result); 210cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 211cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return result; 212cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 213cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 214cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao for (const auto& it : kLocalSocketTypes) { 215cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao std::string prefix = it.first + ":"; 216cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (StartsWith(spec, prefix.c_str())) { 217cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao if (!it.second.available) { 218cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao *error = StringPrintf("attempted to listen on unavailable socket type: '%s'", 219cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao spec.c_str()); 220cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return -1; 221cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 222cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 223cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return network_local_server(&spec[prefix.length()], it.second.socket_namespace, 224cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao SOCK_STREAM, error); 225cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 226cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao } 227cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao 228cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao *error = StringPrintf("unknown socket specification '%s'", spec.c_str()); 229cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao return -1; 230cfb21412e5e3a716fc45601f35d3b58ce5f78f46Josh Gao} 231