• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "android/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*
_sdkctl_socket_alloc_recycler(SDKCtlSocket * sdkctl,uint32_t size)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
_sdkctl_socket_free_recycler(SDKCtlSocket * sdkctl,void * mem)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
_sdkctl_socket_empty_recycler(SDKCtlSocket * sdkctl)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
_sdkctl_socket_add_query(SDKCtlQuery * query)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
_sdkctl_socket_remove_query(SDKCtlQuery * query)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*
_sdkctl_socket_remove_query_id(SDKCtlSocket * sdkctl,int query_id)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*
_sdkctl_socket_pull_first_query(SDKCtlSocket * sdkctl)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
_sdkctl_socket_next_query_id(SDKCtlSocket * sdkctl)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*
_sdkctl_packet_new(SDKCtlSocket * sdkctl,uint32_t size,int type)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
_sdkctl_packet_free(SDKCtlPacket * packet)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
_sdkctl_packet_reference(SDKCtlPacket * packet)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
_sdkctl_packet_release(SDKCtlPacket * packet)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
_on_sdkctl_packet_send_io(void * io_opaque,AsyncSocketIO * asio,AsyncIOState status)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
_sdkctl_packet_transmit(SDKCtlPacket * packet)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*
sdkctl_direct_packet_new(SDKCtlSocket * sdkctl)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
_sdkctl_direct_packet_free(SDKCtlDirectPacket * packet)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
sdkctl_direct_packet_reference(SDKCtlDirectPacket * packet)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
sdkctl_direct_packet_release(SDKCtlDirectPacket * packet)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
_on_sdkctl_direct_packet_send_io(void * io_opaque,AsyncSocketIO * asio,AsyncIOState status)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
sdkctl_direct_packet_send(SDKCtlDirectPacket * packet,void * data,on_sdkctl_direct_cb cb,void * cb_opaque)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*
_sdkctl_message_new(SDKCtlSocket * sdkctl,uint32_t msg_size,int msg_type)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
sdkctl_message_reference(SDKCtlMessage * msg)903 sdkctl_message_reference(SDKCtlMessage* msg)
904 {
905     return _sdkctl_packet_reference(&msg->packet);
906 }
907 
908 int
sdkctl_message_release(SDKCtlMessage * msg)909 sdkctl_message_release(SDKCtlMessage* msg)
910 {
911     return _sdkctl_packet_release(&msg->packet);
912 }
913 
914 SDKCtlMessage*
sdkctl_message_send(SDKCtlSocket * sdkctl,int msg_type,const void * data,uint32_t size)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
sdkctl_message_get_header_size(void)930 sdkctl_message_get_header_size(void)
931 {
932     return sizeof(SDKCtlMessageHeader);
933 }
934 
935 void
sdkctl_init_message_header(void * msg,int msg_type,int msg_size)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
_sdkctl_query_free(SDKCtlQuery * query)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
_sdkctl_query_cancel_timeout(SDKCtlQuery * query)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
_on_sdkctl_query_completed(SDKCtlQuery * query)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
_on_sdkctl_query_cancelled(SDKCtlQuery * query)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
_on_skdctl_query_timeout(void * opaque)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
_on_sdkctl_query_sent(SDKCtlQuery * query)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
_on_sdkctl_query_send_io(void * io_opaque,AsyncSocketIO * asio,AsyncIOState status)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*
sdkctl_query_new(SDKCtlSocket * sdkctl,int query_type,uint32_t in_data_size)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*
sdkctl_query_new_ex(SDKCtlSocket * sdkctl,int query_type,uint32_t in_data_size,const void * in_data,void ** response_buffer,uint32_t * response_size,on_sdkctl_query_cb query_cb,void * query_opaque)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
sdkctl_query_send(SDKCtlQuery * query,int to)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*
sdkctl_query_build_and_send(SDKCtlSocket * sdkctl,int query_type,uint32_t in_data_size,const void * in_data,void ** response_buffer,uint32_t * response_size,on_sdkctl_query_cb query_cb,void * query_opaque,int to)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
sdkctl_query_reference(SDKCtlQuery * query)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
sdkctl_query_release(SDKCtlQuery * query)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*
sdkctl_query_get_buffer_in(SDKCtlQuery * query)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*
sdkctl_query_get_buffer_out(SDKCtlQuery * query)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
_on_sdkctl_packet_received(SDKCtlSocket * sdkctl,SDKCtlPacket * packet)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
_sdkctl_io_dispatcher_start(SDKCtlSocket * sdkctl)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
_sdkctl_io_dispatcher_reset(SDKCtlSocket * sdkctl)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
_on_io_dispatcher_io_failure(SDKCtlIODispatcher * dispatcher,AsyncSocketIO * asio)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
_on_io_dispatcher_io_cancelled(SDKCtlIODispatcher * dispatcher,AsyncSocketIO * asio)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
_on_io_dispatcher_packet_header(SDKCtlIODispatcher * dispatcher,AsyncSocketIO * asio)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
_on_io_dispatcher_packet(SDKCtlIODispatcher * dispatcher,AsyncSocketIO * asio)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
_on_io_dispatcher_query_reply_header(SDKCtlIODispatcher * dispatcher,AsyncSocketIO * asio)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
_on_io_dispatcher_query_reply(SDKCtlIODispatcher * dispatcher,AsyncSocketIO * asio)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
_on_sdkctl_io_dispatcher_io(void * io_opaque,AsyncSocketIO * asio,AsyncIOState status)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
_sdkctl_socket_cancel_all_queries(SDKCtlSocket * sdkctl)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
_sdkctl_socket_cancel_all_packets(SDKCtlSocket * sdkctl)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
_sdkctl_socket_cancel_all_io(SDKCtlSocket * sdkctl)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
_sdkctl_socket_disconnect_socket(SDKCtlSocket * sdkctl)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
_sdkctl_socket_free(SDKCtlSocket * sdkctl)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
_on_async_socket_connected(SDKCtlSocket * sdkctl)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
_on_async_socket_disconnected(SDKCtlSocket * sdkctl)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
_on_async_socket_connection(void * client_opaque,AsyncSocket * as,AsyncIOState status)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*
sdkctl_socket_new(int reconnect_to,const char * service_name,on_sdkctl_socket_connection_cb on_socket_connection,on_sdkctl_port_connection_cb on_port_connection,on_sdkctl_message_cb on_message,void * opaque)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 
sdkctl_socket_reference(SDKCtlSocket * sdkctl)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
sdkctl_socket_release(SDKCtlSocket * sdkctl)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
sdkctl_init_recycler(SDKCtlSocket * sdkctl,uint32_t data_size,int max_recycled_num)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
sdkctl_socket_connect(SDKCtlSocket * sdkctl,int port,int retry_to)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
sdkctl_socket_reconnect(SDKCtlSocket * sdkctl,int port,int retry_to)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
sdkctl_socket_disconnect(SDKCtlSocket * sdkctl)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
sdkctl_socket_is_connected(SDKCtlSocket * sdkctl)2042 sdkctl_socket_is_connected(SDKCtlSocket* sdkctl)
2043 {
2044     return (sdkctl->state == SDKCTL_SOCKET_CONNECTED) ? 1 : 0;
2045 }
2046 
2047 int
sdkctl_socket_is_port_ready(SDKCtlSocket * sdkctl)2048 sdkctl_socket_is_port_ready(SDKCtlSocket* sdkctl)
2049 {
2050     return (sdkctl->port_status == SDKCTL_PORT_ENABLED) ? 1 : 0;
2051 }
2052 
2053 SdkCtlPortStatus
sdkctl_socket_get_port_status(SDKCtlSocket * sdkctl)2054 sdkctl_socket_get_port_status(SDKCtlSocket* sdkctl)
2055 {
2056     return sdkctl->port_status;
2057 }
2058 
2059 int
sdkctl_socket_is_handshake_ok(SDKCtlSocket * sdkctl)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
_on_handshake_io(void * query_opaque,SDKCtlQuery * query,AsyncIOState status)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
_on_sdkctl_endianness_io(void * io_opaque,AsyncSocketIO * asio,AsyncIOState status)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
_sdkctl_do_handshake(SDKCtlSocket * sdkctl)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