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