Vladimir Chtchetkine | d86c724 | 2011-12-09 15:45:46 -0800 | [diff] [blame] | 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 | #include "qemu-common.h" |
David 'Digit' Turner | cc330d4 | 2013-12-14 23:26:42 +0100 | [diff] [blame] | 18 | #include "android/sockets.h" |
David 'Digit' Turner | d413fa5 | 2013-12-14 23:35:20 +0100 | [diff] [blame] | 19 | #include "android/iolooper.h" |
Vladimir Chtchetkine | d86c724 | 2011-12-09 15:45:46 -0800 | [diff] [blame] | 20 | #include "android/async-utils.h" |
| 21 | #include "android/utils/debug.h" |
| 22 | #include "android/utils/list.h" |
| 23 | #include "android/utils/misc.h" |
| 24 | #include "android/adb-server.h" |
| 25 | |
| 26 | #define E(...) derror(__VA_ARGS__) |
| 27 | #define W(...) dwarning(__VA_ARGS__) |
| 28 | #define D(...) VERBOSE_PRINT(adbserver,__VA_ARGS__) |
| 29 | #define D_ACTIVE VERBOSE_CHECK(adbserver) |
| 30 | #define QB(b, s) quote_bytes((const char*)b, (s < 32) ? s : 32) |
| 31 | |
| 32 | typedef struct AdbServer AdbServer; |
| 33 | typedef struct AdbHost AdbHost; |
| 34 | typedef struct AdbGuest AdbGuest; |
| 35 | |
| 36 | /* ADB guest connection descriptor. */ |
| 37 | struct AdbGuest { |
| 38 | /* Entry in the list of pending or connected ADB guests. |
| 39 | * NOTE: This must be the first entry in the descriptor! */ |
| 40 | ACList list_entry; |
| 41 | /* Opaque pointer associated with the guest. */ |
| 42 | void* opaque; |
| 43 | /* ADB server for this guest. */ |
| 44 | AdbServer* adb_srv; |
| 45 | /* ADB host connected with this ADB guest. */ |
| 46 | AdbHost* adb_host; |
| 47 | /* Callback routines for the ADB guest. */ |
| 48 | AdbGuestRoutines* callbacks; |
| 49 | /* ADB guest connection status. If 0 indicates that ADB guest is not yet |
| 50 | * ready to receive data from the host. */ |
| 51 | int is_connected; |
| 52 | }; |
| 53 | |
| 54 | /* ADB host connection descriptor. */ |
| 55 | struct AdbHost { |
| 56 | /* Entry in the list of pending or connected ADB hosts. |
| 57 | * NOTE: This must be the first entry in the descriptor! */ |
| 58 | ACList list_entry; |
| 59 | /* ADB server for this host. */ |
| 60 | AdbServer* adb_srv; |
| 61 | /* ADB socket connected with the host. */ |
| 62 | int host_so; |
| 63 | /* I/O port for asynchronous I/O on the host socket. */ |
| 64 | LoopIo io[1]; |
| 65 | /* ADB guest connected with this ADB host. */ |
| 66 | AdbGuest* adb_guest; |
| 67 | /* Pending data to send to the guest when it is fully connected. */ |
| 68 | uint8_t* pending_data; |
| 69 | /* Size of the pending data buffer. */ |
| 70 | int pending_data_size; |
| 71 | /* Contains data that are pending to be sent to the host. */ |
| 72 | uint8_t* pending_send_buffer; |
| 73 | /* Number of bytes that are pending to be sent to the host. */ |
| 74 | int pending_send_data_size; |
| 75 | /* Size of the pending_send_buffer */ |
| 76 | int pending_send_buffer_size; |
| 77 | }; |
| 78 | |
| 79 | /* ADB server descriptor. */ |
| 80 | struct AdbServer { |
| 81 | /* ADB socket address. */ |
| 82 | SockAddress socket_address; |
| 83 | /* Looper for async I/O on ADB server socket. */ |
| 84 | Looper* looper; |
| 85 | /* I/O port for asynchronous I/O on ADB server socket. */ |
| 86 | LoopIo io[1]; |
| 87 | /* ADB port. */ |
| 88 | int port; |
| 89 | /* Server socket. */ |
| 90 | int so; |
| 91 | /* List of connected ADB hosts. */ |
| 92 | ACList adb_hosts; |
| 93 | /* List of connected ADB guests. */ |
| 94 | ACList adb_guests; |
| 95 | /* List of ADB hosts pending connection with ADB guest. */ |
| 96 | ACList pending_hosts; |
| 97 | /* List of ADB guests pending connection with ADB host. */ |
| 98 | ACList pending_guests; |
| 99 | }; |
| 100 | |
| 101 | /* One and only one ADB server instance. */ |
| 102 | static AdbServer _adb_server; |
| 103 | /* ADB server initialization flag. */ |
| 104 | static int _adb_server_initialized = 0; |
| 105 | |
| 106 | /******************************************************************************** |
| 107 | * ADB host API |
| 108 | *******************************************************************************/ |
| 109 | |
| 110 | /* Creates and initializes a new AdbHost instance. */ |
| 111 | static AdbHost* |
| 112 | _adb_host_new(AdbServer* adb_srv) |
| 113 | { |
| 114 | AdbHost* adb_host; |
| 115 | |
| 116 | ANEW0(adb_host); |
| 117 | alist_init(&adb_host->list_entry); |
| 118 | adb_host->adb_srv = adb_srv; |
| 119 | adb_host->host_so = -1; |
| 120 | |
| 121 | return adb_host; |
| 122 | } |
| 123 | |
| 124 | /* Frees AdbHost instance created with _adb_host_new routine. */ |
| 125 | static void |
| 126 | _adb_host_free(AdbHost* adb_host) |
| 127 | { |
| 128 | if (adb_host != NULL) { |
| 129 | /* At this point it must not be listed anywhere. */ |
| 130 | assert(alist_is_empty(&adb_host->list_entry)); |
| 131 | |
| 132 | /* Close the host socket. */ |
| 133 | if (adb_host->host_so >= 0) { |
| 134 | loopIo_done(adb_host->io); |
| 135 | socket_close(adb_host->host_so); |
| 136 | } |
| 137 | |
| 138 | /* Free pending data buffers. */ |
| 139 | if (adb_host->pending_data != NULL) { |
| 140 | free(adb_host->pending_data); |
| 141 | } |
| 142 | if (adb_host->pending_send_buffer != NULL) { |
| 143 | free(adb_host->pending_send_buffer); |
| 144 | } |
| 145 | |
| 146 | AFREE(adb_host); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | static void |
| 151 | _adb_host_append_message(AdbHost* adb_host, const void* msg, int msglen) |
| 152 | { |
| 153 | printf("Append %d bytes to ADB host buffer.\n", msglen); |
| 154 | |
| 155 | /* Make sure that buffer can contain the appending data. */ |
| 156 | if (adb_host->pending_send_buffer == NULL) { |
| 157 | adb_host->pending_send_buffer = (uint8_t*)malloc(msglen); |
| 158 | adb_host->pending_send_buffer_size = msglen; |
| 159 | } else if ((adb_host->pending_send_data_size + msglen) > |
| 160 | adb_host->pending_send_buffer_size) { |
| 161 | adb_host->pending_send_buffer = |
| 162 | (uint8_t*)realloc(adb_host->pending_send_buffer, |
| 163 | adb_host->pending_send_data_size + msglen); |
| 164 | adb_host->pending_send_buffer_size = |
| 165 | adb_host->pending_send_data_size + msglen; |
| 166 | } |
| 167 | |
| 168 | if (adb_host->pending_send_buffer == NULL) { |
| 169 | D("Unable to allocate %d bytes for pending ADB host data.", |
| 170 | adb_host->pending_send_data_size + msglen); |
| 171 | adb_host->pending_send_buffer_size = adb_host->pending_send_data_size = 0; |
| 172 | loopIo_dontWantWrite(adb_host->io); |
| 173 | return; |
| 174 | } |
| 175 | |
| 176 | memcpy(adb_host->pending_send_buffer + adb_host->pending_send_data_size, |
| 177 | msg, msglen); |
| 178 | loopIo_wantWrite(adb_host->io); |
| 179 | } |
| 180 | |
| 181 | /* Connects ADB host with ADB guest. */ |
| 182 | static void |
| 183 | _adb_connect(AdbHost* adb_host, AdbGuest* adb_guest) |
| 184 | { |
| 185 | D("Connecting ADB host %p(so=%d) with ADB guest %p(o=%p)", |
| 186 | adb_host, adb_host->host_so, adb_guest, adb_guest->opaque); |
| 187 | |
| 188 | adb_guest->adb_host = adb_host; |
| 189 | adb_host->adb_guest = adb_guest; |
| 190 | adb_guest->callbacks->on_connected(adb_guest->opaque, adb_guest); |
| 191 | } |
| 192 | |
| 193 | /* Callback invoked when ADB host socket gets disconnected. */ |
| 194 | static void |
| 195 | _on_adb_host_disconnected(AdbHost* adb_host) |
| 196 | { |
| 197 | AdbGuest* const adb_guest = adb_host->adb_guest; |
| 198 | |
| 199 | /* Notify the ADB guest that the host got disconnected. */ |
| 200 | if (adb_guest != NULL) { |
| 201 | D("Disconnecting ADB host %p(so=%d) from ADB guest %p(o=%p)", |
| 202 | adb_host, adb_host->host_so, adb_guest, adb_guest->opaque); |
| 203 | adb_host->adb_guest = NULL; |
| 204 | adb_guest->callbacks->on_disconnect(adb_guest->opaque, adb_guest); |
| 205 | adb_guest->adb_host = NULL; |
| 206 | } else { |
| 207 | D("Disconnecting ADB host %p(so=%d)", adb_host, adb_host->host_so); |
| 208 | } |
| 209 | |
| 210 | /* Destroy the host. */ |
| 211 | alist_remove(&adb_host->list_entry); |
| 212 | _adb_host_free(adb_host); |
| 213 | |
| 214 | /* Remove the guest from the list. */ |
| 215 | if (adb_guest != NULL) { |
| 216 | alist_remove(&adb_guest->list_entry); |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | /* Read I/O callback on ADB host socket. */ |
| 221 | static void |
| 222 | _on_adb_host_read(AdbHost* adb_host) |
| 223 | { |
| 224 | char buff[4096]; |
| 225 | |
| 226 | /* Read data from the socket. */ |
| 227 | const int size = socket_recv(adb_host->host_so, buff, sizeof(buff)); |
| 228 | if (size < 0) { |
| 229 | D("Error while reading from ADB host %p(so=%d). Error: %s", |
| 230 | adb_host, adb_host->host_so, strerror(errno)); |
| 231 | } else if (size == 0) { |
| 232 | /* This is a "disconnect" condition. */ |
| 233 | _on_adb_host_disconnected(adb_host); |
| 234 | } else { |
| 235 | D("%s %d bytes received from ADB host %p(so=%d): %s", |
| 236 | adb_host->adb_guest ? "Transfer" : "Pend", size, adb_host, |
| 237 | adb_host->host_so, QB(buff, size)); |
| 238 | |
| 239 | /* Lets see if there is an ADB guest associated with this host, and it |
| 240 | * is ready to receive host data. */ |
| 241 | AdbGuest* const adb_guest = adb_host->adb_guest; |
| 242 | if (adb_guest != NULL && adb_guest->is_connected) { |
| 243 | /* Channel the data through... */ |
| 244 | adb_guest->callbacks->on_read(adb_guest->opaque, adb_guest, buff, size); |
| 245 | } else { |
| 246 | /* Pend the data for the upcoming guest connection. */ |
| 247 | if (adb_host->pending_data == NULL) { |
| 248 | adb_host->pending_data = malloc(size); |
| 249 | } else { |
| 250 | adb_host->pending_data = realloc(adb_host->pending_data, |
| 251 | adb_host->pending_data_size + size); |
| 252 | } |
| 253 | if (adb_host->pending_data != NULL) { |
| 254 | memcpy(adb_host->pending_data + adb_host->pending_data_size, |
| 255 | buff, size); |
| 256 | adb_host->pending_data_size += size; |
| 257 | } else { |
| 258 | D("Unable to (re)allocate %d bytes for pending ADB host data", |
| 259 | adb_host->pending_data_size + size); |
| 260 | } |
| 261 | } |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | /* Write I/O callback on ADB host socket. */ |
| 266 | static void |
| 267 | _on_adb_host_write(AdbHost* adb_host) |
| 268 | { |
| 269 | while (adb_host->pending_send_data_size && adb_host->pending_send_buffer != NULL) { |
| 270 | const int sent = socket_send(adb_host->host_so, |
| 271 | adb_host->pending_send_buffer, |
| 272 | adb_host->pending_send_data_size); |
| 273 | if (sent < 0) { |
| 274 | if (errno == EWOULDBLOCK) { |
| 275 | /* Try again later. */ |
| 276 | return; |
| 277 | } else { |
| 278 | D("Unable to send pending data to the ADB host: %s", |
| 279 | strerror(errno)); |
| 280 | free(adb_host->pending_send_buffer); |
| 281 | adb_host->pending_send_buffer = NULL; |
| 282 | adb_host->pending_send_buffer_size = 0; |
| 283 | adb_host->pending_send_data_size = 0; |
| 284 | break; |
| 285 | } |
| 286 | } else if (sent == 0) { |
| 287 | /* Disconnect condition. */ |
| 288 | free(adb_host->pending_send_buffer); |
| 289 | adb_host->pending_send_buffer = NULL; |
| 290 | adb_host->pending_send_buffer_size = 0; |
| 291 | adb_host->pending_send_data_size = 0; |
| 292 | _on_adb_host_disconnected(adb_host); |
| 293 | break; |
| 294 | } else if (sent == adb_host->pending_send_data_size) { |
| 295 | free(adb_host->pending_send_buffer); |
| 296 | adb_host->pending_send_buffer = NULL; |
| 297 | adb_host->pending_send_buffer_size = 0; |
| 298 | adb_host->pending_send_data_size = 0; |
| 299 | } else { |
| 300 | adb_host->pending_send_data_size -= sent; |
| 301 | memmove(adb_host->pending_send_buffer, |
| 302 | adb_host->pending_send_buffer + sent, |
| 303 | adb_host->pending_send_data_size); |
| 304 | return; |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | loopIo_dontWantWrite(adb_host->io); |
| 309 | } |
| 310 | |
| 311 | /* I/O callback on ADB host socket. */ |
| 312 | static void |
| 313 | _on_adb_host_io(void* opaque, int fd, unsigned events) |
| 314 | { |
| 315 | AdbHost* const adb_host = (AdbHost*)opaque; |
| 316 | assert(fd == adb_host->host_so); |
| 317 | |
| 318 | /* Dispatch I/O to read / write handlers. */ |
| 319 | if ((events & LOOP_IO_READ) != 0) { |
| 320 | _on_adb_host_read(adb_host); |
| 321 | } |
| 322 | if ((events & LOOP_IO_WRITE) != 0) { |
| 323 | _on_adb_host_write(adb_host); |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | /******************************************************************************** |
| 328 | * ADB guest API |
| 329 | *******************************************************************************/ |
| 330 | |
| 331 | /* Creates and initializes a new AdbGuest instance. */ |
| 332 | static AdbGuest* |
| 333 | _adb_guest_new(AdbServer* adb_srv) |
| 334 | { |
| 335 | AdbGuest* adb_guest; |
| 336 | |
| 337 | ANEW0(adb_guest); |
| 338 | alist_init(&adb_guest->list_entry); |
| 339 | adb_guest->adb_srv = adb_srv; |
| 340 | |
| 341 | return adb_guest; |
| 342 | } |
| 343 | |
| 344 | /* Frees AdbGuest instance created with _adb_guest_new routine. */ |
| 345 | static void |
| 346 | _adb_guest_free(AdbGuest* adb_guest) |
| 347 | { |
| 348 | if (adb_guest != NULL) { |
| 349 | /* At this poin the guest must not be in any of the lists. */ |
| 350 | assert(alist_is_empty(&adb_guest->list_entry)); |
| 351 | AFREE(adb_guest); |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | /******************************************************************************** |
| 356 | * ADB server internals |
| 357 | *******************************************************************************/ |
| 358 | |
| 359 | /* I/O callback on ADB server socket. */ |
| 360 | static void |
| 361 | _on_server_socket_io(void* opaque, int fd, unsigned events) |
| 362 | { |
| 363 | AdbHost* adb_host; |
| 364 | AdbGuest* adb_guest; |
| 365 | AdbServer* adb_srv = (AdbServer*)opaque; |
| 366 | assert(adb_srv->so == fd); |
| 367 | |
| 368 | /* Since this is a server socket, we only expect a connection I/O here. */ |
| 369 | if ((events & LOOP_IO_READ) == 0) { |
| 370 | D("Unexpected write I/O on ADB server socket"); |
| 371 | return; |
| 372 | } |
| 373 | |
| 374 | /* Create AdbHost instance for the new host connection. */ |
| 375 | adb_host = _adb_host_new(adb_srv); |
| 376 | |
| 377 | /* Accept the connection. */ |
| 378 | adb_host->host_so = socket_accept(fd, &adb_srv->socket_address); |
| 379 | if (adb_host->host_so < 0) { |
| 380 | D("Unable to accept ADB connection: %s", strerror(errno)); |
| 381 | _adb_host_free(adb_host); |
| 382 | return; |
| 383 | } |
| 384 | |
| 385 | /* Prepare for I/O on the host connection socket. */ |
| 386 | loopIo_init(adb_host->io, adb_srv->looper, adb_host->host_so, |
| 387 | _on_adb_host_io, adb_host); |
| 388 | |
| 389 | /* Lets see if there is an ADB guest waiting for a host connection. */ |
| 390 | adb_guest = (AdbGuest*)alist_remove_head(&adb_srv->pending_guests); |
| 391 | if (adb_guest != NULL) { |
| 392 | /* Tie up ADB host with the ADB guest. */ |
| 393 | alist_insert_tail(&adb_srv->adb_guests, &adb_guest->list_entry); |
| 394 | alist_insert_tail(&adb_srv->adb_hosts, &adb_host->list_entry); |
| 395 | _adb_connect(adb_host, adb_guest); |
| 396 | } else { |
| 397 | /* Pend this connection. */ |
| 398 | D("Pend ADB host %p(so=%d)", adb_host, adb_host->host_so); |
| 399 | alist_insert_tail(&adb_srv->pending_hosts, &adb_host->list_entry); |
| 400 | } |
| 401 | |
| 402 | /* Enable I/O on the host socket. */ |
| 403 | loopIo_wantRead(adb_host->io); |
| 404 | } |
| 405 | |
| 406 | /******************************************************************************** |
| 407 | * ADB server API |
| 408 | *******************************************************************************/ |
| 409 | int |
| 410 | adb_server_init(int port) |
| 411 | { |
| 412 | if (!_adb_server_initialized) { |
| 413 | /* Initialize the descriptor. */ |
| 414 | memset(&_adb_server, 0, sizeof(_adb_server)); |
| 415 | alist_init(&_adb_server.adb_hosts); |
| 416 | alist_init(&_adb_server.adb_guests); |
| 417 | alist_init(&_adb_server.pending_hosts); |
| 418 | alist_init(&_adb_server.pending_guests); |
| 419 | _adb_server.port = port; |
| 420 | |
| 421 | /* Create looper for an async I/O on the server. */ |
| 422 | _adb_server.looper = looper_newCore(); |
| 423 | if (_adb_server.looper == NULL) { |
| 424 | E("Unable to create I/O looper for ADB server"); |
| 425 | return -1; |
| 426 | } |
| 427 | |
| 428 | /* Create loopback server socket for the ADB port. */ |
| 429 | sock_address_init_inet(&_adb_server.socket_address, |
| 430 | SOCK_ADDRESS_INET_LOOPBACK, port); |
| 431 | _adb_server.so = socket_loopback_server(port, SOCKET_STREAM); |
| 432 | if (_adb_server.so < 0) { |
| 433 | E("Unable to create ADB server socket: %s", strerror(errno)); |
| 434 | return -1; |
| 435 | } |
| 436 | |
| 437 | /* Prepare server socket for I/O */ |
| 438 | socket_set_nonblock(_adb_server.so); |
| 439 | loopIo_init(_adb_server.io, _adb_server.looper, _adb_server.so, |
| 440 | _on_server_socket_io, &_adb_server); |
| 441 | loopIo_wantRead(_adb_server.io); |
| 442 | |
| 443 | D("ADB server has been initialized for port %d. Socket: %d", |
| 444 | port, _adb_server.so); |
| 445 | |
| 446 | _adb_server_initialized = 1; |
| 447 | } |
| 448 | |
| 449 | return 0; |
| 450 | } |
| 451 | |
| 452 | int |
| 453 | adb_server_is_initialized(void) |
| 454 | { |
| 455 | return _adb_server_initialized; |
| 456 | } |
| 457 | |
| 458 | void* |
| 459 | adb_server_register_guest(void* opaque, AdbGuestRoutines* callbacks) |
| 460 | { |
| 461 | if (_adb_server_initialized) { |
| 462 | AdbHost* adb_host; |
| 463 | |
| 464 | /* Create and initialize ADB guest descriptor. */ |
| 465 | AdbGuest* const adb_guest = _adb_guest_new(&_adb_server); |
| 466 | adb_guest->opaque = opaque; |
| 467 | adb_guest->callbacks = callbacks; |
| 468 | |
| 469 | /* Lets see if there is a pending ADB host for the new guest. */ |
| 470 | adb_host = (AdbHost*)alist_remove_head(&_adb_server.pending_hosts); |
| 471 | if (adb_host != NULL) { |
| 472 | /* Tie up ADB host with the ADB guest. */ |
| 473 | alist_insert_tail(&_adb_server.adb_guests, &adb_guest->list_entry); |
| 474 | alist_insert_tail(&_adb_server.adb_hosts, &adb_host->list_entry); |
| 475 | _adb_connect(adb_host, adb_guest); |
| 476 | } else { |
| 477 | /* Host is not available. Pend this guest. */ |
| 478 | D("Pend ADB guest %p(o=%p)", adb_guest, adb_guest->opaque); |
| 479 | alist_insert_tail(&_adb_server.pending_guests, &adb_guest->list_entry); |
| 480 | } |
| 481 | |
| 482 | return adb_guest; |
| 483 | } else { |
| 484 | D("%s is called on an uninitialized ADB server.", __FUNCTION__); |
| 485 | return NULL; |
| 486 | } |
| 487 | } |
| 488 | |
| 489 | void |
| 490 | adb_server_complete_connection(void* opaque) |
| 491 | { |
| 492 | AdbGuest* const adb_guest = (AdbGuest*)opaque; |
| 493 | AdbHost* const adb_host = adb_guest->adb_host; |
| 494 | |
| 495 | /* Mark the guest as fully connected and ready for the host data. */ |
| 496 | adb_guest->is_connected = 1; |
| 497 | |
| 498 | /* Lets see if there is a host data pending transmission to the guest. */ |
| 499 | if (adb_host->pending_data != NULL && adb_host->pending_data_size != 0) { |
| 500 | /* Send the pending data to the guest. */ |
| 501 | D("Pushing %d bytes of the pending ADB host data.", |
| 502 | adb_host->pending_data_size); |
| 503 | adb_guest->callbacks->on_read(adb_guest->opaque, adb_guest, |
| 504 | adb_host->pending_data, |
| 505 | adb_host->pending_data_size); |
| 506 | free(adb_host->pending_data); |
| 507 | adb_host->pending_data = NULL; |
| 508 | adb_host->pending_data_size = 0; |
| 509 | } |
| 510 | } |
| 511 | |
| 512 | void |
| 513 | adb_server_on_guest_message(void* opaque, const uint8_t* msg, int msglen) |
| 514 | { |
| 515 | AdbGuest* const adb_guest = (AdbGuest*)opaque; |
| 516 | AdbHost* const adb_host = adb_guest->adb_host; |
| 517 | |
| 518 | if (adb_host != NULL) { |
| 519 | D("Sending %d bytes to the ADB host: %s", msglen, QB(msg, msglen)); |
| 520 | |
| 521 | /* Lets see if we can send the data immediatelly... */ |
| 522 | if (adb_host->pending_send_buffer == NULL) { |
| 523 | /* There are no data that are pending to be sent to the host. Do the |
| 524 | * direct send. */ |
| 525 | const int sent = socket_send(adb_host->host_so, msg, msglen); |
| 526 | if (sent < 0) { |
| 527 | if (errno == EWOULDBLOCK) { |
| 528 | } else { |
| 529 | D("Unable to send data to ADB host: %s", strerror(errno)); |
| 530 | } |
| 531 | } else if (sent == 0) { |
| 532 | /* Disconnect condition. */ |
| 533 | _on_adb_host_disconnected(adb_host); |
| 534 | } else if (sent < msglen) { |
| 535 | /* Couldn't send everything. Schedule write via I/O callback. */ |
| 536 | _adb_host_append_message(adb_host, msg + sent, msglen - sent); |
| 537 | } |
| 538 | } else { |
| 539 | /* There are data that are pending to be sent to the host. We need |
| 540 | * to append new data to the end of the pending data buffer. */ |
| 541 | _adb_host_append_message(adb_host, msg, msglen); |
| 542 | } |
| 543 | } else { |
| 544 | D("ADB host is disconneted and can't accept %d bytes in %s", |
| 545 | msglen, QB(msg, msglen)); |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | void |
| 550 | adb_server_on_guest_closed(void* opaque) |
| 551 | { |
| 552 | AdbGuest* const adb_guest = (AdbGuest*)opaque; |
| 553 | AdbHost* const adb_host = adb_guest->adb_host; |
| 554 | |
| 555 | /* Remove the guest from the list */ |
| 556 | if (!alist_is_empty(&adb_guest->list_entry)) { |
| 557 | alist_remove(&adb_guest->list_entry); |
| 558 | } |
| 559 | |
| 560 | /* Disassociate the host. */ |
| 561 | if (adb_host != NULL) { |
| 562 | if (!alist_is_empty(&adb_host->list_entry)) { |
| 563 | alist_remove(&adb_host->list_entry); |
| 564 | } |
| 565 | _adb_host_free(adb_host); |
| 566 | } |
| 567 | _adb_guest_free(adb_guest); |
| 568 | } |