1 /* 2 * Copyright (C) 2011 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 /* 18 * Encapsulates exchange protocol between the emulator, and an Android device 19 * that is connected to the host via USB. The communication is established over 20 * a TCP port forwarding, enabled by ADB. 21 */ 22 23 #include "android/utils/debug.h" 24 #include "android/async-socket-connector.h" 25 #include "utils/panic.h" 26 #include "iolooper.h" 27 28 #define E(...) derror(__VA_ARGS__) 29 #define W(...) dwarning(__VA_ARGS__) 30 #define D(...) VERBOSE_PRINT(asconnector,__VA_ARGS__) 31 #define D_ACTIVE VERBOSE_CHECK(asconnector) 32 33 #define TRACE_ON 0 34 35 #if TRACE_ON 36 #define T(...) VERBOSE_PRINT(asconnector,__VA_ARGS__) 37 #else 38 #define T(...) 39 #endif 40 41 /******************************************************************************** 42 * Internals 43 *******************************************************************************/ 44 45 struct AsyncSocketConnector { 46 /* TCP address for the connection. */ 47 SockAddress address; 48 /* I/O looper for asynchronous I/O. */ 49 Looper* looper; 50 /* I/O port for asynchronous connection. */ 51 LoopIo connector_io[1]; 52 /* Timer that is used to retry asynchronous connections. */ 53 LoopTimer connector_timer[1]; 54 /* Asynchronous connector to the socket. */ 55 AsyncConnector connector[1]; 56 /* Callback to invoke on connection events. */ 57 asc_event_cb on_connected_cb; 58 /* An opaque parameter to pass to the connection callback. */ 59 void* on_connected_cb_opaque; 60 /* Retry timeout in milliseconds. */ 61 int retry_to; 62 /* Socket descriptor for the connection. */ 63 int fd; 64 /* Number of outstanding references to the connector. */ 65 int ref_count; 66 /* Flags whether (1) or not (0) connector owns the looper. */ 67 int owns_looper; 68 }; 69 70 /* Asynchronous I/O looper callback invoked by the connector. 71 * Param: 72 * opaque - AsyncSocketConnector instance. 73 * fd, events - Standard I/O callback parameters. 74 */ 75 static void _on_async_socket_connector_io(void* opaque, int fd, unsigned events); 76 77 /* Gets socket's address string. */ 78 AINLINED const char* 79 _asc_socket_string(AsyncSocketConnector* connector) 80 { 81 return sock_address_to_string(&connector->address); 82 } 83 84 /* Destroys AsyncSocketConnector instance. 85 * Param: 86 * connector - Initialized AsyncSocketConnector instance. 87 */ 88 static void 89 _async_socket_connector_free(AsyncSocketConnector* connector) 90 { 91 if (connector != NULL) { 92 T("ASC %s: Connector is destroying...", _asc_socket_string(connector)); 93 94 /* Stop all activities. */ 95 if (asyncConnector_stop(connector->connector) == 0) { 96 /* Connection was in progress. We need to destroy I/O descriptor for 97 * that connection. */ 98 D("ASC %s: Stopped async connection in progress.", 99 _asc_socket_string(connector)); 100 loopIo_done(connector->connector_io); 101 } 102 103 /* Free allocated resources. */ 104 if (connector->looper != NULL) { 105 loopTimer_done(connector->connector_timer); 106 if (connector->owns_looper) { 107 looper_free(connector->looper); 108 } 109 } 110 111 if (connector->fd >= 0) { 112 socket_close(connector->fd); 113 } 114 115 T("ASC %s: Connector is destroyed", _asc_socket_string(connector)); 116 117 sock_address_done(&connector->address); 118 119 AFREE(connector); 120 } 121 } 122 123 /* Opens connection socket. 124 * Param: 125 * connector - Initialized AsyncSocketConnector instance. 126 * Return: 127 * 0 on success, or -1 on failure. 128 */ 129 static int 130 _async_socket_connector_open_socket(AsyncSocketConnector* connector) 131 { 132 /* Open socket. */ 133 connector->fd = socket_create_inet(SOCKET_STREAM); 134 if (connector->fd < 0) { 135 D("ASC %s: Unable to create socket: %d -> %s", 136 _asc_socket_string(connector), errno, strerror(errno)); 137 return -1; 138 } 139 140 /* Prepare for async I/O on the connector. */ 141 socket_set_nonblock(connector->fd); 142 143 T("ASC %s: Connector socket is opened with FD = %d", 144 _asc_socket_string(connector), connector->fd); 145 146 return 0; 147 } 148 149 /* Closes connection socket. 150 * Param: 151 * connector - Initialized AsyncSocketConnector instance. 152 * Return: 153 * 0 on success, or -1 on failure. 154 */ 155 static void 156 _async_socket_connector_close_socket(AsyncSocketConnector* connector) 157 { 158 if (connector->fd >= 0) { 159 socket_close(connector->fd); 160 T("ASC %s: Connector socket FD = %d is closed.", 161 _asc_socket_string(connector), connector->fd); 162 connector->fd = -1; 163 } 164 } 165 166 /* Asynchronous connector (AsyncConnector instance) has completed connection 167 * attempt. 168 * Param: 169 * connector - Initialized AsyncSocketConnector instance. Note: When this 170 * callback is called, the caller has referenced passed connector object, 171 * So, it's guaranteed that this connector is not going to be destroyed 172 * while this routine executes. 173 * status - Status of the connection attempt. 174 */ 175 static void 176 _on_async_socket_connector_connecting(AsyncSocketConnector* connector, 177 AsyncStatus status) 178 { 179 AsyncIOAction action = ASIO_ACTION_DONE; 180 181 switch (status) { 182 case ASYNC_COMPLETE: 183 loopIo_done(connector->connector_io); 184 D("Socket '%s' is connected", _asc_socket_string(connector)); 185 /* Invoke "on connected" callback */ 186 action = connector->on_connected_cb(connector->on_connected_cb_opaque, 187 connector, ASIO_STATE_SUCCEEDED); 188 break; 189 190 case ASYNC_ERROR: 191 loopIo_done(connector->connector_io); 192 D("Error while connecting to socket '%s': %d -> %s", 193 _asc_socket_string(connector), errno, strerror(errno)); 194 /* Invoke "on connected" callback */ 195 action = connector->on_connected_cb(connector->on_connected_cb_opaque, 196 connector, ASIO_STATE_FAILED); 197 break; 198 199 case ASYNC_NEED_MORE: 200 T("ASC %s: Waiting on connection to complete. Connector FD = %d", 201 _asc_socket_string(connector), connector->fd); 202 return; 203 } 204 205 if (action == ASIO_ACTION_RETRY) { 206 D("ASC %s: Retrying connection. Connector FD = %d", 207 _asc_socket_string(connector), connector->fd); 208 loopTimer_startRelative(connector->connector_timer, connector->retry_to); 209 } else if (action == ASIO_ACTION_ABORT) { 210 D("ASC %s: Client has aborted connection. Connector FD = %d", 211 _asc_socket_string(connector), connector->fd); 212 } 213 } 214 215 static void 216 _on_async_socket_connector_io(void* opaque, int fd, unsigned events) 217 { 218 AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque; 219 220 /* Reference the connector while we're handing I/O. */ 221 async_socket_connector_reference(connector); 222 223 /* Notify the client that another connection attempt is about to start. */ 224 const AsyncIOAction action = 225 connector->on_connected_cb(connector->on_connected_cb_opaque, 226 connector, ASIO_STATE_CONTINUES); 227 if (action != ASIO_ACTION_ABORT) { 228 /* Complete socket connection. */ 229 const AsyncStatus status = asyncConnector_run(connector->connector); 230 _on_async_socket_connector_connecting(connector, status); 231 } else { 232 D("ASC %s: Client has aborted connection. Connector FD = %d", 233 _asc_socket_string(connector), connector->fd); 234 } 235 236 /* Release the connector after we're done with handing I/O. */ 237 async_socket_connector_release(connector); 238 } 239 240 /* Retry connection timer callback. 241 * Param: 242 * opaque - AsyncSocketConnector instance. 243 */ 244 static void 245 _on_async_socket_connector_retry(void* opaque) 246 { 247 AsyncStatus status; 248 AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque; 249 250 T("ASC %s: Reconnect timer expired. Connector FD = %d", 251 _asc_socket_string(connector), connector->fd); 252 253 /* Reference the connector while we're in callback. */ 254 async_socket_connector_reference(connector); 255 256 /* Invoke the callback to notify about a connection retry attempt. */ 257 AsyncIOAction action = 258 connector->on_connected_cb(connector->on_connected_cb_opaque, 259 connector, ASIO_STATE_RETRYING); 260 261 if (action != ASIO_ACTION_ABORT) { 262 /* Close handle opened for the previous (failed) attempt. */ 263 _async_socket_connector_close_socket(connector); 264 265 /* Retry connection attempt. */ 266 if (_async_socket_connector_open_socket(connector) == 0) { 267 loopIo_init(connector->connector_io, connector->looper, 268 connector->fd, _on_async_socket_connector_io, connector); 269 status = asyncConnector_init(connector->connector, 270 &connector->address, 271 connector->connector_io); 272 } else { 273 status = ASYNC_ERROR; 274 } 275 276 _on_async_socket_connector_connecting(connector, status); 277 } else { 278 D("ASC %s: Client has aborted connection. Connector FD = %d", 279 _asc_socket_string(connector), connector->fd); 280 } 281 282 /* Release the connector after we're done with the callback. */ 283 async_socket_connector_release(connector); 284 } 285 286 /******************************************************************************** 287 * Async connector implementation 288 *******************************************************************************/ 289 290 AsyncSocketConnector* 291 async_socket_connector_new(const SockAddress* address, 292 int retry_to, 293 asc_event_cb cb, 294 void* cb_opaque, 295 Looper* looper) 296 { 297 AsyncSocketConnector* connector; 298 299 if (cb == NULL) { 300 W("No callback for AsyncSocketConnector for socket '%s'", 301 sock_address_to_string(address)); 302 errno = EINVAL; 303 return NULL; 304 } 305 306 ANEW0(connector); 307 308 connector->fd = -1; 309 connector->retry_to = retry_to; 310 connector->on_connected_cb = cb; 311 connector->on_connected_cb_opaque = cb_opaque; 312 connector->ref_count = 1; 313 314 /* Copy socket address. */ 315 #ifdef _WIN32 316 connector->address = *address; 317 #else 318 if (sock_address_get_family(address) == SOCKET_UNIX) { 319 sock_address_init_unix(&connector->address, sock_address_get_path(address)); 320 } else { 321 connector->address = *address; 322 } 323 #endif 324 325 /* Create a looper for asynchronous I/O. */ 326 if (looper == NULL) { 327 connector->looper = looper_newCore(); 328 if (connector->looper == NULL) { 329 E("Unable to create I/O looper for AsyncSocketConnector for socket '%s'", 330 _asc_socket_string(connector)); 331 cb(cb_opaque, connector, ASIO_STATE_FAILED); 332 _async_socket_connector_free(connector); 333 return NULL; 334 } 335 connector->owns_looper = 1; 336 } else { 337 connector->looper = looper; 338 connector->owns_looper = 0; 339 } 340 341 /* Create a timer that will be used for connection retries. */ 342 loopTimer_init(connector->connector_timer, connector->looper, 343 _on_async_socket_connector_retry, connector); 344 345 T("ASC %s: New connector object", _asc_socket_string(connector)); 346 347 return connector; 348 } 349 350 int 351 async_socket_connector_reference(AsyncSocketConnector* connector) 352 { 353 assert(connector->ref_count > 0); 354 connector->ref_count++; 355 return connector->ref_count; 356 } 357 358 int 359 async_socket_connector_release(AsyncSocketConnector* connector) 360 { 361 assert(connector->ref_count > 0); 362 connector->ref_count--; 363 if (connector->ref_count == 0) { 364 /* Last reference has been dropped. Destroy this object. */ 365 _async_socket_connector_free(connector); 366 return 0; 367 } 368 return connector->ref_count; 369 } 370 371 void 372 async_socket_connector_connect(AsyncSocketConnector* connector) 373 { 374 AsyncStatus status; 375 376 T("ASC %s: Handling connect request. Connector FD = %d", 377 _asc_socket_string(connector), connector->fd); 378 379 if (_async_socket_connector_open_socket(connector) == 0) { 380 const AsyncIOAction action = 381 connector->on_connected_cb(connector->on_connected_cb_opaque, 382 connector, ASIO_STATE_STARTED); 383 if (action == ASIO_ACTION_ABORT) { 384 D("ASC %s: Client has aborted connection. Connector FD = %d", 385 _asc_socket_string(connector), connector->fd); 386 return; 387 } else { 388 loopIo_init(connector->connector_io, connector->looper, 389 connector->fd, _on_async_socket_connector_io, connector); 390 status = asyncConnector_init(connector->connector, 391 &connector->address, 392 connector->connector_io); 393 } 394 } else { 395 status = ASYNC_ERROR; 396 } 397 398 _on_async_socket_connector_connecting(connector, status); 399 } 400 401 int 402 async_socket_connector_pull_fd(AsyncSocketConnector* connector) 403 { 404 const int fd = connector->fd; 405 if (fd >= 0) { 406 connector->fd = -1; 407 } 408 409 T("ASC %s: Client has pulled connector FD %d", _asc_socket_string(connector), fd); 410 411 return fd; 412 } 413