1 /* 2 * Copyright (C) 2012 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 "android/async-socket.h" 26 #include "android/sdk-controller-socket.h" 27 #include "utils/panic.h" 28 #include "iolooper.h" 29 30 #define E(...) derror(__VA_ARGS__) 31 #define W(...) dwarning(__VA_ARGS__) 32 #define D(...) VERBOSE_PRINT(sdkctlsocket,__VA_ARGS__) 33 #define D_ACTIVE VERBOSE_CHECK(sdkctlsocket) 34 35 #define TRACE_ON 0 36 37 #if TRACE_ON 38 #define T(...) VERBOSE_PRINT(sdkctlsocket,__VA_ARGS__) 39 #else 40 #define T(...) 41 #endif 42 43 /* Recycling memory descriptor. */ 44 typedef struct SDKCtlRecycled SDKCtlRecycled; 45 struct SDKCtlRecycled { 46 union { 47 /* Next recycled descriptor (while listed in recycler). */ 48 SDKCtlRecycled* next; 49 /* Allocated memory size (while outside of the recycler). */ 50 uint32_t size; 51 }; 52 }; 53 54 /* 55 * Types of the data packets sent via SDK controller socket. 56 */ 57 58 /* The packet is a message. */ 59 #define SDKCTL_PACKET_MESSAGE 1 60 /* The packet is a query. */ 61 #define SDKCTL_PACKET_QUERY 2 62 /* The packet is a response to a query. */ 63 #define SDKCTL_PACKET_QUERY_RESPONSE 3 64 65 /* 66 * Types of intenal port messages sent via SDK controller socket. 67 */ 68 69 /* Port is connected. 70 * This message is sent by SDK controller when the service connects a socket with 71 * a port that provides requested emulation functionality. 72 */ 73 #define SDKCTL_MSG_PORT_CONNECTED -1 74 /* Port is disconnected. 75 * This message is sent by SDK controller when a port that provides requested 76 * emulation functionality disconnects from the socket. 77 */ 78 #define SDKCTL_MSG_PORT_DISCONNECTED -2 79 /* Port is enabled. 80 * This message is sent by SDK controller when a port that provides requested 81 * emulation functionality is ready to do the emulation. 82 */ 83 #define SDKCTL_MSG_PORT_ENABLED -3 84 /* Port is disabled. 85 * This message is sent by SDK controller when a port that provides requested 86 * emulation functionality is not ready to do the emulation. 87 */ 88 #define SDKCTL_MSG_PORT_DISABLED -4 89 90 /* 91 * Types of internal queries sent via SDK controller socket. 92 */ 93 94 /* Handshake query. 95 * This query is sent to SDK controller service as part of the connection 96 * protocol implementation. 97 */ 98 #define SDKCTL_QUERY_HANDSHAKE -1 99 100 /******************************************************************************** 101 * SDKCtlPacket declarations 102 *******************************************************************************/ 103 104 /* Packet signature value ('SDKC'). */ 105 static const int _sdkctl_packet_sig = 0x53444B43; 106 107 /* Data packet descriptor. 108 * 109 * All packets, sent and received via SDK controller socket begin with this 110 * header, with packet data immediately following this header. 111 */ 112 typedef struct SDKCtlPacketHeader { 113 /* Signature. */ 114 int signature; 115 /* Total size of the data to transfer with this packet, including this 116 * header. The transferring data should immediatelly follow this header. */ 117 int size; 118 /* Encodes packet type. See SDKCTL_PACKET_XXX for the list of packet types 119 * used by SDK controller. */ 120 int type; 121 } SDKCtlPacketHeader; 122 123 /* Packet descriptor, allocated by this API for data packets to be sent to SDK 124 * controller. 125 * 126 * When packet descriptors are allocated by this API, they are allocated large 127 * enough to contain this header, and packet data to send to the service, 128 * immediately following this descriptor. 129 */ 130 typedef struct SDKCtlPacket { 131 /* Supports recycling. Don't put anything in front: recycler expects this 132 * to be the first field in recyclable descriptor. */ 133 SDKCtlRecycled recycling; 134 135 /* SDK controller socket that transmits this packet. */ 136 SDKCtlSocket* sdkctl; 137 /* Number of outstanding references to the packet. */ 138 int ref_count; 139 140 /* Common packet header. Packet data immediately follows this header, so it 141 * must be the last field in SDKCtlPacket descriptor. */ 142 SDKCtlPacketHeader header; 143 } SDKCtlPacket; 144 145 /******************************************************************************** 146 * SDKCtlDirectPacket declarations 147 *******************************************************************************/ 148 149 /* Direct packet descriptor, allocated by this API for direct data packets to be 150 * sent to SDK controller service on the device. 151 * 152 * Direct packet (unlike SDKCtlPacket) don't contain data buffer, but rather 153 * reference data allocated by the client. This is useful when client sends large 154 * amount of data (such as framebuffer updates sent my multi-touch port), and 155 * regular packet descriptors for such large transfer cannot be obtained from the 156 * recycler. 157 */ 158 struct SDKCtlDirectPacket { 159 /* Supports recycling. Don't put anything in front: recycler expects this 160 * to be the first field in recyclable descriptor. */ 161 SDKCtlRecycled recycling; 162 163 /* SDKCtlSocket that owns this packet. */ 164 SDKCtlSocket* sdkctl; 165 /* Packet to send. */ 166 SDKCtlPacketHeader* packet; 167 /* Callback to invoke on packet transmission events. */ 168 on_sdkctl_direct_cb on_sent; 169 /* An opaque pointer to pass to on_sent callback. */ 170 void* on_sent_opaque; 171 /* Number of outstanding references to the packet. */ 172 int ref_count; 173 }; 174 175 /******************************************************************************** 176 * SDKCtlQuery declarations 177 *******************************************************************************/ 178 179 /* Query packet descriptor. 180 * 181 * All queries, sent and received via SDK controller socket begin with this 182 * header, with query data immediately following this header. 183 */ 184 typedef struct SDKCtlQueryHeader { 185 /* Data packet header for this query. */ 186 SDKCtlPacketHeader packet; 187 /* A unique query identifier. This ID is used to track the query in the 188 * asynchronous environment in whcih SDK controller socket operates. */ 189 int query_id; 190 /* Query type. */ 191 int query_type; 192 } SDKCtlQueryHeader; 193 194 /* Query descriptor, allocated by this API for queries to be sent to SDK 195 * controller service on the device. 196 * 197 * When query descriptors are allocated by this API, they are allocated large 198 * enough to contain this header, and query data to send to the service, 199 * immediately following this descriptor. 200 */ 201 struct SDKCtlQuery { 202 /* Supports recycling. Don't put anything in front: recycler expects this 203 * to be the first field in recyclable descriptor. */ 204 SDKCtlRecycled recycling; 205 206 /* Next query in the list of active queries. */ 207 SDKCtlQuery* next; 208 /* A timer to run time out on this query after it has been sent. */ 209 LoopTimer timer[1]; 210 /* Absolute time for this query's deadline. This is the value that query's 211 * timer is set to after query has been transmitted to the service. */ 212 Duration deadline; 213 /* SDK controller socket that owns the query. */ 214 SDKCtlSocket* sdkctl; 215 /* A callback to invoke on query state changes. */ 216 on_sdkctl_query_cb query_cb; 217 /* An opaque pointer associated with this query. */ 218 void* query_opaque; 219 /* Points to an address of a buffer where to save query response. */ 220 void** response_buffer; 221 /* Points to a variable containing size of the response buffer (on the way 222 * in), or actual query response size (when query is completed). */ 223 uint32_t* response_size; 224 /* Internal response buffer, allocated if query creator didn't provide its 225 * own. This field is valid only if response_buffer field is NULL, or is 226 * pointing to this field. */ 227 void* internal_resp_buffer; 228 /* Internal response buffer size used if query creator didn't provide its 229 * own. This field is valid only if response_size field is NULL, or is 230 * pointing to this field. */ 231 uint32_t internal_resp_size; 232 /* Number of outstanding references to the query. */ 233 int ref_count; 234 235 /* Common query header. Query data immediately follows this header, so it 236 * must be last field in SDKCtlQuery descriptor. */ 237 SDKCtlQueryHeader header; 238 }; 239 240 /* Query reply descriptor. 241 * 242 * All replies to a query, sent and received via SDK controller socket begin with 243 * this header, with query reply data immediately following this header. 244 */ 245 typedef struct SDKCtlQueryReplyHeader { 246 /* Data packet header for this reply. */ 247 SDKCtlPacketHeader packet; 248 249 /* An identifier for the query that is addressed with this reply. */ 250 int query_id; 251 } SDKCtlQueryReplyHeader; 252 253 /******************************************************************************** 254 * SDKCtlMessage declarations 255 *******************************************************************************/ 256 257 /* Message packet descriptor. 258 * 259 * All messages, sent and received via SDK controller socket begin with this 260 * header, with message data immediately following this header. 261 */ 262 typedef struct SDKCtlMessageHeader { 263 /* Data packet header for this query. */ 264 SDKCtlPacketHeader packet; 265 /* Message type. */ 266 int msg_type; 267 } SDKCtlMessageHeader; 268 269 /* Message packet descriptor. 270 * 271 * All messages, sent and received via SDK controller socket begin with this 272 * header, with message data immediately following this header. 273 */ 274 struct SDKCtlMessage { 275 /* Data packet descriptor for this message. */ 276 SDKCtlPacket packet; 277 /* Message type. */ 278 int msg_type; 279 }; 280 281 /******************************************************************************** 282 * SDK Control Socket declarations 283 *******************************************************************************/ 284 285 /* Enumerates SDKCtlSocket states. */ 286 typedef enum SDKCtlSocketState { 287 /* Socket is disconnected from SDK controller. */ 288 SDKCTL_SOCKET_DISCONNECTED, 289 /* Connection to SDK controller is in progress. */ 290 SDKCTL_SOCKET_CONNECTING, 291 /* Socket is connected to an SDK controller service. */ 292 SDKCTL_SOCKET_CONNECTED 293 } SDKCtlSocketState; 294 295 /* Enumerates SDKCtlSocket I/O dispatcher states. */ 296 typedef enum SDKCtlIODispatcherState { 297 /* I/O dispatcher expects a packet header. */ 298 SDKCTL_IODISP_EXPECT_HEADER, 299 /* I/O dispatcher expects packet data. */ 300 SDKCTL_IODISP_EXPECT_DATA, 301 /* I/O dispatcher expects query response header. */ 302 SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER, 303 /* I/O dispatcher expects query response data. */ 304 SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA, 305 } SDKCtlIODispatcherState; 306 307 /* SDKCtlSocket I/O dispatcher descriptor. */ 308 typedef struct SDKCtlIODispatcher { 309 /* SDKCtlSocket instance for this dispatcher. */ 310 SDKCtlSocket* sdkctl; 311 /* Dispatcher state. */ 312 SDKCtlIODispatcherState state; 313 /* Unites all types of headers used in SDK controller data exchange. */ 314 union { 315 /* Common packet header. */ 316 SDKCtlPacketHeader packet_header; 317 /* Header for a query packet. */ 318 SDKCtlQueryHeader query_header; 319 /* Header for a message packet. */ 320 SDKCtlMessageHeader message_header; 321 /* Header for a query response packet. */ 322 SDKCtlQueryReplyHeader query_reply_header; 323 }; 324 /* Descriptor of a packet that is being received from SDK controller. */ 325 SDKCtlPacket* packet; 326 /* A query for which a reply is currently being received. */ 327 SDKCtlQuery* current_query; 328 } SDKCtlIODispatcher; 329 330 /* SDK controller socket descriptor. */ 331 struct SDKCtlSocket { 332 /* SDK controller socket state */ 333 SDKCtlSocketState state; 334 /* SDK controller port status */ 335 SdkCtlPortStatus port_status; 336 /* I/O dispatcher for the socket. */ 337 SDKCtlIODispatcher io_dispatcher; 338 /* Asynchronous socket connected to SDK Controller on the device. */ 339 AsyncSocket* as; 340 /* Client callback that monitors this socket connection. */ 341 on_sdkctl_socket_connection_cb on_socket_connection; 342 /* Client callback that monitors SDK controller prt connection. */ 343 on_sdkctl_port_connection_cb on_port_connection; 344 /* A callback to invoke when a message is received from the SDK controller. */ 345 on_sdkctl_message_cb on_message; 346 /* An opaque pointer associated with this socket. */ 347 void* opaque; 348 /* Name of an SDK controller port this socket is connected to. */ 349 char* service_name; 350 /* I/O looper for timers. */ 351 Looper* looper; 352 /* Head of the active query list. */ 353 SDKCtlQuery* query_head; 354 /* Tail of the active query list. */ 355 SDKCtlQuery* query_tail; 356 /* Query ID generator that gets incremented for each new query. */ 357 int next_query_id; 358 /* Timeout before trying to reconnect after disconnection. */ 359 int reconnect_to; 360 /* Number of outstanding references to this descriptor. */ 361 int ref_count; 362 /* Head of the recycled memory */ 363 SDKCtlRecycled* recycler; 364 /* Recyclable block size. */ 365 uint32_t recycler_block_size; 366 /* Maximum number of blocks to recycle. */ 367 int recycler_max; 368 /* Number of blocs in the recycler. */ 369 int recycler_count; 370 }; 371 372 /******************************************************************************** 373 * SDKCtlSocket recycling management 374 *******************************************************************************/ 375 376 /* Gets a recycled block for a given SDKCtlSocket, or allocates new memory 377 * block. */ 378 static void* 379 _sdkctl_socket_alloc_recycler(SDKCtlSocket* sdkctl, uint32_t size) 380 { 381 SDKCtlRecycled* block = NULL; 382 383 if (sdkctl->recycler != NULL && size <= sdkctl->recycler_block_size) { 384 assert(sdkctl->recycler_count > 0); 385 /* There are blocks in the recycler, and requested size fits. */ 386 block = sdkctl->recycler; 387 sdkctl->recycler = block->next; 388 block->size = sdkctl->recycler_block_size; 389 sdkctl->recycler_count--; 390 } else if (size <= sdkctl->recycler_block_size) { 391 /* There are no blocks in the recycler, but requested size fits. Lets 392 * allocate block that we can later recycle. */ 393 block = malloc(sdkctl->recycler_block_size); 394 if (block == NULL) { 395 APANIC("SDKCtl %s: Unable to allocate %d bytes block.", 396 sdkctl->service_name, sdkctl->recycler_block_size); 397 } 398 block->size = sdkctl->recycler_block_size; 399 } else { 400 /* Requested size doesn't fit the recycler. */ 401 block = malloc(size); 402 if (block == NULL) { 403 APANIC("SDKCtl %s: Unable to allocate %d bytes block", 404 sdkctl->service_name, size); 405 } 406 block->size = size; 407 } 408 409 return block; 410 } 411 412 /* Recycles, or frees a block of memory for a given SDKCtlSocket. */ 413 static void 414 _sdkctl_socket_free_recycler(SDKCtlSocket* sdkctl, void* mem) 415 { 416 SDKCtlRecycled* const block = (SDKCtlRecycled*)mem; 417 418 if (block->size != sdkctl->recycler_block_size || 419 sdkctl->recycler_count == sdkctl->recycler_max) { 420 /* Recycler is full, or block cannot be recycled. Just free the memory. */ 421 free(mem); 422 } else { 423 /* Add that block to the recycler. */ 424 assert(sdkctl->recycler_count >= 0); 425 block->next = sdkctl->recycler; 426 sdkctl->recycler = block; 427 sdkctl->recycler_count++; 428 } 429 } 430 431 /* Empties the recycler for a given SDKCtlSocket. */ 432 static void 433 _sdkctl_socket_empty_recycler(SDKCtlSocket* sdkctl) 434 { 435 SDKCtlRecycled* block = sdkctl->recycler; 436 while (block != NULL) { 437 void* const to_free = block; 438 block = block->next; 439 free(to_free); 440 } 441 sdkctl->recycler = NULL; 442 sdkctl->recycler_count = 0; 443 } 444 445 /******************************************************************************** 446 * SDKCtlSocket query list management 447 *******************************************************************************/ 448 449 /* Adds a query to the list of active queries. 450 * Param: 451 * sdkctl - SDKCtlSocket instance for the query. 452 * query - Query to add to the list. 453 */ 454 static void 455 _sdkctl_socket_add_query(SDKCtlQuery* query) 456 { 457 SDKCtlSocket* const sdkctl = query->sdkctl; 458 if (sdkctl->query_head == NULL) { 459 assert(sdkctl->query_tail == NULL); 460 sdkctl->query_head = sdkctl->query_tail = query; 461 } else { 462 sdkctl->query_tail->next = query; 463 sdkctl->query_tail = query; 464 } 465 466 /* Keep the query referenced while it's in the list. */ 467 sdkctl_query_reference(query); 468 } 469 470 /* Removes a query from the list of active queries. 471 * Param: 472 * query - Query to remove from the list of active queries. If query has been 473 * removed from the list, it will be dereferenced to offset the reference 474 * that wad made when the query has been added to the list. 475 * Return: 476 * Boolean: 1 if query has been removed, or 0 if query has not been found in the 477 * list of active queries. 478 */ 479 static int 480 _sdkctl_socket_remove_query(SDKCtlQuery* query) 481 { 482 SDKCtlSocket* const sdkctl = query->sdkctl; 483 SDKCtlQuery* prev = NULL; 484 SDKCtlQuery* head = sdkctl->query_head; 485 486 /* Quick check: the query could be currently handled by the dispatcher. */ 487 if (sdkctl->io_dispatcher.current_query == query) { 488 /* Release the query from dispatcher. */ 489 sdkctl->io_dispatcher.current_query = NULL; 490 sdkctl_query_release(query); 491 return 1; 492 } 493 494 /* Remove query from the list. */ 495 while (head != NULL && query != head) { 496 prev = head; 497 head = head->next; 498 } 499 if (head == NULL) { 500 D("SDKCtl %s: Query %p is not found in the list.", 501 sdkctl->service_name, query); 502 return 0; 503 } 504 505 if (prev == NULL) { 506 /* Query is at the head of the list. */ 507 assert(query == sdkctl->query_head); 508 sdkctl->query_head = query->next; 509 } else { 510 /* Query is in the middle / at the end of the list. */ 511 assert(query != sdkctl->query_head); 512 prev->next = query->next; 513 } 514 if (sdkctl->query_tail == query) { 515 /* Query is at the tail of the list. */ 516 assert(query->next == NULL); 517 sdkctl->query_tail = prev; 518 } 519 query->next = NULL; 520 521 /* Release query that is now removed from the list. Note that query 522 * passed to this routine should hold an extra reference, owned by the 523 * caller. */ 524 sdkctl_query_release(query); 525 526 return 1; 527 } 528 529 /* Removes a query (based on query ID) from the list of active queries. 530 * Param: 531 * sdkctl - SDKCtlSocket instance that owns the query. 532 * query_id - Identifies the query to remove. 533 * Return: 534 * A query removed from the list of active queries, or NULL if query with the 535 * given ID has not been found in the list. Note that query returned from this 536 * routine still holds the reference made when the query has been added to the 537 * list. 538 */ 539 static SDKCtlQuery* 540 _sdkctl_socket_remove_query_id(SDKCtlSocket* sdkctl, int query_id) 541 { 542 SDKCtlQuery* query = NULL; 543 SDKCtlQuery* prev = NULL; 544 SDKCtlQuery* head = sdkctl->query_head; 545 546 /* Quick check: the query could be currently handled by dispatcher. */ 547 if (sdkctl->io_dispatcher.current_query != NULL && 548 sdkctl->io_dispatcher.current_query->header.query_id == query_id) { 549 /* Release the query from dispatcher. */ 550 query = sdkctl->io_dispatcher.current_query; 551 sdkctl->io_dispatcher.current_query = NULL; 552 return query; 553 } 554 555 /* Remove query from the list. */ 556 while (head != NULL && head->header.query_id != query_id) { 557 prev = head; 558 head = head->next; 559 } 560 if (head == NULL) { 561 D("SDKCtl %s: Query ID %d is not found in the list.", 562 sdkctl->service_name, query_id); 563 return NULL; 564 } 565 566 /* Query is found in the list. */ 567 query = head; 568 if (prev == NULL) { 569 /* Query is at the head of the list. */ 570 assert(query == sdkctl->query_head); 571 sdkctl->query_head = query->next; 572 } else { 573 /* Query is in the middle, or at the end of the list. */ 574 assert(query != sdkctl->query_head); 575 prev->next = query->next; 576 } 577 if (sdkctl->query_tail == query) { 578 /* Query is at the tail of the list. */ 579 assert(query->next == NULL); 580 sdkctl->query_tail = prev; 581 } 582 query->next = NULL; 583 584 return query; 585 } 586 587 /* Pulls the first query from the list of active queries. 588 * Param: 589 * sdkctl - SDKCtlSocket instance that owns the query. 590 * Return: 591 * A query removed from the head of the list of active queries, or NULL if query 592 * list is empty. 593 */ 594 static SDKCtlQuery* 595 _sdkctl_socket_pull_first_query(SDKCtlSocket* sdkctl) 596 { 597 SDKCtlQuery* const query = sdkctl->query_head; 598 599 if (query != NULL) { 600 sdkctl->query_head = query->next; 601 if (sdkctl->query_head == NULL) { 602 sdkctl->query_tail = NULL; 603 } 604 } 605 return query; 606 } 607 608 /* Generates new query ID for the given SDKCtl. */ 609 static int 610 _sdkctl_socket_next_query_id(SDKCtlSocket* sdkctl) 611 { 612 return ++sdkctl->next_query_id; 613 } 614 615 /******************************************************************************** 616 * SDKCtlPacket implementation 617 *******************************************************************************/ 618 619 /* Alocates a packet. */ 620 static SDKCtlPacket* 621 _sdkctl_packet_new(SDKCtlSocket* sdkctl, uint32_t size, int type) 622 { 623 /* Allocate packet descriptor large enough to contain packet data. */ 624 SDKCtlPacket* const packet = 625 _sdkctl_socket_alloc_recycler(sdkctl, sizeof(SDKCtlPacket) + size); 626 627 packet->sdkctl = sdkctl; 628 packet->ref_count = 1; 629 packet->header.signature = _sdkctl_packet_sig; 630 packet->header.size = size; 631 packet->header.type = type; 632 633 /* Refence SDKCTlSocket that owns this packet. */ 634 sdkctl_socket_reference(sdkctl); 635 636 T("SDKCtl %s: Packet %p of type %d is allocated for %d bytes transfer.", 637 sdkctl->service_name, packet, type, size); 638 639 return packet; 640 } 641 642 /* Frees a packet. */ 643 static void 644 _sdkctl_packet_free(SDKCtlPacket* packet) 645 { 646 SDKCtlSocket* const sdkctl = packet->sdkctl; 647 648 /* Recycle packet. */ 649 _sdkctl_socket_free_recycler(packet->sdkctl, packet); 650 651 T("SDKCtl %s: Packet %p is freed.", sdkctl->service_name, packet); 652 653 /* Release SDKCTlSocket that owned this packet. */ 654 sdkctl_socket_release(sdkctl); 655 } 656 657 /* References a packet. */ 658 int 659 _sdkctl_packet_reference(SDKCtlPacket* packet) 660 { 661 assert(packet->ref_count > 0); 662 packet->ref_count++; 663 return packet->ref_count; 664 } 665 666 /* Releases a packet. */ 667 int 668 _sdkctl_packet_release(SDKCtlPacket* packet) 669 { 670 assert(packet->ref_count > 0); 671 packet->ref_count--; 672 if (packet->ref_count == 0) { 673 /* Last reference has been dropped. Destroy this object. */ 674 _sdkctl_packet_free(packet); 675 return 0; 676 } 677 return packet->ref_count; 678 } 679 680 /* An I/O callback invoked on packet transmission. 681 * Param: 682 * io_opaque SDKCtlPacket instance of the packet that's being sent with this I/O. 683 * asio - Write I/O descriptor. 684 * status - I/O status. 685 */ 686 static AsyncIOAction 687 _on_sdkctl_packet_send_io(void* io_opaque, 688 AsyncSocketIO* asio, 689 AsyncIOState status) 690 { 691 SDKCtlPacket* const packet = (SDKCtlPacket*)io_opaque; 692 AsyncIOAction action = ASIO_ACTION_DONE; 693 694 /* Reference the packet while we're in this callback. */ 695 _sdkctl_packet_reference(packet); 696 697 /* Lets see what's going on with query transmission. */ 698 switch (status) { 699 case ASIO_STATE_SUCCEEDED: 700 /* Packet has been sent to the service. */ 701 T("SDKCtl %s: Packet %p transmission has succeeded.", 702 packet->sdkctl->service_name, packet); 703 break; 704 705 case ASIO_STATE_CANCELLED: 706 T("SDKCtl %s: Packet %p is cancelled.", 707 packet->sdkctl->service_name, packet); 708 break; 709 710 case ASIO_STATE_FAILED: 711 T("SDKCtl %s: Packet %p has failed: %d -> %s", 712 packet->sdkctl->service_name, packet, errno, strerror(errno)); 713 break; 714 715 case ASIO_STATE_FINISHED: 716 /* Time to disassociate the packet with the I/O. */ 717 _sdkctl_packet_release(packet); 718 break; 719 720 default: 721 /* Transitional state. */ 722 break; 723 } 724 725 _sdkctl_packet_release(packet); 726 727 return action; 728 } 729 730 /* Transmits a packet to SDK Controller. 731 * Param: 732 * packet - Packet to transmit. 733 */ 734 static void 735 _sdkctl_packet_transmit(SDKCtlPacket* packet) 736 { 737 assert(packet->header.signature == _sdkctl_packet_sig); 738 739 /* Reference to associate with the I/O */ 740 _sdkctl_packet_reference(packet); 741 742 /* Transmit the packet to SDK controller. */ 743 async_socket_write_rel(packet->sdkctl->as, &packet->header, packet->header.size, 744 _on_sdkctl_packet_send_io, packet, -1); 745 746 T("SDKCtl %s: Packet %p size %d is being sent.", 747 packet->sdkctl->service_name, packet, packet->header.size); 748 } 749 750 /******************************************************************************** 751 * SDKCtlDirectPacket implementation 752 ********************************************************************************/ 753 754 SDKCtlDirectPacket* 755 sdkctl_direct_packet_new(SDKCtlSocket* sdkctl) 756 { 757 SDKCtlDirectPacket* const packet = 758 _sdkctl_socket_alloc_recycler(sdkctl, sizeof(SDKCtlDirectPacket)); 759 760 packet->sdkctl = sdkctl; 761 packet->ref_count = 1; 762 763 /* Refence SDKCTlSocket that owns this packet. */ 764 sdkctl_socket_reference(packet->sdkctl); 765 766 T("SDKCtl %s: Direct packet %p is allocated.", sdkctl->service_name, packet); 767 768 return packet; 769 } 770 771 /* Frees a direct packet. */ 772 static void 773 _sdkctl_direct_packet_free(SDKCtlDirectPacket* packet) 774 { 775 SDKCtlSocket* const sdkctl = packet->sdkctl; 776 777 /* Free allocated resources. */ 778 _sdkctl_socket_free_recycler(packet->sdkctl, packet); 779 780 T("SDKCtl %s: Direct packet %p is freed.", sdkctl->service_name, packet); 781 782 /* Release SDKCTlSocket that owned this packet. */ 783 sdkctl_socket_release(sdkctl); 784 } 785 786 /* References a packet. */ 787 int 788 sdkctl_direct_packet_reference(SDKCtlDirectPacket* packet) 789 { 790 assert(packet->ref_count > 0); 791 packet->ref_count++; 792 return packet->ref_count; 793 } 794 795 /* Releases a packet. */ 796 int 797 sdkctl_direct_packet_release(SDKCtlDirectPacket* packet) 798 { 799 assert(packet->ref_count > 0); 800 packet->ref_count--; 801 if (packet->ref_count == 0) { 802 /* Last reference has been dropped. Destroy this object. */ 803 _sdkctl_direct_packet_free(packet); 804 return 0; 805 } 806 return packet->ref_count; 807 } 808 809 /* An I/O callback invoked on direct packet transmission. 810 * Param: 811 * io_opaque SDKCtlDirectPacket instance of the packet that's being sent with 812 * this I/O. 813 * asio - Write I/O descriptor. 814 * status - I/O status. 815 */ 816 static AsyncIOAction 817 _on_sdkctl_direct_packet_send_io(void* io_opaque, 818 AsyncSocketIO* asio, 819 AsyncIOState status) 820 { 821 SDKCtlDirectPacket* const packet = (SDKCtlDirectPacket*)io_opaque; 822 AsyncIOAction action = ASIO_ACTION_DONE; 823 824 /* Reference the packet while we're in this callback. */ 825 sdkctl_direct_packet_reference(packet); 826 827 /* Lets see what's going on with query transmission. */ 828 switch (status) { 829 case ASIO_STATE_SUCCEEDED: 830 /* Packet has been sent to the service. */ 831 T("SDKCtl %s: Direct packet %p transmission has succeeded.", 832 packet->sdkctl->service_name, packet); 833 packet->on_sent(packet->on_sent_opaque, packet, status); 834 break; 835 836 case ASIO_STATE_CANCELLED: 837 T("SDKCtl %s: Direct packet %p is cancelled.", 838 packet->sdkctl->service_name, packet); 839 packet->on_sent(packet->on_sent_opaque, packet, status); 840 break; 841 842 case ASIO_STATE_FAILED: 843 T("SDKCtl %s: Direct packet %p has failed: %d -> %s", 844 packet->sdkctl->service_name, packet, errno, strerror(errno)); 845 packet->on_sent(packet->on_sent_opaque, packet, status); 846 break; 847 848 case ASIO_STATE_FINISHED: 849 /* Time to disassociate with the I/O. */ 850 sdkctl_direct_packet_release(packet); 851 break; 852 853 default: 854 /* Transitional state. */ 855 break; 856 } 857 858 sdkctl_direct_packet_release(packet); 859 860 return action; 861 } 862 863 void 864 sdkctl_direct_packet_send(SDKCtlDirectPacket* packet, 865 void* data, 866 on_sdkctl_direct_cb cb, 867 void* cb_opaque) 868 { 869 packet->packet = (SDKCtlPacketHeader*)data; 870 packet->on_sent = cb; 871 packet->on_sent_opaque = cb_opaque; 872 assert(packet->packet->signature == _sdkctl_packet_sig); 873 874 /* Reference for I/O */ 875 sdkctl_direct_packet_reference(packet); 876 877 /* Transmit the packet to SDK controller. */ 878 async_socket_write_rel(packet->sdkctl->as, packet->packet, packet->packet->size, 879 _on_sdkctl_direct_packet_send_io, packet, -1); 880 881 T("SDKCtl %s: Direct packet %p size %d is being sent", 882 packet->sdkctl->service_name, packet, packet->packet->size); 883 } 884 885 /******************************************************************************** 886 * SDKCtlMessage implementation 887 *******************************************************************************/ 888 889 /* Alocates a message descriptor. */ 890 static SDKCtlMessage* 891 _sdkctl_message_new(SDKCtlSocket* sdkctl, uint32_t msg_size, int msg_type) 892 { 893 SDKCtlMessage* const msg = 894 (SDKCtlMessage*)_sdkctl_packet_new(sdkctl, 895 sizeof(SDKCtlMessageHeader) + msg_size, 896 SDKCTL_PACKET_MESSAGE); 897 msg->msg_type = msg_type; 898 899 return msg; 900 } 901 902 int 903 sdkctl_message_reference(SDKCtlMessage* msg) 904 { 905 return _sdkctl_packet_reference(&msg->packet); 906 } 907 908 int 909 sdkctl_message_release(SDKCtlMessage* msg) 910 { 911 return _sdkctl_packet_release(&msg->packet); 912 } 913 914 SDKCtlMessage* 915 sdkctl_message_send(SDKCtlSocket* sdkctl, 916 int msg_type, 917 const void* data, 918 uint32_t size) 919 { 920 SDKCtlMessage* const msg = _sdkctl_message_new(sdkctl, size, msg_type); 921 if (size != 0 && data != NULL) { 922 memcpy(msg + 1, data, size); 923 } 924 _sdkctl_packet_transmit(&msg->packet); 925 926 return msg; 927 } 928 929 int 930 sdkctl_message_get_header_size(void) 931 { 932 return sizeof(SDKCtlMessageHeader); 933 } 934 935 void 936 sdkctl_init_message_header(void* msg, int msg_type, int msg_size) 937 { 938 SDKCtlMessageHeader* const msg_header = (SDKCtlMessageHeader*)msg; 939 940 msg_header->packet.signature = _sdkctl_packet_sig; 941 msg_header->packet.size = sizeof(SDKCtlMessageHeader) + msg_size; 942 msg_header->packet.type = SDKCTL_PACKET_MESSAGE; 943 msg_header->msg_type = msg_type; 944 } 945 946 /******************************************************************************** 947 * SDKCtlQuery implementation 948 *******************************************************************************/ 949 950 /* Frees query descriptor. */ 951 static void 952 _sdkctl_query_free(SDKCtlQuery* query) 953 { 954 if (query != NULL) { 955 SDKCtlSocket* const sdkctl = query->sdkctl; 956 if (query->internal_resp_buffer != NULL && 957 (query->response_buffer == NULL || 958 query->response_buffer == &query->internal_resp_buffer)) { 959 /* This query used its internal buffer to receive the response. 960 * Free it. */ 961 free(query->internal_resp_buffer); 962 } 963 964 loopTimer_done(query->timer); 965 966 /* Recyle the descriptor. */ 967 _sdkctl_socket_free_recycler(sdkctl, query); 968 969 T("SDKCtl %s: Query %p is freed.", sdkctl->service_name, query); 970 971 /* Release socket that owned this query. */ 972 sdkctl_socket_release(sdkctl); 973 } 974 } 975 976 /* Cancels timeout for the query. 977 * 978 * For the simplicity of implementation, the dispatcher will cancel query timer 979 * when query response data begins to flow in. If we let the timer to expire at 980 * that stage, we will end up with data flowing in without real place to 981 * accomodate it. 982 */ 983 static void 984 _sdkctl_query_cancel_timeout(SDKCtlQuery* query) 985 { 986 loopTimer_stop(query->timer); 987 988 T("SDKCtl %s: Query %p ID %d deadline %lld is cancelled.", 989 query->sdkctl->service_name, query, query->header.query_id, query->deadline); 990 } 991 992 /* 993 * Query I/O callbacks. 994 */ 995 996 /* Callback that is invoked by the I/O dispatcher when query is successfuly 997 * completed (i.e. response to the query is received). 998 */ 999 static void 1000 _on_sdkctl_query_completed(SDKCtlQuery* query) 1001 { 1002 T("SDKCtl %s: Query %p ID %d is completed.", 1003 query->sdkctl->service_name, query, query->header.query_id); 1004 1005 /* Cancel deadline, and inform the client about query completion. */ 1006 _sdkctl_query_cancel_timeout(query); 1007 query->query_cb(query->query_opaque, query, ASIO_STATE_SUCCEEDED); 1008 } 1009 1010 /* A callback that is invoked on query cancellation. */ 1011 static void 1012 _on_sdkctl_query_cancelled(SDKCtlQuery* query) 1013 { 1014 /* 1015 * Query cancellation means that SDK controller is disconnected. In turn, 1016 * this means that SDK controller socket will handle disconnection in its 1017 * connection callback. So, at this point all we need to do here is to inform 1018 * the client about query cancellation. 1019 */ 1020 1021 /* Cancel deadline, and inform the client about query cancellation. */ 1022 _sdkctl_query_cancel_timeout(query); 1023 query->query_cb(query->query_opaque, query, ASIO_STATE_CANCELLED); 1024 } 1025 1026 /* A timer callback that is invoked on query timeout. 1027 * Param: 1028 * opaque - SDKCtlQuery instance. 1029 */ 1030 static void 1031 _on_skdctl_query_timeout(void* opaque) 1032 { 1033 SDKCtlQuery* const query = (SDKCtlQuery*)opaque; 1034 1035 D("SDKCtl %s: Query %p ID %d with deadline %lld has timed out at %lld", 1036 query->sdkctl->service_name, query, query->header.query_id, 1037 query->deadline, async_socket_deadline(query->sdkctl->as, 0)); 1038 1039 /* Reference the query while we're in this callback. */ 1040 sdkctl_query_reference(query); 1041 1042 /* Inform the client about deadline expiration. Note that client may 1043 * extend the deadline, and retry the query. */ 1044 const AsyncIOAction action = 1045 query->query_cb(query->query_opaque, query, ASIO_STATE_TIMED_OUT); 1046 1047 /* For actions other than retry we will destroy the query. */ 1048 if (action != ASIO_ACTION_RETRY) { 1049 _sdkctl_socket_remove_query(query); 1050 } 1051 1052 sdkctl_query_release(query); 1053 } 1054 1055 /* A callback that is invoked when query has been sent to the SDK controller. */ 1056 static void 1057 _on_sdkctl_query_sent(SDKCtlQuery* query) 1058 { 1059 T("SDKCtl %s: Sent %d bytes of query %p ID %d of type %d", 1060 query->sdkctl->service_name, query->header.packet.size, query, 1061 query->header.query_id, query->header.query_type); 1062 1063 /* Inform the client about the event. */ 1064 query->query_cb(query->query_opaque, query, ASIO_STATE_CONTINUES); 1065 1066 /* Set a timer to expire at query's deadline, and let the response to come 1067 * through the dispatcher loop. */ 1068 loopTimer_startAbsolute(query->timer, query->deadline); 1069 } 1070 1071 /* An I/O callback invoked on query transmission. 1072 * Param: 1073 * io_opaque SDKCtlQuery instance of the query that's being sent with this I/O. 1074 * asio - Write I/O descriptor. 1075 * status - I/O status. 1076 */ 1077 static AsyncIOAction 1078 _on_sdkctl_query_send_io(void* io_opaque, 1079 AsyncSocketIO* asio, 1080 AsyncIOState status) 1081 { 1082 SDKCtlQuery* const query = (SDKCtlQuery*)io_opaque; 1083 AsyncIOAction action = ASIO_ACTION_DONE; 1084 1085 /* Reference the query while we're in this callback. */ 1086 sdkctl_query_reference(query); 1087 1088 /* Lets see what's going on with query transmission. */ 1089 switch (status) { 1090 case ASIO_STATE_SUCCEEDED: 1091 /* Query has been sent to the service. */ 1092 _on_sdkctl_query_sent(query); 1093 break; 1094 1095 case ASIO_STATE_CANCELLED: 1096 T("SDKCtl %s: Query %p ID %d is cancelled in transmission.", 1097 query->sdkctl->service_name, query, query->header.query_id); 1098 /* Remove the query from the list of active queries. */ 1099 _sdkctl_socket_remove_query(query); 1100 _on_sdkctl_query_cancelled(query); 1101 break; 1102 1103 case ASIO_STATE_TIMED_OUT: 1104 D("SDKCtl %s: Query %p ID %d with deadline %lld has timed out in transmission at %lld", 1105 query->sdkctl->service_name, query, query->header.query_id, 1106 query->deadline, async_socket_deadline(query->sdkctl->as, 0)); 1107 /* Invoke query's callback. */ 1108 action = query->query_cb(query->query_opaque, query, status); 1109 /* For actions other than retry we need to stop the query. */ 1110 if (action != ASIO_ACTION_RETRY) { 1111 _sdkctl_socket_remove_query(query); 1112 } 1113 break; 1114 1115 case ASIO_STATE_FAILED: 1116 T("SDKCtl %s: Query %p ID %d failed in transmission: %d -> %s", 1117 query->sdkctl->service_name, query, query->header.query_id, 1118 errno, strerror(errno)); 1119 /* Invoke query's callback. Note that we will let the client to 1120 * decide what to do on I/O failure. */ 1121 action = query->query_cb(query->query_opaque, query, status); 1122 /* For actions other than retry we need to stop the query. */ 1123 if (action != ASIO_ACTION_RETRY) { 1124 _sdkctl_socket_remove_query(query); 1125 } 1126 break; 1127 1128 case ASIO_STATE_FINISHED: 1129 /* Time to disassociate with the I/O. */ 1130 sdkctl_query_release(query); 1131 break; 1132 1133 default: 1134 /* Transitional state. */ 1135 break; 1136 } 1137 1138 sdkctl_query_release(query); 1139 1140 return action; 1141 } 1142 1143 /******************************************************************************** 1144 * SDKCtlQuery public API implementation 1145 ********************************************************************************/ 1146 1147 SDKCtlQuery* 1148 sdkctl_query_new(SDKCtlSocket* sdkctl, int query_type, uint32_t in_data_size) 1149 { 1150 SDKCtlQuery* const query = 1151 _sdkctl_socket_alloc_recycler(sdkctl, sizeof(SDKCtlQuery) + in_data_size); 1152 query->next = NULL; 1153 query->sdkctl = sdkctl; 1154 query->response_buffer = NULL; 1155 query->response_size = NULL; 1156 query->internal_resp_buffer = NULL; 1157 query->internal_resp_size = 0; 1158 query->query_cb = NULL; 1159 query->query_opaque = NULL; 1160 query->deadline = DURATION_INFINITE; 1161 query->ref_count = 1; 1162 query->header.packet.signature = _sdkctl_packet_sig; 1163 query->header.packet.size = sizeof(SDKCtlQueryHeader) + in_data_size; 1164 query->header.packet.type = SDKCTL_PACKET_QUERY; 1165 query->header.query_id = _sdkctl_socket_next_query_id(sdkctl); 1166 query->header.query_type = query_type; 1167 1168 /* Initialize timer to fire up on query deadline expiration. */ 1169 loopTimer_init(query->timer, sdkctl->looper, _on_skdctl_query_timeout, query); 1170 1171 /* Reference socket that owns this query. */ 1172 sdkctl_socket_reference(sdkctl); 1173 1174 T("SDKCtl %s: Query %p ID %d type %d is created for %d bytes of data.", 1175 query->sdkctl->service_name, query, query->header.query_id, 1176 query_type, in_data_size); 1177 1178 return query; 1179 } 1180 1181 SDKCtlQuery* 1182 sdkctl_query_new_ex(SDKCtlSocket* sdkctl, 1183 int query_type, 1184 uint32_t in_data_size, 1185 const void* in_data, 1186 void** response_buffer, 1187 uint32_t* response_size, 1188 on_sdkctl_query_cb query_cb, 1189 void* query_opaque) 1190 { 1191 SDKCtlQuery* const query = sdkctl_query_new(sdkctl, query_type, in_data_size); 1192 1193 query->response_buffer = response_buffer; 1194 if (query->response_buffer == NULL) { 1195 /* Creator didn't supply a buffer. Use internal one instead. */ 1196 query->response_buffer = &query->internal_resp_buffer; 1197 } 1198 query->response_size = response_size; 1199 if (query->response_size == NULL) { 1200 /* Creator didn't supply a buffer for response size. Use internal one 1201 * instead. */ 1202 query->response_size = &query->internal_resp_size; 1203 } 1204 query->query_cb = query_cb; 1205 query->query_opaque = query_opaque; 1206 /* Init query's input buffer. */ 1207 if (in_data_size != 0 && in_data != NULL) { 1208 memcpy(query + 1, in_data, in_data_size); 1209 } 1210 1211 return query; 1212 } 1213 1214 void 1215 sdkctl_query_send(SDKCtlQuery* query, int to) 1216 { 1217 SDKCtlSocket* const sdkctl = query->sdkctl; 1218 1219 /* Initialize the deadline. */ 1220 query->deadline = async_socket_deadline(query->sdkctl->as, to); 1221 1222 /* List the query in the list of active queries. */ 1223 _sdkctl_socket_add_query(query); 1224 1225 /* Reference query associated with write I/O. */ 1226 sdkctl_query_reference(query); 1227 1228 assert(query->header.packet.signature == _sdkctl_packet_sig); 1229 /* Transmit the query to SDK controller. */ 1230 async_socket_write_abs(sdkctl->as, &query->header, query->header.packet.size, 1231 _on_sdkctl_query_send_io, query, query->deadline); 1232 1233 T("SDKCtl %s: Query %p ID %d type %d is being sent with deadline at %lld", 1234 query->sdkctl->service_name, query, query->header.query_id, 1235 query->header.query_type, query->deadline); 1236 } 1237 1238 SDKCtlQuery* 1239 sdkctl_query_build_and_send(SDKCtlSocket* sdkctl, 1240 int query_type, 1241 uint32_t in_data_size, 1242 const void* in_data, 1243 void** response_buffer, 1244 uint32_t* response_size, 1245 on_sdkctl_query_cb query_cb, 1246 void* query_opaque, 1247 int to) 1248 { 1249 SDKCtlQuery* const query = 1250 sdkctl_query_new_ex(sdkctl, query_type, in_data_size, in_data, 1251 response_buffer, response_size, query_cb, 1252 query_opaque); 1253 sdkctl_query_send(query, to); 1254 return query; 1255 } 1256 1257 int 1258 sdkctl_query_reference(SDKCtlQuery* query) 1259 { 1260 assert(query->ref_count > 0); 1261 query->ref_count++; 1262 return query->ref_count; 1263 } 1264 1265 int 1266 sdkctl_query_release(SDKCtlQuery* query) 1267 { 1268 assert(query->ref_count > 0); 1269 query->ref_count--; 1270 if (query->ref_count == 0) { 1271 /* Last reference has been dropped. Destroy this object. */ 1272 _sdkctl_query_free(query); 1273 return 0; 1274 } 1275 return query->ref_count; 1276 } 1277 1278 void* 1279 sdkctl_query_get_buffer_in(SDKCtlQuery* query) 1280 { 1281 /* Query buffer starts right after the header. */ 1282 return query + 1; 1283 } 1284 1285 void* 1286 sdkctl_query_get_buffer_out(SDKCtlQuery* query) 1287 { 1288 return query->response_buffer != NULL ? *query->response_buffer : 1289 query->internal_resp_buffer; 1290 } 1291 1292 /******************************************************************************** 1293 * SDKCtlPacket implementation 1294 *******************************************************************************/ 1295 1296 /* A packet has been received from SDK controller. 1297 * Note that we expect the packet to be a message, since queries, and query 1298 * replies are handled separately. */ 1299 static void 1300 _on_sdkctl_packet_received(SDKCtlSocket* sdkctl, SDKCtlPacket* packet) 1301 { 1302 T("SDKCtl %s: Received packet size: %d, type: %d", 1303 sdkctl->service_name, packet->header.size, packet->header.type); 1304 1305 assert(packet->header.signature == _sdkctl_packet_sig); 1306 if (packet->header.type == SDKCTL_PACKET_MESSAGE) { 1307 SDKCtlMessage* const msg = (SDKCtlMessage*)packet; 1308 /* Lets see if this is an internal protocol message. */ 1309 switch (msg->msg_type) { 1310 case SDKCTL_MSG_PORT_CONNECTED: 1311 sdkctl->port_status = SDKCTL_PORT_CONNECTED; 1312 sdkctl->on_port_connection(sdkctl->opaque, sdkctl, 1313 SDKCTL_PORT_CONNECTED); 1314 break; 1315 1316 case SDKCTL_MSG_PORT_DISCONNECTED: 1317 sdkctl->port_status = SDKCTL_PORT_DISCONNECTED; 1318 sdkctl->on_port_connection(sdkctl->opaque, sdkctl, 1319 SDKCTL_PORT_DISCONNECTED); 1320 break; 1321 1322 case SDKCTL_MSG_PORT_ENABLED: 1323 sdkctl->port_status = SDKCTL_PORT_ENABLED; 1324 sdkctl->on_port_connection(sdkctl->opaque, sdkctl, 1325 SDKCTL_PORT_ENABLED); 1326 break; 1327 1328 case SDKCTL_MSG_PORT_DISABLED: 1329 sdkctl->port_status = SDKCTL_PORT_DISABLED; 1330 sdkctl->on_port_connection(sdkctl->opaque, sdkctl, 1331 SDKCTL_PORT_DISABLED); 1332 break; 1333 1334 default: 1335 /* This is a higher-level message. Dispatch the message to the 1336 * client. */ 1337 sdkctl->on_message(sdkctl->opaque, sdkctl, msg, msg->msg_type, msg + 1, 1338 packet->header.size - sizeof(SDKCtlMessageHeader)); 1339 break; 1340 } 1341 } else { 1342 E("SDKCtl %s: Received unknown packet type %d size %d", 1343 sdkctl->service_name, packet->header.type, packet->header.size); 1344 } 1345 } 1346 1347 /******************************************************************************** 1348 * SDKCtlIODispatcher implementation 1349 *******************************************************************************/ 1350 1351 /* An I/O callback invoked when data gets received from the socket. 1352 * Param: 1353 * io_opaque SDKCtlIODispatcher instance associated with the reader. 1354 * asio - Read I/O descriptor. 1355 * status - I/O status. 1356 */ 1357 static AsyncIOAction _on_sdkctl_io_dispatcher_io(void* io_opaque, 1358 AsyncSocketIO* asio, 1359 AsyncIOState status); 1360 1361 /* Starts I/O dispatcher for SDK controller socket. */ 1362 static void 1363 _sdkctl_io_dispatcher_start(SDKCtlSocket* sdkctl) { 1364 SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher; 1365 1366 dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER; 1367 dispatcher->sdkctl = sdkctl; 1368 dispatcher->packet = NULL; 1369 dispatcher->current_query = NULL; 1370 1371 /* Register a packet header reader with the socket. */ 1372 async_socket_read_rel(dispatcher->sdkctl->as, &dispatcher->packet_header, 1373 sizeof(SDKCtlPacketHeader), _on_sdkctl_io_dispatcher_io, 1374 dispatcher, -1); 1375 } 1376 1377 /* Resets I/O dispatcher for SDK controller socket. */ 1378 static void 1379 _sdkctl_io_dispatcher_reset(SDKCtlSocket* sdkctl) { 1380 SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher; 1381 1382 /* Cancel current query. */ 1383 if (dispatcher->current_query != NULL) { 1384 SDKCtlQuery* const query = dispatcher->current_query; 1385 dispatcher->current_query = NULL; 1386 _on_sdkctl_query_cancelled(query); 1387 sdkctl_query_release(query); 1388 } 1389 1390 /* Free packet data buffer. */ 1391 if (dispatcher->packet != NULL) { 1392 _sdkctl_packet_release(dispatcher->packet); 1393 dispatcher->packet = NULL; 1394 } 1395 1396 /* Reset dispatcher state. */ 1397 dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER; 1398 1399 T("SDKCtl %s: I/O Dispatcher is reset", sdkctl->service_name); 1400 } 1401 1402 /* 1403 * I/O dispatcher callbacks. 1404 */ 1405 1406 /* A callback that is invoked when a failure occurred while dispatcher was 1407 * reading data from the socket. 1408 */ 1409 static void 1410 _on_io_dispatcher_io_failure(SDKCtlIODispatcher* dispatcher, 1411 AsyncSocketIO* asio) 1412 { 1413 SDKCtlSocket* const sdkctl = dispatcher->sdkctl; 1414 1415 D("SDKCtl %s: Dispatcher I/O failure: %d -> %s", 1416 sdkctl->service_name, errno, strerror(errno)); 1417 1418 /* We treat all I/O failures same way we treat disconnection. Just cancel 1419 * everything, disconnect, and let the client to decide what to do next. */ 1420 sdkctl_socket_disconnect(sdkctl); 1421 1422 /* Report disconnection to the client, and let it restore connection in this 1423 * callback. */ 1424 sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED); 1425 } 1426 1427 /* A callback that is invoked when dispatcher's reader has been cancelled. */ 1428 static void 1429 _on_io_dispatcher_io_cancelled(SDKCtlIODispatcher* dispatcher, 1430 AsyncSocketIO* asio) 1431 { 1432 T("SDKCtl %s: Dispatcher I/O cancelled.", dispatcher->sdkctl->service_name); 1433 1434 /* If we're in the middle of receiving query reply we need to cancel the 1435 * query. */ 1436 if (dispatcher->current_query != NULL) { 1437 SDKCtlQuery* const query = dispatcher->current_query; 1438 dispatcher->current_query = NULL; 1439 _on_sdkctl_query_cancelled(query); 1440 sdkctl_query_release(query); 1441 } 1442 1443 /* Discard packet data we've received so far. */ 1444 if (dispatcher->packet != NULL) { 1445 _sdkctl_packet_release(dispatcher->packet); 1446 dispatcher->packet = NULL; 1447 } 1448 } 1449 1450 /* A generic packet header has been received by I/O dispatcher. */ 1451 static AsyncIOAction 1452 _on_io_dispatcher_packet_header(SDKCtlIODispatcher* dispatcher, 1453 AsyncSocketIO* asio) 1454 { 1455 SDKCtlSocket* const sdkctl = dispatcher->sdkctl; 1456 1457 T("SDKCtl %s: Packet header type %d, size %d is received.", 1458 dispatcher->sdkctl->service_name, dispatcher->packet_header.type, 1459 dispatcher->packet_header.size); 1460 1461 /* Make sure we have a valid packet header. */ 1462 if (dispatcher->packet_header.signature != _sdkctl_packet_sig) { 1463 E("SDKCtl %s: Invalid packet signature %x for packet type %d, size %d", 1464 sdkctl->service_name, dispatcher->packet_header.signature, 1465 dispatcher->packet_header.type, dispatcher->packet_header.size); 1466 /* This is a protocol failure. Treat it as I/O failure: disconnect, and 1467 * let the client to decide what to do next. */ 1468 errno = EINVAL; 1469 _on_io_dispatcher_io_failure(dispatcher, asio); 1470 return ASIO_ACTION_DONE; 1471 } 1472 1473 /* Here we have three choices for the packet, that define the rest of 1474 * the data that follow it: 1475 * - Regular packet, 1476 * - Response to a query that has been sent to SDK controller, 1477 * - A query from SDK controller. 1478 * Update the state accordingly, and initiate reading of the 1479 * remaining of the packet. 1480 */ 1481 if (dispatcher->packet_header.type == SDKCTL_PACKET_QUERY_RESPONSE) { 1482 /* This is a response to the query. Before receiving response data we 1483 * need to locate the relevant query, and use its response buffer to read 1484 * the data. For that we need to obtain query ID firts. So, initiate 1485 * reading of the remaining part of SDKCtlQueryReplyHeader. */ 1486 dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER; 1487 async_socket_read_rel(sdkctl->as, &dispatcher->query_reply_header.query_id, 1488 sizeof(SDKCtlQueryReplyHeader) - sizeof(SDKCtlPacketHeader), 1489 _on_sdkctl_io_dispatcher_io, dispatcher, -1); 1490 } else { 1491 /* For regular packets, as well as queries, we simply allocate buffer, 1492 * that fits the entire packet, and read the remainder of the data in 1493 * there. */ 1494 dispatcher->state = SDKCTL_IODISP_EXPECT_DATA; 1495 dispatcher->packet = 1496 _sdkctl_packet_new(sdkctl, dispatcher->packet_header.size, 1497 dispatcher->packet_header.type); 1498 /* Initiate reading of the packet data. */ 1499 async_socket_read_rel(sdkctl->as, dispatcher->packet + 1, 1500 dispatcher->packet_header.size - sizeof(SDKCtlPacketHeader), 1501 _on_sdkctl_io_dispatcher_io, dispatcher, -1); 1502 } 1503 1504 return ASIO_ACTION_DONE; 1505 } 1506 1507 /* A generic packet has been received by I/O dispatcher. */ 1508 static AsyncIOAction 1509 _on_io_dispatcher_packet(SDKCtlIODispatcher* dispatcher, AsyncSocketIO* asio) 1510 { 1511 SDKCtlSocket* const sdkctl = dispatcher->sdkctl; 1512 SDKCtlPacket* const packet = dispatcher->packet; 1513 dispatcher->packet = NULL; 1514 1515 T("SDKCtl %s: Packet type %d, size %d is received.", 1516 dispatcher->sdkctl->service_name, dispatcher->packet_header.type, 1517 dispatcher->packet_header.size); 1518 1519 _on_sdkctl_packet_received(sdkctl, packet); 1520 _sdkctl_packet_release(packet); 1521 1522 /* Get ready for the next I/O cycle. */ 1523 dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER; 1524 async_socket_read_rel(sdkctl->as, &dispatcher->packet_header, sizeof(SDKCtlPacketHeader), 1525 _on_sdkctl_io_dispatcher_io, dispatcher, -1); 1526 return ASIO_ACTION_DONE; 1527 } 1528 1529 /* A query reply header has been received by I/O dispatcher. */ 1530 static AsyncIOAction 1531 _on_io_dispatcher_query_reply_header(SDKCtlIODispatcher* dispatcher, 1532 AsyncSocketIO* asio) 1533 { 1534 SDKCtlSocket* const sdkctl = dispatcher->sdkctl; 1535 SDKCtlQuery* query; 1536 1537 T("SDKCtl %s: Query reply header is received for query ID %d", 1538 dispatcher->sdkctl->service_name, dispatcher->query_reply_header.query_id); 1539 1540 /* Pull the query out of the list of active queries. It's the dispatcher that 1541 * owns this query now. */ 1542 dispatcher->current_query = 1543 _sdkctl_socket_remove_query_id(sdkctl, dispatcher->query_reply_header.query_id); 1544 query = dispatcher->current_query; 1545 const uint32_t query_data_size = 1546 dispatcher->packet_header.size - sizeof(SDKCtlQueryReplyHeader); 1547 dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA; 1548 1549 if (query == NULL) { 1550 D("%s: Query #%d is not found by dispatcher", 1551 dispatcher->sdkctl->service_name, dispatcher->query_reply_header.query_id); 1552 1553 /* Query is not found. Just read the remainder of reply up in the air, 1554 * and then discard when it's over. */ 1555 dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA; 1556 dispatcher->packet = 1557 _sdkctl_packet_new(sdkctl, dispatcher->packet_header.size, 1558 dispatcher->packet_header.type); 1559 /* Copy query reply info to the packet. */ 1560 memcpy(&dispatcher->packet->header, &dispatcher->query_reply_header, 1561 sizeof(SDKCtlQueryReplyHeader)); 1562 async_socket_read_rel(sdkctl->as, dispatcher->packet + 1, query_data_size, 1563 _on_sdkctl_io_dispatcher_io, dispatcher, -1); 1564 } else { 1565 /* Prepare to receive query reply. For the simplicity sake, cancel query 1566 * time out, so it doesn't expire on us while we're in the middle of 1567 * receiving query's reply. */ 1568 _sdkctl_query_cancel_timeout(query); 1569 1570 if (*query->response_size < query_data_size) { 1571 *query->response_buffer = malloc(query_data_size); 1572 if (*query->response_buffer == NULL) { 1573 APANIC("%s: Unable to allocate %d bytes for query response", 1574 sdkctl->service_name, query_data_size); 1575 } 1576 } 1577 /* Save the actual query response size. */ 1578 *query->response_size = query_data_size; 1579 1580 /* Start reading query response. */ 1581 async_socket_read_rel(sdkctl->as, *query->response_buffer, 1582 *query->response_size, _on_sdkctl_io_dispatcher_io, 1583 dispatcher, -1); 1584 } 1585 1586 return ASIO_ACTION_DONE; 1587 } 1588 1589 /* A query reply header has been received by I/O dispatcher. */ 1590 static AsyncIOAction 1591 _on_io_dispatcher_query_reply(SDKCtlIODispatcher* dispatcher, AsyncSocketIO* asio) 1592 { 1593 SDKCtlSocket* const sdkctl = dispatcher->sdkctl; 1594 SDKCtlQuery* const query = dispatcher->current_query; 1595 dispatcher->current_query = NULL; 1596 1597 if (query != NULL) { 1598 _ANDROID_ASSERT(query->header.query_id == dispatcher->query_reply_header.query_id, 1599 "SDKCtl %s: Query ID mismatch in I/O dispatcher", 1600 sdkctl->service_name); 1601 T("SDKCtl %s: Query reply is received for query %p ID %d. Reply size is %d", 1602 dispatcher->sdkctl->service_name, query, query->header.query_id, 1603 *query->response_size); 1604 1605 /* Complete the query, and release it from the dispatcher. */ 1606 _on_sdkctl_query_completed(query); 1607 sdkctl_query_release(query); 1608 } else { 1609 /* This was "read up in the air" for a cancelled query. Just discard the 1610 * read data. */ 1611 if (dispatcher->packet != NULL) { 1612 _sdkctl_packet_release(dispatcher->packet); 1613 dispatcher->packet = NULL; 1614 } 1615 } 1616 1617 /* Get ready for the next I/O cycle. */ 1618 dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER; 1619 async_socket_read_rel(sdkctl->as, &dispatcher->packet_header, sizeof(SDKCtlPacketHeader), 1620 _on_sdkctl_io_dispatcher_io, dispatcher, -1); 1621 return ASIO_ACTION_DONE; 1622 } 1623 1624 /* An I/O callback invoked when data gets received from the socket. 1625 * This is main I/O dispatcher loop. 1626 * Param: 1627 * io_opaque SDKCtlIODispatcher instance associated with the reader. 1628 * asio - Read I/O descriptor. 1629 * status - I/O status. 1630 */ 1631 static AsyncIOAction 1632 _on_sdkctl_io_dispatcher_io(void* io_opaque, 1633 AsyncSocketIO* asio, 1634 AsyncIOState status) 1635 { 1636 AsyncIOAction action = ASIO_ACTION_DONE; 1637 SDKCtlIODispatcher* const dispatcher = (SDKCtlIODispatcher*)io_opaque; 1638 SDKCtlSocket* const sdkctl = dispatcher->sdkctl; 1639 1640 /* Reference SDKCtlSocket while we're in this callback. */ 1641 sdkctl_socket_reference(sdkctl); 1642 1643 if (status != ASIO_STATE_SUCCEEDED) { 1644 /* Something going on with I/O other than receiving data.. */ 1645 switch (status) { 1646 case ASIO_STATE_STARTED: 1647 /* Data has started flowing in. Cancel timeout on I/O that has 1648 * started, so we can complete the current state of the 1649 * dispatcher without interruptions other than I/O failures. */ 1650 async_socket_io_cancel_time_out(asio); 1651 break; 1652 1653 case ASIO_STATE_FAILED: 1654 /* I/O failure has occurred. Handle the failure. */ 1655 _on_io_dispatcher_io_failure(dispatcher, asio); 1656 break; 1657 1658 case ASIO_STATE_TIMED_OUT: 1659 /* The way I/O dispatcher is implemented, this should never 1660 * happen, because dispatcher doesn't set I/O expiration time 1661 * when registering its readers. */ 1662 _ANDROID_ASSERT(0, 1663 "SDKCtl %s: We should never receive ASIO_STATE_TIMED_OUT in SDKCtl I/O dispatcher.", 1664 sdkctl->service_name); 1665 break; 1666 1667 case ASIO_STATE_CANCELLED: 1668 /* Cancellation means that we're in the middle of handling 1669 * disconnection. Sooner or later, this dispatcher will be reset, 1670 * so we don't really care about keeping its state at this point. 1671 */ 1672 _on_io_dispatcher_io_cancelled(dispatcher, asio); 1673 break; 1674 1675 case ASIO_STATE_FINISHED: 1676 break; 1677 1678 default: 1679 _ANDROID_ASSERT(0, "SDKCtl %s: Unexpected I/O status %d in the dispatcher", 1680 sdkctl->service_name, status); 1681 /* Handle this as protocol failure. */ 1682 errno = EINVAL; 1683 _on_io_dispatcher_io_failure(dispatcher, asio); 1684 action = ASIO_ACTION_ABORT; 1685 break; 1686 } 1687 1688 sdkctl_socket_release(sdkctl); 1689 1690 return action; 1691 } 1692 1693 /* Requested data has been read. Handle the chunk depending on dispatcher's 1694 * state. */ 1695 switch (dispatcher->state) { 1696 case SDKCTL_IODISP_EXPECT_HEADER: 1697 /* A generic packet header is received. */ 1698 action = _on_io_dispatcher_packet_header(dispatcher, asio); 1699 break; 1700 1701 case SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER: 1702 /* Query reply header is received. */ 1703 action = _on_io_dispatcher_query_reply_header(dispatcher, asio); 1704 break; 1705 1706 case SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA: 1707 /* Query reply is received. Complete the query. */ 1708 action = _on_io_dispatcher_query_reply(dispatcher, asio); 1709 break; 1710 1711 case SDKCTL_IODISP_EXPECT_DATA: 1712 /* A generic packet is received. */ 1713 action = _on_io_dispatcher_packet(dispatcher, asio); 1714 break; 1715 1716 default: 1717 _ANDROID_ASSERT(0, "SDKCtl %s: Unexpected I/O dispacher state %d", 1718 sdkctl->service_name, dispatcher->state); 1719 break; 1720 } 1721 1722 sdkctl_socket_release(sdkctl); 1723 1724 return action; 1725 } 1726 1727 /******************************************************************************** 1728 * SDKCtlSocket internals. 1729 *******************************************************************************/ 1730 1731 /* Cancels all queries that is active on this socket. */ 1732 static void 1733 _sdkctl_socket_cancel_all_queries(SDKCtlSocket* sdkctl) 1734 { 1735 SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher; 1736 SDKCtlQuery* query; 1737 1738 /* Cancel query that is being completed in dispatcher. */ 1739 if (dispatcher->current_query != NULL) { 1740 SDKCtlQuery* const query = dispatcher->current_query; 1741 dispatcher->current_query = NULL; 1742 _on_sdkctl_query_cancelled(query); 1743 sdkctl_query_release(query); 1744 } 1745 1746 /* One by one empty query list cancelling pulled queries. */ 1747 query = _sdkctl_socket_pull_first_query(sdkctl); 1748 while (query != NULL) { 1749 _sdkctl_query_cancel_timeout(query); 1750 query->query_cb(query->query_opaque, query, ASIO_STATE_CANCELLED); 1751 sdkctl_query_release(query); 1752 query = _sdkctl_socket_pull_first_query(sdkctl); 1753 } 1754 } 1755 1756 /* Cancels all packets that is active on this socket. */ 1757 static void 1758 _sdkctl_socket_cancel_all_packets(SDKCtlSocket* sdkctl) 1759 { 1760 } 1761 1762 /* Cancels all I/O that is active on this socket. */ 1763 static void 1764 _sdkctl_socket_cancel_all_io(SDKCtlSocket* sdkctl) 1765 { 1766 /* Cancel all queries, and packets that are active for this I/O. */ 1767 _sdkctl_socket_cancel_all_queries(sdkctl); 1768 _sdkctl_socket_cancel_all_packets(sdkctl); 1769 } 1770 1771 /* Disconnects AsyncSocket for SDKCtlSocket. */ 1772 static void 1773 _sdkctl_socket_disconnect_socket(SDKCtlSocket* sdkctl) 1774 { 1775 if (sdkctl->as != NULL) { 1776 /* Disconnect the socket. This will trigger I/O cancellation callbacks. */ 1777 async_socket_disconnect(sdkctl->as); 1778 1779 /* Cancel all I/O that is active on this socket. */ 1780 _sdkctl_socket_cancel_all_io(sdkctl); 1781 1782 /* Reset I/O dispatcher. */ 1783 _sdkctl_io_dispatcher_reset(sdkctl); 1784 } 1785 1786 sdkctl->state = SDKCTL_SOCKET_DISCONNECTED; 1787 sdkctl->port_status = SDKCTL_PORT_DISCONNECTED; 1788 } 1789 1790 /* Frees SDKCtlSocket instance. */ 1791 static void 1792 _sdkctl_socket_free(SDKCtlSocket* sdkctl) 1793 { 1794 if (sdkctl != NULL) { 1795 T("SDKCtl %s: descriptor is destroing.", sdkctl->service_name); 1796 1797 /* Disconnect, and release the socket. */ 1798 if (sdkctl->as != NULL) { 1799 async_socket_disconnect(sdkctl->as); 1800 async_socket_release(sdkctl->as); 1801 } 1802 1803 /* Free allocated resources. */ 1804 if (sdkctl->looper != NULL) { 1805 looper_free(sdkctl->looper); 1806 } 1807 if (sdkctl->service_name != NULL) { 1808 free(sdkctl->service_name); 1809 } 1810 _sdkctl_socket_empty_recycler(sdkctl); 1811 1812 AFREE(sdkctl); 1813 } 1814 } 1815 1816 /******************************************************************************** 1817 * SDK Control Socket connection callbacks. 1818 *******************************************************************************/ 1819 1820 /* Initiates handshake query when SDK controller socket is connected. */ 1821 static void _sdkctl_do_handshake(SDKCtlSocket* sdkctl); 1822 1823 /* A socket connection is established. 1824 * Here we will start I/O dispatcher, and will initiate a handshake with 1825 * the SdkController service for this socket. */ 1826 static AsyncIOAction 1827 _on_async_socket_connected(SDKCtlSocket* sdkctl) 1828 { 1829 D("SDKCtl %s: Socket is connected.", sdkctl->service_name); 1830 1831 /* Notify the client that connection is established. */ 1832 const AsyncIOAction action = 1833 sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_SUCCEEDED); 1834 1835 if (action == ASIO_ACTION_DONE) { 1836 /* Initialize, and start main I/O dispatcher. */ 1837 _sdkctl_io_dispatcher_start(sdkctl); 1838 1839 /* Initiate handshake. */ 1840 _sdkctl_do_handshake(sdkctl); 1841 1842 return action; 1843 } else { 1844 /* Client didn't like something about this connection. */ 1845 return action; 1846 } 1847 } 1848 1849 /* Handles lost connection with SdkController service. */ 1850 static AsyncIOAction 1851 _on_async_socket_disconnected(SDKCtlSocket* sdkctl) 1852 { 1853 D("SDKCtl %s: Socket has been disconnected.", sdkctl->service_name); 1854 1855 _sdkctl_socket_disconnect_socket(sdkctl); 1856 1857 AsyncIOAction action = sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, 1858 ASIO_STATE_FAILED); 1859 if (action == ASIO_ACTION_DONE) { 1860 /* Default action for disconnect is to reestablish the connection. */ 1861 action = ASIO_ACTION_RETRY; 1862 } 1863 if (action == ASIO_ACTION_RETRY) { 1864 sdkctl->state = SDKCTL_SOCKET_CONNECTING; 1865 } 1866 return action; 1867 } 1868 1869 /* An entry point for all socket connection events. 1870 * Here we will dispatch connection events to appropriate handlers. 1871 * Param: 1872 * client_opaque - SDKCtlSocket isntance. 1873 */ 1874 static AsyncIOAction 1875 _on_async_socket_connection(void* client_opaque, 1876 AsyncSocket* as, 1877 AsyncIOState status) 1878 { 1879 AsyncIOAction action = ASIO_ACTION_DONE; 1880 SDKCtlSocket* const sdkctl = (SDKCtlSocket*)client_opaque; 1881 1882 /* Reference the socket while in this callback. */ 1883 sdkctl_socket_reference(sdkctl); 1884 1885 switch (status) { 1886 case ASIO_STATE_SUCCEEDED: 1887 sdkctl->state = SDKCTL_SOCKET_CONNECTED; 1888 _on_async_socket_connected(sdkctl); 1889 break; 1890 1891 case ASIO_STATE_FAILED: 1892 if (sdkctl->state == SDKCTL_SOCKET_CONNECTED) { 1893 /* This is disconnection condition. */ 1894 action = _on_async_socket_disconnected(sdkctl); 1895 } else { 1896 /* An error has occurred while attempting to connect to socket. 1897 * Lets try again... */ 1898 action = ASIO_ACTION_RETRY; 1899 } 1900 break; 1901 1902 case ASIO_STATE_RETRYING: 1903 default: 1904 action = ASIO_ACTION_RETRY; 1905 break; 1906 } 1907 1908 sdkctl_socket_release(sdkctl); 1909 1910 return action; 1911 } 1912 1913 /******************************************************************************** 1914 * SDK Control Socket public API 1915 *******************************************************************************/ 1916 1917 SDKCtlSocket* 1918 sdkctl_socket_new(int reconnect_to, 1919 const char* service_name, 1920 on_sdkctl_socket_connection_cb on_socket_connection, 1921 on_sdkctl_port_connection_cb on_port_connection, 1922 on_sdkctl_message_cb on_message, 1923 void* opaque) 1924 { 1925 SDKCtlSocket* sdkctl; 1926 ANEW0(sdkctl); 1927 1928 sdkctl->state = SDKCTL_SOCKET_DISCONNECTED; 1929 sdkctl->port_status = SDKCTL_PORT_DISCONNECTED; 1930 sdkctl->opaque = opaque; 1931 sdkctl->service_name = ASTRDUP(service_name); 1932 sdkctl->on_socket_connection = on_socket_connection; 1933 sdkctl->on_port_connection = on_port_connection; 1934 sdkctl->on_message = on_message; 1935 sdkctl->reconnect_to = reconnect_to; 1936 sdkctl->as = NULL; 1937 sdkctl->next_query_id = 0; 1938 sdkctl->query_head = sdkctl->query_tail = NULL; 1939 sdkctl->ref_count = 1; 1940 sdkctl->recycler = NULL; 1941 sdkctl->recycler_block_size = 0; 1942 sdkctl->recycler_max = 0; 1943 sdkctl->recycler_count = 0; 1944 1945 T("SDKCtl %s: descriptor is created.", sdkctl->service_name); 1946 1947 sdkctl->looper = looper_newCore(); 1948 if (sdkctl->looper == NULL) { 1949 E("Unable to create I/O looper for SDKCtl socket '%s'", 1950 service_name); 1951 on_socket_connection(opaque, sdkctl, ASIO_STATE_FAILED); 1952 _sdkctl_socket_free(sdkctl); 1953 return NULL; 1954 } 1955 1956 return sdkctl; 1957 } 1958 1959 int sdkctl_socket_reference(SDKCtlSocket* sdkctl) 1960 { 1961 assert(sdkctl->ref_count > 0); 1962 sdkctl->ref_count++; 1963 return sdkctl->ref_count; 1964 } 1965 1966 int 1967 sdkctl_socket_release(SDKCtlSocket* sdkctl) 1968 { 1969 assert(sdkctl->ref_count > 0); 1970 sdkctl->ref_count--; 1971 if (sdkctl->ref_count == 0) { 1972 /* Last reference has been dropped. Destroy this object. */ 1973 _sdkctl_socket_free(sdkctl); 1974 return 0; 1975 } 1976 return sdkctl->ref_count; 1977 } 1978 1979 void 1980 sdkctl_init_recycler(SDKCtlSocket* sdkctl, 1981 uint32_t data_size, 1982 int max_recycled_num) 1983 { 1984 if (sdkctl->recycler != NULL) { 1985 D("SDKCtl %s: Recycler is already initialized. Ignoring recycler init.", 1986 sdkctl->service_name); 1987 return; 1988 } 1989 1990 /* SDKCtlQuery is max descriptor sizeof. */ 1991 data_size += sizeof(SDKCtlQuery); 1992 1993 sdkctl->recycler_block_size = data_size; 1994 sdkctl->recycler_max = max_recycled_num; 1995 sdkctl->recycler_count = 0; 1996 } 1997 1998 void 1999 sdkctl_socket_connect(SDKCtlSocket* sdkctl, int port, int retry_to) 2000 { 2001 T("SDKCtl %s: Handling connect request to port %d, retrying in %dms...", 2002 sdkctl->service_name, port, retry_to); 2003 2004 sdkctl->state = SDKCTL_SOCKET_CONNECTING; 2005 sdkctl->as = async_socket_new(port, sdkctl->reconnect_to, 2006 _on_async_socket_connection, sdkctl, 2007 sdkctl->looper); 2008 if (sdkctl->as == NULL) { 2009 E("Unable to allocate AsyncSocket for SDKCtl socket '%s'", 2010 sdkctl->service_name); 2011 sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED); 2012 } else { 2013 async_socket_connect(sdkctl->as, retry_to); 2014 } 2015 } 2016 2017 void 2018 sdkctl_socket_reconnect(SDKCtlSocket* sdkctl, int port, int retry_to) 2019 { 2020 T("SDKCtl %s: Handling reconnection request to port %d, retrying in %dms...", 2021 sdkctl->service_name, port, retry_to); 2022 2023 _sdkctl_socket_disconnect_socket(sdkctl); 2024 2025 if (sdkctl->as == NULL) { 2026 sdkctl_socket_connect(sdkctl, port, retry_to); 2027 } else { 2028 sdkctl->state = SDKCTL_SOCKET_CONNECTING; 2029 async_socket_reconnect(sdkctl->as, retry_to); 2030 } 2031 } 2032 2033 void 2034 sdkctl_socket_disconnect(SDKCtlSocket* sdkctl) 2035 { 2036 T("SDKCtl %s: Handling disconnect request.", sdkctl->service_name); 2037 2038 _sdkctl_socket_disconnect_socket(sdkctl); 2039 } 2040 2041 int 2042 sdkctl_socket_is_connected(SDKCtlSocket* sdkctl) 2043 { 2044 return (sdkctl->state == SDKCTL_SOCKET_CONNECTED) ? 1 : 0; 2045 } 2046 2047 int 2048 sdkctl_socket_is_port_ready(SDKCtlSocket* sdkctl) 2049 { 2050 return (sdkctl->port_status == SDKCTL_PORT_ENABLED) ? 1 : 0; 2051 } 2052 2053 SdkCtlPortStatus 2054 sdkctl_socket_get_port_status(SDKCtlSocket* sdkctl) 2055 { 2056 return sdkctl->port_status; 2057 } 2058 2059 int 2060 sdkctl_socket_is_handshake_ok(SDKCtlSocket* sdkctl) 2061 { 2062 switch (sdkctl->port_status) { 2063 case SDKCTL_HANDSHAKE_DUP: 2064 case SDKCTL_HANDSHAKE_UNKNOWN_QUERY: 2065 case SDKCTL_HANDSHAKE_UNKNOWN_RESPONSE: 2066 return 0; 2067 default: 2068 return 1; 2069 } 2070 } 2071 2072 /******************************************************************************** 2073 * Handshake query 2074 *******************************************************************************/ 2075 2076 /* 2077 * Handshake result values. 2078 */ 2079 2080 /* Handshake has succeeded completed, and service-side port is connected. */ 2081 #define SDKCTL_HANDSHAKE_RESP_CONNECTED 0 2082 /* Handshake has succeeded completed, but service-side port is not connected. */ 2083 #define SDKCTL_HANDSHAKE_RESP_NOPORT 1 2084 /* Handshake has failed due to duplicate connection request. */ 2085 #define SDKCTL_HANDSHAKE_RESP_DUP -1 2086 /* Handshake has failed due to unknown query. */ 2087 #define SDKCTL_HANDSHAKE_RESP_QUERY_UNKNOWN -2 2088 2089 /* A callback that is ivoked on handshake I/O events. */ 2090 static AsyncIOAction 2091 _on_handshake_io(void* query_opaque, 2092 SDKCtlQuery* query, 2093 AsyncIOState status) 2094 { 2095 SDKCtlSocket* const sdkctl = (SDKCtlSocket*)query_opaque; 2096 2097 if (status == ASIO_STATE_SUCCEEDED) { 2098 const int* res = (const int*)(*query->response_buffer); 2099 SdkCtlPortStatus handshake_status; 2100 switch (*res) { 2101 case SDKCTL_HANDSHAKE_RESP_CONNECTED: 2102 D("SDKCtl %s: Handshake succeeded. Port is connected", 2103 sdkctl->service_name); 2104 handshake_status = SDKCTL_HANDSHAKE_CONNECTED; 2105 break; 2106 2107 case SDKCTL_HANDSHAKE_RESP_NOPORT: 2108 D("SDKCtl %s: Handshake succeeded. Port is not connected", 2109 sdkctl->service_name); 2110 handshake_status = SDKCTL_HANDSHAKE_NO_PORT; 2111 break; 2112 2113 case SDKCTL_HANDSHAKE_RESP_DUP: 2114 D("SDKCtl %s: Handshake failed: duplicate connection.", 2115 sdkctl->service_name); 2116 handshake_status = SDKCTL_HANDSHAKE_DUP; 2117 break; 2118 2119 case SDKCTL_HANDSHAKE_RESP_QUERY_UNKNOWN: 2120 D("SDKCtl %s: Handshake failed: unknown query.", 2121 sdkctl->service_name); 2122 handshake_status = SDKCTL_HANDSHAKE_UNKNOWN_QUERY; 2123 break; 2124 2125 default: 2126 E("SDKCtl %s: Unknown handshake response: %d", 2127 sdkctl->service_name, *res); 2128 handshake_status = SDKCTL_HANDSHAKE_UNKNOWN_RESPONSE; 2129 break; 2130 } 2131 sdkctl->port_status = handshake_status; 2132 sdkctl->on_port_connection(sdkctl->opaque, sdkctl, handshake_status); 2133 } else { 2134 /* Something is going on with the handshake... */ 2135 switch (status) { 2136 case ASIO_STATE_FAILED: 2137 case ASIO_STATE_TIMED_OUT: 2138 case ASIO_STATE_CANCELLED: 2139 D("SDKCtl %s: Handshake failed: I/O state %d. Error: %d -> %s", 2140 sdkctl->service_name, status, errno, strerror(errno)); 2141 sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, 2142 ASIO_STATE_FAILED); 2143 break; 2144 2145 default: 2146 break; 2147 } 2148 } 2149 return ASIO_ACTION_DONE; 2150 } 2151 2152 static AsyncIOAction 2153 _on_sdkctl_endianness_io(void* io_opaque, 2154 AsyncSocketIO* asio, 2155 AsyncIOState status) { 2156 SDKCtlSocket* const sdkctl = (SDKCtlSocket*)io_opaque; 2157 2158 if (status == ASIO_STATE_SUCCEEDED) { 2159 /* Now it's time to initiate handshake message. */ 2160 D("SDKCtl %s: Sending handshake query...", sdkctl->service_name); 2161 SDKCtlQuery* query = 2162 sdkctl_query_build_and_send(sdkctl, SDKCTL_QUERY_HANDSHAKE, 2163 strlen(sdkctl->service_name), 2164 sdkctl->service_name, NULL, NULL, 2165 _on_handshake_io, sdkctl, 3000); 2166 sdkctl_query_release(query); 2167 return ASIO_ACTION_DONE; 2168 } else { 2169 /* Something is going on with the endianness... */ 2170 switch (status) { 2171 case ASIO_STATE_FAILED: 2172 case ASIO_STATE_TIMED_OUT: 2173 case ASIO_STATE_CANCELLED: 2174 D("SDKCtl %s: endianness failed: I/O state %d. Error: %d -> %s", 2175 sdkctl->service_name, status, errno, strerror(errno)); 2176 sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED); 2177 break; 2178 2179 default: 2180 break; 2181 } 2182 } 2183 return ASIO_ACTION_DONE; 2184 } 2185 2186 static void 2187 _sdkctl_do_handshake(SDKCtlSocket* sdkctl) 2188 { 2189 #ifndef HOST_WORDS_BIGENDIAN 2190 static const char _host_end = 0; 2191 #else 2192 static const char _host_end = 1; 2193 #endif 2194 2195 D("SDKCtl %s: Sending endianness: %d", sdkctl->service_name, _host_end); 2196 2197 /* Before we can send any structured data to the SDK controller we need to 2198 * report endianness of the host. */ 2199 async_socket_write_rel(sdkctl->as, &_host_end, 1, 2200 _on_sdkctl_endianness_io, sdkctl, 3000); 2201 } 2202