Home | History | Annotate | Download | only in android
      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