| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <errno.h> | 5 #include <errno.h> |
| 6 #include <signal.h> | 6 #include <signal.h> |
| 7 #include <sys/types.h> | 7 #include <sys/types.h> |
| 8 #include <sys/wait.h> | 8 #include <sys/wait.h> |
| 9 #include <unistd.h> | 9 #include <unistd.h> |
| 10 | 10 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 } | 91 } |
| 92 | 92 |
| 93 ~HostControllersManager() { | 93 ~HostControllersManager() { |
| 94 if (!thread_.get()) | 94 if (!thread_.get()) |
| 95 return; | 95 return; |
| 96 // Delete the controllers on the thread they were created on. | 96 // Delete the controllers on the thread they were created on. |
| 97 thread_->message_loop_proxy()->DeleteSoon( | 97 thread_->message_loop_proxy()->DeleteSoon( |
| 98 FROM_HERE, controllers_.release()); | 98 FROM_HERE, controllers_.release()); |
| 99 } | 99 } |
| 100 | 100 |
| 101 void HandleRequest(const std::string& device_serial, | 101 void HandleRequest(const std::string& adb_path, |
| 102 const std::string& device_serial, |
| 102 int device_port, | 103 int device_port, |
| 103 int host_port, | 104 int host_port, |
| 104 scoped_ptr<Socket> client_socket) { | 105 scoped_ptr<Socket> client_socket) { |
| 105 // Lazy initialize so that the CLI process doesn't get this thread created. | 106 // Lazy initialize so that the CLI process doesn't get this thread created. |
| 106 InitOnce(); | 107 InitOnce(); |
| 107 thread_->message_loop_proxy()->PostTask( | 108 thread_->message_loop_proxy()->PostTask( |
| 108 FROM_HERE, | 109 FROM_HERE, |
| 109 base::Bind( | 110 base::Bind(&HostControllersManager::HandleRequestOnInternalThread, |
| 110 &HostControllersManager::HandleRequestOnInternalThread, | 111 base::Unretained(this), adb_path, device_serial, device_port, |
| 111 base::Unretained(this), device_serial, device_port, host_port, | 112 host_port, base::Passed(&client_socket))); |
| 112 base::Passed(&client_socket))); | |
| 113 } | 113 } |
| 114 | 114 |
| 115 bool has_failed() const { return has_failed_; } | 115 bool has_failed() const { return has_failed_; } |
| 116 | 116 |
| 117 private: | 117 private: |
| 118 typedef base::hash_map< | 118 typedef base::hash_map< |
| 119 std::string, linked_ptr<HostController> > HostControllerMap; | 119 std::string, linked_ptr<HostController> > HostControllerMap; |
| 120 | 120 |
| 121 static std::string MakeHostControllerMapKey(int adb_port, int device_port) { | 121 static std::string MakeHostControllerMapKey(int adb_port, int device_port) { |
| 122 return base::StringPrintf("%d:%d", adb_port, device_port); | 122 return base::StringPrintf("%d:%d", adb_port, device_port); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 145 return; | 145 return; |
| 146 } | 146 } |
| 147 DCHECK(manager->thread_->message_loop_proxy()->RunsTasksOnCurrentThread()); | 147 DCHECK(manager->thread_->message_loop_proxy()->RunsTasksOnCurrentThread()); |
| 148 // Note that this will delete |controller| which is owned by the map. | 148 // Note that this will delete |controller| which is owned by the map. |
| 149 DeleteRefCountedValueInMap( | 149 DeleteRefCountedValueInMap( |
| 150 MakeHostControllerMapKey( | 150 MakeHostControllerMapKey( |
| 151 controller->adb_port(), controller->device_port()), | 151 controller->adb_port(), controller->device_port()), |
| 152 manager->controllers_.get()); | 152 manager->controllers_.get()); |
| 153 } | 153 } |
| 154 | 154 |
| 155 void HandleRequestOnInternalThread(const std::string& device_serial, | 155 void HandleRequestOnInternalThread(const std::string& adb_path, |
| 156 const std::string& device_serial, |
| 156 int device_port, | 157 int device_port, |
| 157 int host_port, | 158 int host_port, |
| 158 scoped_ptr<Socket> client_socket) { | 159 scoped_ptr<Socket> client_socket) { |
| 159 const int adb_port = GetAdbPortForDevice(device_serial); | 160 const int adb_port = GetAdbPortForDevice(adb_path, device_serial); |
| 160 if (adb_port < 0) { | 161 if (adb_port < 0) { |
| 161 SendMessage( | 162 SendMessage( |
| 162 "ERROR: could not get adb port for device. You might need to add " | 163 "ERROR: could not get adb port for device. You might need to add " |
| 163 "'adb' to your PATH or provide the device serial id.", | 164 "'adb' to your PATH or provide the device serial id.", |
| 164 client_socket.get()); | 165 client_socket.get()); |
| 165 return; | 166 return; |
| 166 } | 167 } |
| 167 if (device_port < 0) { | 168 if (device_port < 0) { |
| 168 // Remove the previously created host controller. | 169 // Remove the previously created host controller. |
| 169 const std::string controller_key = MakeHostControllerMapKey( | 170 const std::string controller_key = MakeHostControllerMapKey( |
| 170 adb_port, -device_port); | 171 adb_port, -device_port); |
| 171 const bool controller_did_exist = DeleteRefCountedValueInMap( | 172 const bool controller_did_exist = DeleteRefCountedValueInMap( |
| 172 controller_key, controllers_.get()); | 173 controller_key, controllers_.get()); |
| 173 SendMessage( | 174 SendMessage( |
| 174 !controller_did_exist ? "ERROR: could not unmap port" : "OK", | 175 !controller_did_exist ? "ERROR: could not unmap port" : "OK", |
| 175 client_socket.get()); | 176 client_socket.get()); |
| 176 | 177 |
| 177 RemoveAdbPortForDeviceIfNeeded(device_serial); | 178 RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial); |
| 178 return; | 179 return; |
| 179 } | 180 } |
| 180 if (host_port < 0) { | 181 if (host_port < 0) { |
| 181 SendMessage("ERROR: missing host port", client_socket.get()); | 182 SendMessage("ERROR: missing host port", client_socket.get()); |
| 182 return; | 183 return; |
| 183 } | 184 } |
| 184 const bool use_dynamic_port_allocation = device_port == 0; | 185 const bool use_dynamic_port_allocation = device_port == 0; |
| 185 if (!use_dynamic_port_allocation) { | 186 if (!use_dynamic_port_allocation) { |
| 186 const std::string controller_key = MakeHostControllerMapKey( | 187 const std::string controller_key = MakeHostControllerMapKey( |
| 187 adb_port, device_port); | 188 adb_port, device_port); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 210 << host_port; | 211 << host_port; |
| 211 const std::string msg = base::StringPrintf("%d:%d", device_port, host_port); | 212 const std::string msg = base::StringPrintf("%d:%d", device_port, host_port); |
| 212 if (!SendMessage(msg, client_socket.get())) | 213 if (!SendMessage(msg, client_socket.get())) |
| 213 return; | 214 return; |
| 214 host_controller->Start(); | 215 host_controller->Start(); |
| 215 controllers_->insert( | 216 controllers_->insert( |
| 216 std::make_pair(MakeHostControllerMapKey(adb_port, device_port), | 217 std::make_pair(MakeHostControllerMapKey(adb_port, device_port), |
| 217 linked_ptr<HostController>(host_controller.release()))); | 218 linked_ptr<HostController>(host_controller.release()))); |
| 218 } | 219 } |
| 219 | 220 |
| 220 void RemoveAdbPortForDeviceIfNeeded(const std::string& device_serial) { | 221 void RemoveAdbPortForDeviceIfNeeded(const std::string& adb_path, |
| 222 const std::string& device_serial) { |
| 221 base::hash_map<std::string, int>::const_iterator it = | 223 base::hash_map<std::string, int>::const_iterator it = |
| 222 device_serial_to_adb_port_map_.find(device_serial); | 224 device_serial_to_adb_port_map_.find(device_serial); |
| 223 if (it == device_serial_to_adb_port_map_.end()) | 225 if (it == device_serial_to_adb_port_map_.end()) |
| 224 return; | 226 return; |
| 225 | 227 |
| 226 int port = it->second; | 228 int port = it->second; |
| 227 const std::string prefix = base::StringPrintf("%d:", port); | 229 const std::string prefix = base::StringPrintf("%d:", port); |
| 228 for (HostControllerMap::const_iterator others = controllers_->begin(); | 230 for (HostControllerMap::const_iterator others = controllers_->begin(); |
| 229 others != controllers_->end(); ++others) { | 231 others != controllers_->end(); ++others) { |
| 230 if (others->first.find(prefix) == 0U) | 232 if (others->first.find(prefix) == 0U) |
| 231 return; | 233 return; |
| 232 } | 234 } |
| 233 // No other port is being forwarded to this device: | 235 // No other port is being forwarded to this device: |
| 234 // - Remove it from our internal serial -> adb port map. | 236 // - Remove it from our internal serial -> adb port map. |
| 235 // - Remove from "adb forward" command. | 237 // - Remove from "adb forward" command. |
| 236 LOG(INFO) << "Device " << device_serial << " has no more ports."; | 238 LOG(INFO) << "Device " << device_serial << " has no more ports."; |
| 237 device_serial_to_adb_port_map_.erase(device_serial); | 239 device_serial_to_adb_port_map_.erase(device_serial); |
| 238 const std::string serial_part = device_serial.empty() ? | 240 const std::string serial_part = device_serial.empty() ? |
| 239 std::string() : std::string("-s ") + device_serial; | 241 std::string() : std::string("-s ") + device_serial; |
| 240 const std::string command = base::StringPrintf( | 242 const std::string command = base::StringPrintf( |
| 241 "adb %s forward --remove tcp:%d", | 243 "%s %s forward --remove tcp:%d", |
| 244 adb_path.c_str(), |
| 242 serial_part.c_str(), | 245 serial_part.c_str(), |
| 243 port); | 246 port); |
| 244 const int ret = system(command.c_str()); | 247 const int ret = system(command.c_str()); |
| 245 LOG(INFO) << command << " ret: " << ret; | 248 LOG(INFO) << command << " ret: " << ret; |
| 246 // Wait for the socket to be fully unmapped. | 249 // Wait for the socket to be fully unmapped. |
| 247 const std::string port_mapped_cmd = base::StringPrintf( | 250 const std::string port_mapped_cmd = base::StringPrintf( |
| 248 "lsof -nPi:%d", | 251 "lsof -nPi:%d", |
| 249 port); | 252 port); |
| 250 const int poll_interval_us = 500 * 1000; | 253 const int poll_interval_us = 500 * 1000; |
| 251 int retries = 3; | 254 int retries = 3; |
| 252 while (retries) { | 255 while (retries) { |
| 253 const int port_unmapped = system(port_mapped_cmd.c_str()); | 256 const int port_unmapped = system(port_mapped_cmd.c_str()); |
| 254 LOG(INFO) << "Device " << device_serial << " port " << port << " unmap " | 257 LOG(INFO) << "Device " << device_serial << " port " << port << " unmap " |
| 255 << port_unmapped; | 258 << port_unmapped; |
| 256 if (port_unmapped) | 259 if (port_unmapped) |
| 257 break; | 260 break; |
| 258 --retries; | 261 --retries; |
| 259 usleep(poll_interval_us); | 262 usleep(poll_interval_us); |
| 260 } | 263 } |
| 261 } | 264 } |
| 262 | 265 |
| 263 int GetAdbPortForDevice(const std::string& device_serial) { | 266 int GetAdbPortForDevice(const std::string adb_path, |
| 267 const std::string& device_serial) { |
| 264 base::hash_map<std::string, int>::const_iterator it = | 268 base::hash_map<std::string, int>::const_iterator it = |
| 265 device_serial_to_adb_port_map_.find(device_serial); | 269 device_serial_to_adb_port_map_.find(device_serial); |
| 266 if (it != device_serial_to_adb_port_map_.end()) | 270 if (it != device_serial_to_adb_port_map_.end()) |
| 267 return it->second; | 271 return it->second; |
| 268 Socket bind_socket; | 272 Socket bind_socket; |
| 269 CHECK(bind_socket.BindTcp("127.0.0.1", 0)); | 273 CHECK(bind_socket.BindTcp("127.0.0.1", 0)); |
| 270 const int port = bind_socket.GetPort(); | 274 const int port = bind_socket.GetPort(); |
| 271 bind_socket.Close(); | 275 bind_socket.Close(); |
| 272 const std::string serial_part = device_serial.empty() ? | 276 const std::string serial_part = device_serial.empty() ? |
| 273 std::string() : std::string("-s ") + device_serial; | 277 std::string() : std::string("-s ") + device_serial; |
| 274 const std::string command = base::StringPrintf( | 278 const std::string command = base::StringPrintf( |
| 275 "adb %s forward tcp:%d localabstract:chrome_device_forwarder", | 279 "%s %s forward tcp:%d localabstract:chrome_device_forwarder", |
| 280 adb_path.c_str(), |
| 276 serial_part.c_str(), | 281 serial_part.c_str(), |
| 277 port); | 282 port); |
| 278 LOG(INFO) << command; | 283 LOG(INFO) << command; |
| 279 const int ret = system(command.c_str()); | 284 const int ret = system(command.c_str()); |
| 280 if (ret < 0 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0) | 285 if (ret < 0 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0) |
| 281 return -1; | 286 return -1; |
| 282 device_serial_to_adb_port_map_[device_serial] = port; | 287 device_serial_to_adb_port_map_[device_serial] = port; |
| 283 return port; | 288 return port; |
| 284 } | 289 } |
| 285 | 290 |
| 286 bool SendMessage(const std::string& msg, Socket* client_socket) { | 291 bool SendMessage(const std::string& msg, Socket* client_socket) { |
| 287 bool result = client_socket->WriteString(msg); | 292 bool result = client_socket->WriteString(msg); |
| 288 DCHECK(result); | 293 DCHECK(result); |
| 289 if (!result) | 294 if (!result) |
| 290 has_failed_ = true; | 295 has_failed_ = true; |
| 291 return result; | 296 return result; |
| 292 } | 297 } |
| 293 | 298 |
| 294 base::hash_map<std::string, int> device_serial_to_adb_port_map_; | 299 base::hash_map<std::string, int> device_serial_to_adb_port_map_; |
| 295 scoped_ptr<HostControllerMap> controllers_; | 300 scoped_ptr<HostControllerMap> controllers_; |
| 296 bool has_failed_; | 301 bool has_failed_; |
| 297 scoped_ptr<base::AtExitManager> at_exit_manager_; // Needed by base::Thread. | 302 scoped_ptr<base::AtExitManager> at_exit_manager_; // Needed by base::Thread. |
| 298 scoped_ptr<base::Thread> thread_; | 303 scoped_ptr<base::Thread> thread_; |
| 299 base::WeakPtrFactory<HostControllersManager> weak_ptr_factory_; | 304 base::WeakPtrFactory<HostControllersManager> weak_ptr_factory_; |
| 300 }; | 305 }; |
| 301 | 306 |
| 302 class ServerDelegate : public Daemon::ServerDelegate { | 307 class ServerDelegate : public Daemon::ServerDelegate { |
| 303 public: | 308 public: |
| 304 ServerDelegate() : has_failed_(false) {} | 309 ServerDelegate(const std::string& adb_path) |
| 310 : adb_path_(adb_path), has_failed_(false) {} |
| 305 | 311 |
| 306 bool has_failed() const { | 312 bool has_failed() const { |
| 307 return has_failed_ || controllers_manager_.has_failed(); | 313 return has_failed_ || controllers_manager_.has_failed(); |
| 308 } | 314 } |
| 309 | 315 |
| 310 // Daemon::ServerDelegate: | 316 // Daemon::ServerDelegate: |
| 311 virtual void Init() override { | 317 virtual void Init() override { |
| 312 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")"; | 318 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")"; |
| 313 DCHECK(!g_notifier); | 319 DCHECK(!g_notifier); |
| 314 g_notifier = new PipeNotifier(); | 320 g_notifier = new PipeNotifier(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 331 std::string device_serial; | 337 std::string device_serial; |
| 332 CHECK(pickle_it.ReadString(&device_serial)); | 338 CHECK(pickle_it.ReadString(&device_serial)); |
| 333 int device_port; | 339 int device_port; |
| 334 if (!pickle_it.ReadInt(&device_port)) { | 340 if (!pickle_it.ReadInt(&device_port)) { |
| 335 client_socket->WriteString("ERROR: missing device port"); | 341 client_socket->WriteString("ERROR: missing device port"); |
| 336 return; | 342 return; |
| 337 } | 343 } |
| 338 int host_port; | 344 int host_port; |
| 339 if (!pickle_it.ReadInt(&host_port)) | 345 if (!pickle_it.ReadInt(&host_port)) |
| 340 host_port = -1; | 346 host_port = -1; |
| 341 controllers_manager_.HandleRequest( | 347 controllers_manager_.HandleRequest(adb_path_, device_serial, device_port, |
| 342 device_serial, device_port, host_port, client_socket.Pass()); | 348 host_port, client_socket.Pass()); |
| 343 } | 349 } |
| 344 | 350 |
| 345 private: | 351 private: |
| 352 std::string adb_path_; |
| 346 bool has_failed_; | 353 bool has_failed_; |
| 347 HostControllersManager controllers_manager_; | 354 HostControllersManager controllers_manager_; |
| 348 | 355 |
| 349 DISALLOW_COPY_AND_ASSIGN(ServerDelegate); | 356 DISALLOW_COPY_AND_ASSIGN(ServerDelegate); |
| 350 }; | 357 }; |
| 351 | 358 |
| 352 class ClientDelegate : public Daemon::ClientDelegate { | 359 class ClientDelegate : public Daemon::ClientDelegate { |
| 353 public: | 360 public: |
| 354 ClientDelegate(const Pickle& command_pickle) | 361 ClientDelegate(const Pickle& command_pickle) |
| 355 : command_pickle_(command_pickle), | 362 : command_pickle_(command_pickle), |
| (...skipping 27 matching lines...) Expand all Loading... |
| 383 const Pickle command_pickle_; | 390 const Pickle command_pickle_; |
| 384 bool has_failed_; | 391 bool has_failed_; |
| 385 }; | 392 }; |
| 386 | 393 |
| 387 void ExitWithUsage() { | 394 void ExitWithUsage() { |
| 388 std::cerr << "Usage: host_forwarder [options]\n\n" | 395 std::cerr << "Usage: host_forwarder [options]\n\n" |
| 389 "Options:\n" | 396 "Options:\n" |
| 390 " --serial-id=[0-9A-Z]{16}]\n" | 397 " --serial-id=[0-9A-Z]{16}]\n" |
| 391 " --map DEVICE_PORT HOST_PORT\n" | 398 " --map DEVICE_PORT HOST_PORT\n" |
| 392 " --unmap DEVICE_PORT\n" | 399 " --unmap DEVICE_PORT\n" |
| 400 " --adb PATH_TO_ADB\n" |
| 393 " --kill-server\n"; | 401 " --kill-server\n"; |
| 394 exit(1); | 402 exit(1); |
| 395 } | 403 } |
| 396 | 404 |
| 397 int PortToInt(const std::string& s) { | 405 int PortToInt(const std::string& s) { |
| 398 int value; | 406 int value; |
| 399 // Note that 0 is a valid port (used for dynamic port allocation). | 407 // Note that 0 is a valid port (used for dynamic port allocation). |
| 400 if (!base::StringToInt(s, &value) || value < 0 || | 408 if (!base::StringToInt(s, &value) || value < 0 || |
| 401 value > std::numeric_limits<uint16>::max()) { | 409 value > std::numeric_limits<uint16>::max()) { |
| 402 LOG(ERROR) << "Could not convert string " << s << " to port"; | 410 LOG(ERROR) << "Could not convert string " << s << " to port"; |
| 403 ExitWithUsage(); | 411 ExitWithUsage(); |
| 404 } | 412 } |
| 405 return value; | 413 return value; |
| 406 } | 414 } |
| 407 | 415 |
| 408 int RunHostForwarder(int argc, char** argv) { | 416 int RunHostForwarder(int argc, char** argv) { |
| 409 base::CommandLine::Init(argc, argv); | 417 base::CommandLine::Init(argc, argv); |
| 410 const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess(); | 418 const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess(); |
| 419 std::string adb_path = "adb"; |
| 411 bool kill_server = false; | 420 bool kill_server = false; |
| 412 | 421 |
| 413 Pickle pickle; | 422 Pickle pickle; |
| 414 pickle.WriteString( | 423 pickle.WriteString( |
| 415 cmd_line.HasSwitch("serial-id") ? | 424 cmd_line.HasSwitch("serial-id") ? |
| 416 cmd_line.GetSwitchValueASCII("serial-id") : std::string()); | 425 cmd_line.GetSwitchValueASCII("serial-id") : std::string()); |
| 417 | 426 |
| 418 const std::vector<std::string> args = cmd_line.GetArgs(); | 427 const std::vector<std::string> args = cmd_line.GetArgs(); |
| 419 if (cmd_line.HasSwitch("kill-server")) { | 428 if (cmd_line.HasSwitch("kill-server")) { |
| 420 kill_server = true; | 429 kill_server = true; |
| 421 } else if (cmd_line.HasSwitch("unmap")) { | 430 } else if (cmd_line.HasSwitch("unmap")) { |
| 422 if (args.size() != 1) | 431 if (args.size() != 1) |
| 423 ExitWithUsage(); | 432 ExitWithUsage(); |
| 424 // Note the minus sign below. | 433 // Note the minus sign below. |
| 425 pickle.WriteInt(-PortToInt(args[0])); | 434 pickle.WriteInt(-PortToInt(args[0])); |
| 426 } else if (cmd_line.HasSwitch("map")) { | 435 } else if (cmd_line.HasSwitch("map")) { |
| 427 if (args.size() != 2) | 436 if (args.size() != 2) |
| 428 ExitWithUsage(); | 437 ExitWithUsage(); |
| 429 pickle.WriteInt(PortToInt(args[0])); | 438 pickle.WriteInt(PortToInt(args[0])); |
| 430 pickle.WriteInt(PortToInt(args[1])); | 439 pickle.WriteInt(PortToInt(args[1])); |
| 431 } else { | 440 } else { |
| 432 ExitWithUsage(); | 441 ExitWithUsage(); |
| 433 } | 442 } |
| 434 | 443 |
| 444 if (cmd_line.HasSwitch("adb")) { |
| 445 adb_path = cmd_line.GetSwitchValueASCII("adb"); |
| 446 } |
| 447 |
| 435 if (kill_server && args.size() > 0) | 448 if (kill_server && args.size() > 0) |
| 436 ExitWithUsage(); | 449 ExitWithUsage(); |
| 437 | 450 |
| 438 ClientDelegate client_delegate(pickle); | 451 ClientDelegate client_delegate(pickle); |
| 439 ServerDelegate daemon_delegate; | 452 ServerDelegate daemon_delegate(adb_path); |
| 440 Daemon daemon( | 453 Daemon daemon( |
| 441 kLogFilePath, kDaemonIdentifier, &client_delegate, &daemon_delegate, | 454 kLogFilePath, kDaemonIdentifier, &client_delegate, &daemon_delegate, |
| 442 &GetExitNotifierFD); | 455 &GetExitNotifierFD); |
| 443 | 456 |
| 444 if (kill_server) | 457 if (kill_server) |
| 445 return !daemon.Kill(); | 458 return !daemon.Kill(); |
| 446 if (!daemon.SpawnIfNeeded()) | 459 if (!daemon.SpawnIfNeeded()) |
| 447 return 1; | 460 return 1; |
| 448 | 461 |
| 449 return client_delegate.has_failed() || daemon_delegate.has_failed(); | 462 return client_delegate.has_failed() || daemon_delegate.has_failed(); |
| 450 } | 463 } |
| 451 | 464 |
| 452 } // namespace | 465 } // namespace |
| 453 } // namespace forwarder2 | 466 } // namespace forwarder2 |
| 454 | 467 |
| 455 int main(int argc, char** argv) { | 468 int main(int argc, char** argv) { |
| 456 return forwarder2::RunHostForwarder(argc, argv); | 469 return forwarder2::RunHostForwarder(argc, argv); |
| 457 } | 470 } |
| OLD | NEW |