blob: 8b0d8133f43f9591838c7048ee1923de1b22364a [file] [log] [blame]
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001/*
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
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070023#include "android/utils/debug.h"
24#include "android/async-socket-connector.h"
25#include "android/async-socket.h"
26#include "android/sdk-controller-socket.h"
27#include "utils/panic.h"
28#include "iolooper.h"
29
30#define E(...) derror(__VA_ARGS__)
31#define W(...) dwarning(__VA_ARGS__)
32#define D(...) VERBOSE_PRINT(sdkctlsocket,__VA_ARGS__)
33#define D_ACTIVE VERBOSE_CHECK(sdkctlsocket)
34
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -070035#define TRACE_ON 0
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070036
37#if TRACE_ON
38#define T(...) VERBOSE_PRINT(sdkctlsocket,__VA_ARGS__)
39#else
40#define T(...)
41#endif
42
43/* Recycling memory descriptor. */
44typedef struct SDKCtlRecycled SDKCtlRecycled;
45struct 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
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070054/*
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -070055 * Types of the data packets sent via SDK controller socket.
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070056 */
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
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -070065/*
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'). */
105static const int _sdkctl_packet_sig = 0x53444B43;
106
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700107/* 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 */
112typedef struct SDKCtlPacketHeader {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700113 /* Signature. */
114 int signature;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700115 /* 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
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700124 * controller.
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700125 *
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 */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700130typedef struct SDKCtlPacket {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700131 /* Supports recycling. Don't put anything in front: recycler expects this
132 * to be the first field in recyclable descriptor. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700133 SDKCtlRecycled recycling;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700134
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700135 /* SDK controller socket that transmits this packet. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700136 SDKCtlSocket* sdkctl;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700137 /* Number of outstanding references to the packet. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700138 int ref_count;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700139
140 /* Common packet header. Packet data immediately follows this header, so it
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700141 * 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 */
158struct 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;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700173};
174
175/********************************************************************************
176 * SDKCtlQuery declarations
177 *******************************************************************************/
178
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700179/* 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 */
184typedef 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;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700190 /* Query type. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700191 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 */
201struct 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
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700206 /* Next query in the list of active queries. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700207 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
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700211 * timer is set to after query has been transmitted to the service. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700212 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;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700221 /* Points to a variable containing size of the response buffer (on the way
222 * in), or actual query response size (when query is completed). */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700223 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;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700228 /* 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. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700231 uint32_t internal_resp_size;
232 /* Number of outstanding references to the query. */
233 int ref_count;
234
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700235 /* Common query header. Query data immediately follows this header, so it
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700236 * 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 */
245typedef 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/********************************************************************************
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700254 * 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 */
262typedef 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 */
Vladimir Chtchetkine4732aee2012-04-30 12:38:06 -0700274struct SDKCtlMessage {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700275 /* Data packet descriptor for this message. */
276 SDKCtlPacket packet;
277 /* Message type. */
278 int msg_type;
Vladimir Chtchetkine4732aee2012-04-30 12:38:06 -0700279};
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700280
281/********************************************************************************
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700282 * SDK Control Socket declarations
283 *******************************************************************************/
284
285/* Enumerates SDKCtlSocket states. */
286typedef 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. */
296typedef 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. */
308typedef 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. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700316 SDKCtlPacketHeader packet_header;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700317 /* Header for a query packet. */
318 SDKCtlQueryHeader query_header;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700319 /* Header for a message packet. */
320 SDKCtlMessageHeader message_header;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700321 /* Header for a query response packet. */
322 SDKCtlQueryReplyHeader query_reply_header;
323 };
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700324 /* Descriptor of a packet that is being received from SDK controller. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700325 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. */
331struct SDKCtlSocket {
332 /* SDK controller socket state */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700333 SDKCtlSocketState state;
334 /* SDK controller port status */
335 SdkCtlPortStatus port_status;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700336 /* I/O dispatcher for the socket. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700337 SDKCtlIODispatcher io_dispatcher;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700338 /* Asynchronous socket connected to SDK Controller on the device. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700339 AsyncSocket* as;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700340 /* Client callback that monitors this socket connection. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700341 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;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700344 /* A callback to invoke when a message is received from the SDK controller. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700345 on_sdkctl_message_cb on_message;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700346 /* An opaque pointer associated with this socket. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700347 void* opaque;
348 /* Name of an SDK controller port this socket is connected to. */
349 char* service_name;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700350 /* I/O looper for timers. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700351 Looper* looper;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700352 /* Head of the active query list. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700353 SDKCtlQuery* query_head;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700354 /* Tail of the active query list. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700355 SDKCtlQuery* query_tail;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700356 /* Query ID generator that gets incremented for each new query. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700357 int next_query_id;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700358 /* Timeout before trying to reconnect after disconnection. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700359 int reconnect_to;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700360 /* Number of outstanding references to this descriptor. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700361 int ref_count;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700362 /* Head of the recycled memory */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700363 SDKCtlRecycled* recycler;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700364 /* Recyclable block size. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700365 uint32_t recycler_block_size;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700366 /* Maximum number of blocks to recycle. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700367 int recycler_max;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700368 /* Number of blocs in the recycler. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700369 int recycler_count;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700370};
371
372/********************************************************************************
373 * SDKCtlSocket recycling management
374 *******************************************************************************/
375
376/* Gets a recycled block for a given SDKCtlSocket, or allocates new memory
377 * block. */
378static void*
379_sdkctl_socket_alloc_recycler(SDKCtlSocket* sdkctl, uint32_t size)
380{
381 SDKCtlRecycled* block = NULL;
382
383 if (sdkctl->recycler != NULL && size <= sdkctl->recycler_block_size) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700384 assert(sdkctl->recycler_count > 0);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700385 /* 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) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700391 /* There are no blocks in the recycler, but requested size fits. Lets
392 * allocate block that we can later recycle. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700393 block = malloc(sdkctl->recycler_block_size);
394 if (block == NULL) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700395 APANIC("SDKCtl %s: Unable to allocate %d bytes block.",
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700396 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. */
413static void
414_sdkctl_socket_free_recycler(SDKCtlSocket* sdkctl, void* mem)
415{
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700416 SDKCtlRecycled* const block = (SDKCtlRecycled*)mem;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700417
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700418 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. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700421 free(mem);
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700422 } 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++;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700428 }
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700429}
430
431/* Empties the recycler for a given SDKCtlSocket. */
432static void
433_sdkctl_socket_empty_recycler(SDKCtlSocket* sdkctl)
434{
435 SDKCtlRecycled* block = sdkctl->recycler;
436 while (block != NULL) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700437 void* const to_free = block;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700438 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 */
454static void
455_sdkctl_socket_add_query(SDKCtlQuery* query)
456{
457 SDKCtlSocket* const sdkctl = query->sdkctl;
458 if (sdkctl->query_head == NULL) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700459 assert(sdkctl->query_tail == NULL);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700460 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:
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700472 * 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.
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700475 * 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 */
479static int
480_sdkctl_socket_remove_query(SDKCtlQuery* query)
481{
482 SDKCtlSocket* const sdkctl = query->sdkctl;
483 SDKCtlQuery* prev = NULL;
484 SDKCtlQuery* head = sdkctl->query_head;
485
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700486 /* Quick check: the query could be currently handled by the dispatcher. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700487 if (sdkctl->io_dispatcher.current_query == query) {
488 /* Release the query from dispatcher. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700489 sdkctl->io_dispatcher.current_query = NULL;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700490 sdkctl_query_release(query);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700491 return 1;
492 }
493
494 /* Remove query from the list. */
495 while (head != NULL && query != head) {
496 prev = head;
497 head = head->next;
498 }
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700499 if (head == NULL) {
500 D("SDKCtl %s: Query %p is not found in the list.",
501 sdkctl->service_name, query);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700502 return 0;
503 }
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700504
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;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700527}
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
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700535 * 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.
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700538 */
539static SDKCtlQuery*
540_sdkctl_socket_remove_query_id(SDKCtlSocket* sdkctl, int query_id)
541{
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700542 SDKCtlQuery* query = NULL;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700543 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. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700550 query = sdkctl->io_dispatcher.current_query;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700551 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 }
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700560 if (head == NULL) {
561 D("SDKCtl %s: Query ID %d is not found in the list.",
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700562 sdkctl->service_name, query_id);
563 return NULL;
564 }
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700565
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;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700585}
586
587/* Pulls the first query from the list of active queries.
588 * Param:
589 * sdkctl - SDKCtlSocket instance that owns the query.
590 * Return:
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700591 * A query removed from the head of the list of active queries, or NULL if query
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700592 * list is empty.
593 */
594static SDKCtlQuery*
595_sdkctl_socket_pull_first_query(SDKCtlSocket* sdkctl)
596{
597 SDKCtlQuery* const query = sdkctl->query_head;
598
599 if (query != NULL) {
600 sdkctl->query_head = query->next;
601 if (sdkctl->query_head == NULL) {
602 sdkctl->query_tail = NULL;
603 }
604 }
605 return query;
606}
607
608/* Generates new query ID for the given SDKCtl. */
609static int
610_sdkctl_socket_next_query_id(SDKCtlSocket* sdkctl)
611{
612 return ++sdkctl->next_query_id;
613}
614
615/********************************************************************************
616 * SDKCtlPacket implementation
617 *******************************************************************************/
618
619/* Alocates a packet. */
620static SDKCtlPacket*
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700621_sdkctl_packet_new(SDKCtlSocket* sdkctl, uint32_t size, int type)
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700622{
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700623 /* Allocate packet descriptor large enough to contain packet data. */
624 SDKCtlPacket* const packet =
625 _sdkctl_socket_alloc_recycler(sdkctl, sizeof(SDKCtlPacket) + size);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700626
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700627 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;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700632
633 /* Refence SDKCTlSocket that owns this packet. */
634 sdkctl_socket_reference(sdkctl);
635
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700636 T("SDKCtl %s: Packet %p of type %d is allocated for %d bytes transfer.",
637 sdkctl->service_name, packet, type, size);
638
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700639 return packet;
640}
641
642/* Frees a packet. */
643static void
644_sdkctl_packet_free(SDKCtlPacket* packet)
645{
646 SDKCtlSocket* const sdkctl = packet->sdkctl;
647
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700648 /* Recycle packet. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700649 _sdkctl_socket_free_recycler(packet->sdkctl, packet);
650
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700651 T("SDKCtl %s: Packet %p is freed.", sdkctl->service_name, packet);
652
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700653 /* Release SDKCTlSocket that owned this packet. */
654 sdkctl_socket_release(sdkctl);
655}
656
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700657/* References a packet. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700658int
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700659_sdkctl_packet_reference(SDKCtlPacket* packet)
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700660{
661 assert(packet->ref_count > 0);
662 packet->ref_count++;
663 return packet->ref_count;
664}
665
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700666/* Releases a packet. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700667int
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700668_sdkctl_packet_release(SDKCtlPacket* packet)
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700669{
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
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700680/* 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 */
686static AsyncIOAction
687_on_sdkctl_packet_send_io(void* io_opaque,
688 AsyncSocketIO* asio,
689 AsyncIOState status)
690{
691 SDKCtlPacket* const packet = (SDKCtlPacket*)io_opaque;
692 AsyncIOAction action = ASIO_ACTION_DONE;
693
694 /* Reference the packet while we're in this callback. */
695 _sdkctl_packet_reference(packet);
696
697 /* Lets see what's going on with query transmission. */
698 switch (status) {
699 case ASIO_STATE_SUCCEEDED:
700 /* Packet has been sent to the service. */
701 T("SDKCtl %s: Packet %p transmission has succeeded.",
702 packet->sdkctl->service_name, packet);
703 break;
704
705 case ASIO_STATE_CANCELLED:
706 T("SDKCtl %s: Packet %p is cancelled.",
707 packet->sdkctl->service_name, packet);
708 break;
709
710 case ASIO_STATE_FAILED:
711 T("SDKCtl %s: Packet %p has failed: %d -> %s",
712 packet->sdkctl->service_name, packet, errno, strerror(errno));
713 break;
714
715 case ASIO_STATE_FINISHED:
716 /* Time to disassociate the packet with the I/O. */
717 _sdkctl_packet_release(packet);
718 break;
719
720 default:
721 /* Transitional state. */
722 break;
723 }
724
725 _sdkctl_packet_release(packet);
726
727 return action;
728}
729
730/* Transmits a packet to SDK Controller.
731 * Param:
732 * packet - Packet to transmit.
733 */
734static void
735_sdkctl_packet_transmit(SDKCtlPacket* packet)
736{
737 assert(packet->header.signature == _sdkctl_packet_sig);
738
739 /* Reference to associate with the I/O */
740 _sdkctl_packet_reference(packet);
741
742 /* Transmit the packet to SDK controller. */
743 async_socket_write_rel(packet->sdkctl->as, &packet->header, packet->header.size,
744 _on_sdkctl_packet_send_io, packet, -1);
745
746 T("SDKCtl %s: Packet %p size %d is being sent.",
747 packet->sdkctl->service_name, packet, packet->header.size);
748}
749
750/********************************************************************************
751 * SDKCtlDirectPacket implementation
752 ********************************************************************************/
753
754SDKCtlDirectPacket*
755sdkctl_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. */
772static void
773_sdkctl_direct_packet_free(SDKCtlDirectPacket* packet)
774{
775 SDKCtlSocket* const sdkctl = packet->sdkctl;
776
777 /* Free allocated resources. */
778 _sdkctl_socket_free_recycler(packet->sdkctl, packet);
779
780 T("SDKCtl %s: Direct packet %p is freed.", sdkctl->service_name, packet);
781
782 /* Release SDKCTlSocket that owned this packet. */
783 sdkctl_socket_release(sdkctl);
784}
785
786/* References a packet. */
787int
788sdkctl_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. */
796int
797sdkctl_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 */
816static AsyncIOAction
817_on_sdkctl_direct_packet_send_io(void* io_opaque,
818 AsyncSocketIO* asio,
819 AsyncIOState status)
820{
821 SDKCtlDirectPacket* const packet = (SDKCtlDirectPacket*)io_opaque;
822 AsyncIOAction action = ASIO_ACTION_DONE;
823
824 /* Reference the packet while we're in this callback. */
825 sdkctl_direct_packet_reference(packet);
826
827 /* Lets see what's going on with query transmission. */
828 switch (status) {
829 case ASIO_STATE_SUCCEEDED:
830 /* Packet has been sent to the service. */
831 T("SDKCtl %s: Direct packet %p transmission has succeeded.",
832 packet->sdkctl->service_name, packet);
833 packet->on_sent(packet->on_sent_opaque, packet, status);
834 break;
835
836 case ASIO_STATE_CANCELLED:
837 T("SDKCtl %s: Direct packet %p is cancelled.",
838 packet->sdkctl->service_name, packet);
839 packet->on_sent(packet->on_sent_opaque, packet, status);
840 break;
841
842 case ASIO_STATE_FAILED:
843 T("SDKCtl %s: Direct packet %p has failed: %d -> %s",
844 packet->sdkctl->service_name, packet, errno, strerror(errno));
845 packet->on_sent(packet->on_sent_opaque, packet, status);
846 break;
847
848 case ASIO_STATE_FINISHED:
849 /* Time to disassociate with the I/O. */
850 sdkctl_direct_packet_release(packet);
851 break;
852
853 default:
854 /* Transitional state. */
855 break;
856 }
857
858 sdkctl_direct_packet_release(packet);
859
860 return action;
861}
862
863void
864sdkctl_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. */
890static SDKCtlMessage*
891_sdkctl_message_new(SDKCtlSocket* sdkctl, uint32_t msg_size, int msg_type)
892{
893 SDKCtlMessage* const msg =
894 (SDKCtlMessage*)_sdkctl_packet_new(sdkctl,
895 sizeof(SDKCtlMessageHeader) + msg_size,
896 SDKCTL_PACKET_MESSAGE);
897 msg->msg_type = msg_type;
898
899 return msg;
900}
901
902int
903sdkctl_message_reference(SDKCtlMessage* msg)
904{
905 return _sdkctl_packet_reference(&msg->packet);
906}
907
908int
909sdkctl_message_release(SDKCtlMessage* msg)
910{
911 return _sdkctl_packet_release(&msg->packet);
912}
913
914SDKCtlMessage*
915sdkctl_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
929int
930sdkctl_message_get_header_size(void)
931{
932 return sizeof(SDKCtlMessageHeader);
933}
934
935void
936sdkctl_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
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700946/********************************************************************************
947 * SDKCtlQuery implementation
948 *******************************************************************************/
949
950/* Frees query descriptor. */
951static void
952_sdkctl_query_free(SDKCtlQuery* query)
953{
954 if (query != NULL) {
955 SDKCtlSocket* const sdkctl = query->sdkctl;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700956 if (query->internal_resp_buffer != NULL &&
957 (query->response_buffer == NULL ||
958 query->response_buffer == &query->internal_resp_buffer)) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700959 /* This query used its internal buffer to receive the response.
960 * Free it. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700961 free(query->internal_resp_buffer);
962 }
963
964 loopTimer_done(query->timer);
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700965
966 /* Recyle the descriptor. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700967 _sdkctl_socket_free_recycler(sdkctl, query);
968
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700969 T("SDKCtl %s: Query %p is freed.", sdkctl->service_name, query);
970
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700971 /* 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 */
983static void
984_sdkctl_query_cancel_timeout(SDKCtlQuery* query)
985{
986 loopTimer_stop(query->timer);
987
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -0700988 T("SDKCtl %s: Query %p ID %d deadline %lld is cancelled.",
989 query->sdkctl->service_name, query, query->header.query_id, query->deadline);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700990}
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 */
999static void
1000_on_sdkctl_query_completed(SDKCtlQuery* query)
1001{
1002 T("SDKCtl %s: Query %p ID %d is completed.",
1003 query->sdkctl->service_name, query, query->header.query_id);
1004
1005 /* Cancel deadline, and inform the client about query completion. */
1006 _sdkctl_query_cancel_timeout(query);
1007 query->query_cb(query->query_opaque, query, ASIO_STATE_SUCCEEDED);
1008}
1009
1010/* A callback that is invoked on query cancellation. */
1011static void
1012_on_sdkctl_query_cancelled(SDKCtlQuery* query)
1013{
1014 /*
1015 * Query cancellation means that SDK controller is disconnected. In turn,
1016 * this means that SDK controller socket will handle disconnection in its
1017 * connection callback. So, at this point all we need to do here is to inform
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001018 * the client about query cancellation.
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001019 */
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 */
1030static void
1031_on_skdctl_query_timeout(void* opaque)
1032{
1033 SDKCtlQuery* const query = (SDKCtlQuery*)opaque;
1034
1035 D("SDKCtl %s: Query %p ID %d with deadline %lld has timed out at %lld",
1036 query->sdkctl->service_name, query, query->header.query_id,
1037 query->deadline, async_socket_deadline(query->sdkctl->as, 0));
1038
1039 /* Reference the query while we're in this callback. */
1040 sdkctl_query_reference(query);
1041
1042 /* Inform the client about deadline expiration. Note that client may
1043 * extend the deadline, and retry the query. */
1044 const AsyncIOAction action =
1045 query->query_cb(query->query_opaque, query, ASIO_STATE_TIMED_OUT);
1046
1047 /* For actions other than retry we will destroy the query. */
1048 if (action != ASIO_ACTION_RETRY) {
1049 _sdkctl_socket_remove_query(query);
1050 }
1051
1052 sdkctl_query_release(query);
1053}
1054
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001055/* A callback that is invoked when query has been sent to the SDK controller. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001056static void
1057_on_sdkctl_query_sent(SDKCtlQuery* query)
1058{
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001059 T("SDKCtl %s: Sent %d bytes of query %p ID %d of type %d",
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001060 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 */
1077static AsyncIOAction
1078_on_sdkctl_query_send_io(void* io_opaque,
1079 AsyncSocketIO* asio,
1080 AsyncIOState status)
1081{
1082 SDKCtlQuery* const query = (SDKCtlQuery*)io_opaque;
1083 AsyncIOAction action = ASIO_ACTION_DONE;
1084
1085 /* Reference the query while we're in this callback. */
1086 sdkctl_query_reference(query);
1087
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001088 /* Lets see what's going on with query transmission. */
1089 switch (status) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001090 case ASIO_STATE_SUCCEEDED:
1091 /* Query has been sent to the service. */
1092 _on_sdkctl_query_sent(query);
1093 break;
1094
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001095 case ASIO_STATE_CANCELLED:
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001096 T("SDKCtl %s: Query %p ID %d is cancelled in transmission.",
1097 query->sdkctl->service_name, query, query->header.query_id);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001098 /* 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:
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001104 D("SDKCtl %s: Query %p ID %d with deadline %lld has timed out in transmission at %lld",
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001105 query->sdkctl->service_name, query, query->header.query_id,
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001106 query->deadline, async_socket_deadline(query->sdkctl->as, 0));
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001107 /* 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:
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001116 T("SDKCtl %s: Query %p ID %d failed in transmission: %d -> %s",
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001117 query->sdkctl->service_name, query, query->header.query_id,
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001118 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
1147SDKCtlQuery*
1148sdkctl_query_new(SDKCtlSocket* sdkctl, int query_type, uint32_t in_data_size)
1149{
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001150 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;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001167
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
1181SDKCtlQuery*
1182sdkctl_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
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001193 query->response_buffer = response_buffer;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001194 if (query->response_buffer == NULL) {
1195 /* Creator didn't supply a buffer. Use internal one instead. */
1196 query->response_buffer = &query->internal_resp_buffer;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001197 }
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001198 query->response_size = response_size;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001199 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;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001203 }
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001204 query->query_cb = query_cb;
1205 query->query_opaque = query_opaque;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001206 /* 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
1214void
1215sdkctl_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
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001228 assert(query->header.packet.signature == _sdkctl_packet_sig);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001229 /* 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
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001233 T("SDKCtl %s: Query %p ID %d type %d is being sent with deadline at %lld",
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001234 query->sdkctl->service_name, query, query->header.query_id,
1235 query->header.query_type, query->deadline);
1236}
1237
1238SDKCtlQuery*
1239sdkctl_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
1257int
1258sdkctl_query_reference(SDKCtlQuery* query)
1259{
1260 assert(query->ref_count > 0);
1261 query->ref_count++;
1262 return query->ref_count;
1263}
1264
1265int
1266sdkctl_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
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001278void*
1279sdkctl_query_get_buffer_in(SDKCtlQuery* query)
1280{
1281 /* Query buffer starts right after the header. */
1282 return query + 1;
1283}
1284
1285void*
1286sdkctl_query_get_buffer_out(SDKCtlQuery* query)
1287{
1288 return query->response_buffer != NULL ? *query->response_buffer :
1289 query->internal_resp_buffer;
1290}
1291
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001292/********************************************************************************
1293 * SDKCtlPacket implementation
1294 *******************************************************************************/
1295
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001296/* 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. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001299static void
1300_on_sdkctl_packet_received(SDKCtlSocket* sdkctl, SDKCtlPacket* packet)
1301{
1302 T("SDKCtl %s: Received packet size: %d, type: %d",
1303 sdkctl->service_name, packet->header.size, packet->header.type);
1304
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001305 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 }
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001345}
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 */
1357static 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. */
1362static void
1363_sdkctl_io_dispatcher_start(SDKCtlSocket* sdkctl) {
1364 SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
1365
1366 dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
1367 dispatcher->sdkctl = sdkctl;
1368 dispatcher->packet = NULL;
1369 dispatcher->current_query = NULL;
1370
1371 /* Register a packet header reader with the socket. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001372 async_socket_read_rel(dispatcher->sdkctl->as, &dispatcher->packet_header,
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001373 sizeof(SDKCtlPacketHeader), _on_sdkctl_io_dispatcher_io,
1374 dispatcher, -1);
1375}
1376
1377/* Resets I/O dispatcher for SDK controller socket. */
1378static void
1379_sdkctl_io_dispatcher_reset(SDKCtlSocket* sdkctl) {
1380 SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
1381
1382 /* Cancel current query. */
1383 if (dispatcher->current_query != NULL) {
1384 SDKCtlQuery* const query = dispatcher->current_query;
1385 dispatcher->current_query = NULL;
1386 _on_sdkctl_query_cancelled(query);
1387 sdkctl_query_release(query);
1388 }
1389
1390 /* Free packet data buffer. */
1391 if (dispatcher->packet != NULL) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001392 _sdkctl_packet_release(dispatcher->packet);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001393 dispatcher->packet = NULL;
1394 }
1395
1396 /* Reset dispatcher state. */
1397 dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001398
1399 T("SDKCtl %s: I/O Dispatcher is reset", sdkctl->service_name);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001400}
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 */
1409static void
1410_on_io_dispatcher_io_failure(SDKCtlIODispatcher* dispatcher,
1411 AsyncSocketIO* asio)
1412{
1413 SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1414
1415 D("SDKCtl %s: Dispatcher I/O failure: %d -> %s",
1416 sdkctl->service_name, errno, strerror(errno));
1417
1418 /* We treat all I/O failures same way we treat disconnection. Just cancel
1419 * everything, disconnect, and let the client to decide what to do next. */
1420 sdkctl_socket_disconnect(sdkctl);
1421
1422 /* Report disconnection to the client, and let it restore connection in this
1423 * callback. */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001424 sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001425}
1426
1427/* A callback that is invoked when dispatcher's reader has been cancelled. */
1428static void
1429_on_io_dispatcher_io_cancelled(SDKCtlIODispatcher* dispatcher,
1430 AsyncSocketIO* asio)
1431{
1432 T("SDKCtl %s: Dispatcher I/O cancelled.", dispatcher->sdkctl->service_name);
1433
1434 /* If we're in the middle of receiving query reply we need to cancel the
1435 * query. */
1436 if (dispatcher->current_query != NULL) {
1437 SDKCtlQuery* const query = dispatcher->current_query;
1438 dispatcher->current_query = NULL;
1439 _on_sdkctl_query_cancelled(query);
1440 sdkctl_query_release(query);
1441 }
1442
1443 /* Discard packet data we've received so far. */
1444 if (dispatcher->packet != NULL) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001445 _sdkctl_packet_release(dispatcher->packet);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001446 dispatcher->packet = NULL;
1447 }
1448}
1449
1450/* A generic packet header has been received by I/O dispatcher. */
1451static AsyncIOAction
1452_on_io_dispatcher_packet_header(SDKCtlIODispatcher* dispatcher,
1453 AsyncSocketIO* asio)
1454{
1455 SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1456
1457 T("SDKCtl %s: Packet header type %d, size %d is received.",
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001458 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 }
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001472
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 */
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001481 if (dispatcher->packet_header.type == SDKCTL_PACKET_QUERY_RESPONSE) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001482 /* 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 =
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001496 _sdkctl_packet_new(sdkctl, dispatcher->packet_header.size,
1497 dispatcher->packet_header.type);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001498 /* Initiate reading of the packet data. */
1499 async_socket_read_rel(sdkctl->as, dispatcher->packet + 1,
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001500 dispatcher->packet_header.size - sizeof(SDKCtlPacketHeader),
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001501 _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. */
1508static AsyncIOAction
1509_on_io_dispatcher_packet(SDKCtlIODispatcher* dispatcher, AsyncSocketIO* asio)
1510{
1511 SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001512 SDKCtlPacket* const packet = dispatcher->packet;
1513 dispatcher->packet = NULL;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001514
1515 T("SDKCtl %s: Packet type %d, size %d is received.",
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001516 dispatcher->sdkctl->service_name, dispatcher->packet_header.type,
1517 dispatcher->packet_header.size);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001518
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001519 _on_sdkctl_packet_received(sdkctl, packet);
1520 _sdkctl_packet_release(packet);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001521
1522 /* Get ready for the next I/O cycle. */
1523 dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001524 async_socket_read_rel(sdkctl->as, &dispatcher->packet_header, sizeof(SDKCtlPacketHeader),
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001525 _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. */
1530static AsyncIOAction
1531_on_io_dispatcher_query_reply_header(SDKCtlIODispatcher* dispatcher,
1532 AsyncSocketIO* asio)
1533{
1534 SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1535 SDKCtlQuery* query;
1536
1537 T("SDKCtl %s: Query reply header is received for query ID %d",
1538 dispatcher->sdkctl->service_name, dispatcher->query_reply_header.query_id);
1539
1540 /* Pull the query out of the list of active queries. It's the dispatcher that
1541 * owns this query now. */
1542 dispatcher->current_query =
1543 _sdkctl_socket_remove_query_id(sdkctl, dispatcher->query_reply_header.query_id);
1544 query = dispatcher->current_query;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001545 const uint32_t query_data_size =
1546 dispatcher->packet_header.size - sizeof(SDKCtlQueryReplyHeader);
1547 dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001548
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 =
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001557 _sdkctl_packet_new(sdkctl, dispatcher->packet_header.size,
1558 dispatcher->packet_header.type);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001559 /* Copy query reply info to the packet. */
1560 memcpy(&dispatcher->packet->header, &dispatcher->query_reply_header,
1561 sizeof(SDKCtlQueryReplyHeader));
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001562 async_socket_read_rel(sdkctl->as, dispatcher->packet + 1, query_data_size,
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001563 _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
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001570 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. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001581 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. */
1590static AsyncIOAction
1591_on_io_dispatcher_query_reply(SDKCtlIODispatcher* dispatcher, AsyncSocketIO* asio)
1592{
1593 SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1594 SDKCtlQuery* const query = dispatcher->current_query;
1595 dispatcher->current_query = NULL;
1596
1597 if (query != NULL) {
1598 _ANDROID_ASSERT(query->header.query_id == dispatcher->query_reply_header.query_id,
1599 "SDKCtl %s: Query ID mismatch in I/O dispatcher",
1600 sdkctl->service_name);
1601 T("SDKCtl %s: Query reply is received for query %p ID %d. Reply size is %d",
1602 dispatcher->sdkctl->service_name, query, query->header.query_id,
1603 *query->response_size);
1604
1605 /* Complete the query, and release it from the dispatcher. */
1606 _on_sdkctl_query_completed(query);
1607 sdkctl_query_release(query);
1608 } else {
1609 /* This was "read up in the air" for a cancelled query. Just discard the
1610 * read data. */
1611 if (dispatcher->packet != NULL) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001612 _sdkctl_packet_release(dispatcher->packet);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001613 dispatcher->packet = NULL;
1614 }
1615 }
1616
1617 /* Get ready for the next I/O cycle. */
1618 dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001619 async_socket_read_rel(sdkctl->as, &dispatcher->packet_header, sizeof(SDKCtlPacketHeader),
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001620 _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 */
1631static AsyncIOAction
1632_on_sdkctl_io_dispatcher_io(void* io_opaque,
1633 AsyncSocketIO* asio,
1634 AsyncIOState status)
1635{
1636 AsyncIOAction action = ASIO_ACTION_DONE;
1637 SDKCtlIODispatcher* const dispatcher = (SDKCtlIODispatcher*)io_opaque;
1638 SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1639
1640 /* Reference SDKCtlSocket while we're in this callback. */
1641 sdkctl_socket_reference(sdkctl);
1642
1643 if (status != ASIO_STATE_SUCCEEDED) {
1644 /* Something going on with I/O other than receiving data.. */
1645 switch (status) {
1646 case ASIO_STATE_STARTED:
1647 /* Data has started flowing in. Cancel timeout on I/O that has
1648 * started, so we can complete the current state of the
1649 * dispatcher without interruptions other than I/O failures. */
1650 async_socket_io_cancel_time_out(asio);
1651 break;
1652
1653 case ASIO_STATE_FAILED:
1654 /* I/O failure has occurred. Handle the failure. */
1655 _on_io_dispatcher_io_failure(dispatcher, asio);
1656 break;
1657
1658 case ASIO_STATE_TIMED_OUT:
1659 /* The way I/O dispatcher is implemented, this should never
1660 * happen, because dispatcher doesn't set I/O expiration time
1661 * when registering its readers. */
1662 _ANDROID_ASSERT(0,
1663 "SDKCtl %s: We should never receive ASIO_STATE_TIMED_OUT in SDKCtl I/O dispatcher.",
1664 sdkctl->service_name);
1665 break;
1666
1667 case ASIO_STATE_CANCELLED:
1668 /* Cancellation means that we're in the middle of handling
1669 * disconnection. Sooner or later, this dispatcher will be reset,
1670 * so we don't really care about keeping its state at this point.
1671 */
1672 _on_io_dispatcher_io_cancelled(dispatcher, asio);
1673 break;
1674
1675 case ASIO_STATE_FINISHED:
1676 break;
1677
1678 default:
1679 _ANDROID_ASSERT(0, "SDKCtl %s: Unexpected I/O status %d in the dispatcher",
1680 sdkctl->service_name, status);
1681 /* Handle this as protocol failure. */
1682 errno = EINVAL;
1683 _on_io_dispatcher_io_failure(dispatcher, asio);
1684 action = ASIO_ACTION_ABORT;
1685 break;
1686 }
1687
1688 sdkctl_socket_release(sdkctl);
1689
1690 return action;
1691 }
1692
1693 /* Requested data has been read. Handle the chunk depending on dispatcher's
1694 * state. */
1695 switch (dispatcher->state) {
1696 case SDKCTL_IODISP_EXPECT_HEADER:
1697 /* A generic packet header is received. */
1698 action = _on_io_dispatcher_packet_header(dispatcher, asio);
1699 break;
1700
1701 case SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER:
1702 /* Query reply header is received. */
1703 action = _on_io_dispatcher_query_reply_header(dispatcher, asio);
1704 break;
1705
1706 case SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA:
1707 /* Query reply is received. Complete the query. */
1708 action = _on_io_dispatcher_query_reply(dispatcher, asio);
1709 break;
1710
1711 case SDKCTL_IODISP_EXPECT_DATA:
1712 /* A generic packet is received. */
1713 action = _on_io_dispatcher_packet(dispatcher, asio);
1714 break;
1715
1716 default:
1717 _ANDROID_ASSERT(0, "SDKCtl %s: Unexpected I/O dispacher state %d",
1718 sdkctl->service_name, dispatcher->state);
1719 break;
1720 }
1721
1722 sdkctl_socket_release(sdkctl);
1723
1724 return action;
1725}
1726
1727/********************************************************************************
1728 * SDKCtlSocket internals.
1729 *******************************************************************************/
1730
1731/* Cancels all queries that is active on this socket. */
1732static void
1733_sdkctl_socket_cancel_all_queries(SDKCtlSocket* sdkctl)
1734{
1735 SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
1736 SDKCtlQuery* query;
1737
1738 /* Cancel query that is being completed in dispatcher. */
1739 if (dispatcher->current_query != NULL) {
1740 SDKCtlQuery* const query = dispatcher->current_query;
1741 dispatcher->current_query = NULL;
1742 _on_sdkctl_query_cancelled(query);
1743 sdkctl_query_release(query);
1744 }
1745
1746 /* One by one empty query list cancelling pulled queries. */
1747 query = _sdkctl_socket_pull_first_query(sdkctl);
1748 while (query != NULL) {
1749 _sdkctl_query_cancel_timeout(query);
1750 query->query_cb(query->query_opaque, query, ASIO_STATE_CANCELLED);
1751 sdkctl_query_release(query);
1752 query = _sdkctl_socket_pull_first_query(sdkctl);
1753 }
1754}
1755
1756/* Cancels all packets that is active on this socket. */
1757static void
1758_sdkctl_socket_cancel_all_packets(SDKCtlSocket* sdkctl)
1759{
1760}
1761
1762/* Cancels all I/O that is active on this socket. */
1763static void
1764_sdkctl_socket_cancel_all_io(SDKCtlSocket* sdkctl)
1765{
1766 /* Cancel all queries, and packets that are active for this I/O. */
1767 _sdkctl_socket_cancel_all_queries(sdkctl);
1768 _sdkctl_socket_cancel_all_packets(sdkctl);
1769}
1770
1771/* Disconnects AsyncSocket for SDKCtlSocket. */
1772static void
1773_sdkctl_socket_disconnect_socket(SDKCtlSocket* sdkctl)
1774{
1775 if (sdkctl->as != NULL) {
1776 /* Disconnect the socket. This will trigger I/O cancellation callbacks. */
1777 async_socket_disconnect(sdkctl->as);
1778
1779 /* Cancel all I/O that is active on this socket. */
1780 _sdkctl_socket_cancel_all_io(sdkctl);
1781
1782 /* Reset I/O dispatcher. */
1783 _sdkctl_io_dispatcher_reset(sdkctl);
1784 }
1785
1786 sdkctl->state = SDKCTL_SOCKET_DISCONNECTED;
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001787 sdkctl->port_status = SDKCTL_PORT_DISCONNECTED;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001788}
1789
1790/* Frees SDKCtlSocket instance. */
1791static void
1792_sdkctl_socket_free(SDKCtlSocket* sdkctl)
1793{
1794 if (sdkctl != NULL) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001795 T("SDKCtl %s: descriptor is destroing.", sdkctl->service_name);
1796
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001797 /* 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. */
1821static 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. */
1826static AsyncIOAction
1827_on_async_socket_connected(SDKCtlSocket* sdkctl)
1828{
1829 D("SDKCtl %s: Socket is connected.", sdkctl->service_name);
1830
1831 /* Notify the client that connection is established. */
1832 const AsyncIOAction action =
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001833 sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_SUCCEEDED);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001834
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. */
1850static AsyncIOAction
1851_on_async_socket_disconnected(SDKCtlSocket* sdkctl)
1852{
1853 D("SDKCtl %s: Socket has been disconnected.", sdkctl->service_name);
1854
1855 _sdkctl_socket_disconnect_socket(sdkctl);
1856
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001857 AsyncIOAction action = sdkctl->on_socket_connection(sdkctl->opaque, sdkctl,
1858 ASIO_STATE_FAILED);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001859 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 */
1874static AsyncIOAction
1875_on_async_socket_connection(void* client_opaque,
1876 AsyncSocket* as,
1877 AsyncIOState status)
1878{
1879 AsyncIOAction action = ASIO_ACTION_DONE;
1880 SDKCtlSocket* const sdkctl = (SDKCtlSocket*)client_opaque;
1881
1882 /* Reference the socket while in this callback. */
1883 sdkctl_socket_reference(sdkctl);
1884
1885 switch (status) {
1886 case ASIO_STATE_SUCCEEDED:
1887 sdkctl->state = SDKCTL_SOCKET_CONNECTED;
1888 _on_async_socket_connected(sdkctl);
1889 break;
1890
1891 case ASIO_STATE_FAILED:
1892 if (sdkctl->state == SDKCTL_SOCKET_CONNECTED) {
1893 /* This is disconnection condition. */
1894 action = _on_async_socket_disconnected(sdkctl);
1895 } else {
1896 /* An error has occurred while attempting to connect to socket.
1897 * Lets try again... */
1898 action = ASIO_ACTION_RETRY;
1899 }
1900 break;
1901
1902 case ASIO_STATE_RETRYING:
1903 default:
1904 action = ASIO_ACTION_RETRY;
1905 break;
1906 }
1907
1908 sdkctl_socket_release(sdkctl);
1909
1910 return action;
1911}
1912
1913/********************************************************************************
1914 * SDK Control Socket public API
1915 *******************************************************************************/
1916
1917SDKCtlSocket*
1918sdkctl_socket_new(int reconnect_to,
1919 const char* service_name,
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001920 on_sdkctl_socket_connection_cb on_socket_connection,
1921 on_sdkctl_port_connection_cb on_port_connection,
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001922 on_sdkctl_message_cb on_message,
1923 void* opaque)
1924{
1925 SDKCtlSocket* sdkctl;
1926 ANEW0(sdkctl);
1927
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001928 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);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001946
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);
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07001951 on_socket_connection(opaque, sdkctl, ASIO_STATE_FAILED);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07001952 _sdkctl_socket_free(sdkctl);
1953 return NULL;
1954 }
1955
1956 return sdkctl;
1957}
1958
1959int sdkctl_socket_reference(SDKCtlSocket* sdkctl)
1960{
1961 assert(sdkctl->ref_count > 0);
1962 sdkctl->ref_count++;
1963 return sdkctl->ref_count;
1964}
1965
1966int
1967sdkctl_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
1979void
1980sdkctl_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
1998void
1999sdkctl_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);
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07002011 sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07002012 } else {
2013 async_socket_connect(sdkctl->as, retry_to);
2014 }
2015}
2016
2017void
2018sdkctl_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
2033void
2034sdkctl_socket_disconnect(SDKCtlSocket* sdkctl)
2035{
2036 T("SDKCtl %s: Handling disconnect request.", sdkctl->service_name);
2037
2038 _sdkctl_socket_disconnect_socket(sdkctl);
2039}
2040
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07002041int
2042sdkctl_socket_is_connected(SDKCtlSocket* sdkctl)
2043{
2044 return (sdkctl->state == SDKCTL_SOCKET_CONNECTED) ? 1 : 0;
2045}
2046
2047int
2048sdkctl_socket_is_port_ready(SDKCtlSocket* sdkctl)
2049{
2050 return (sdkctl->port_status == SDKCTL_PORT_ENABLED) ? 1 : 0;
2051}
2052
2053SdkCtlPortStatus
2054sdkctl_socket_get_port_status(SDKCtlSocket* sdkctl)
2055{
2056 return sdkctl->port_status;
2057}
2058
2059int
2060sdkctl_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}
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07002071
2072/********************************************************************************
2073 * Handshake query
2074 *******************************************************************************/
2075
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07002076/*
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
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07002089/* A callback that is ivoked on handshake I/O events. */
2090static AsyncIOAction
2091_on_handshake_io(void* query_opaque,
2092 SDKCtlQuery* query,
2093 AsyncIOState status)
2094{
2095 SDKCtlSocket* const sdkctl = (SDKCtlSocket*)query_opaque;
2096
2097 if (status == ASIO_STATE_SUCCEEDED) {
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07002098 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;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07002106
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07002107 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);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07002133 } 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));
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07002141 sdkctl->on_socket_connection(sdkctl->opaque, sdkctl,
2142 ASIO_STATE_FAILED);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07002143 break;
2144
2145 default:
2146 break;
2147 }
2148 }
2149 return ASIO_ACTION_DONE;
2150}
2151
2152static AsyncIOAction
2153_on_sdkctl_endianness_io(void* io_opaque,
2154 AsyncSocketIO* asio,
2155 AsyncIOState status) {
2156 SDKCtlSocket* const sdkctl = (SDKCtlSocket*)io_opaque;
2157
2158 if (status == ASIO_STATE_SUCCEEDED) {
2159 /* Now it's time to initiate handshake message. */
2160 D("SDKCtl %s: Sending handshake query...", sdkctl->service_name);
2161 SDKCtlQuery* query =
2162 sdkctl_query_build_and_send(sdkctl, SDKCTL_QUERY_HANDSHAKE,
2163 strlen(sdkctl->service_name),
2164 sdkctl->service_name, NULL, NULL,
2165 _on_handshake_io, sdkctl, 3000);
2166 sdkctl_query_release(query);
2167 return ASIO_ACTION_DONE;
2168 } else {
2169 /* Something is going on with the endianness... */
2170 switch (status) {
2171 case ASIO_STATE_FAILED:
2172 case ASIO_STATE_TIMED_OUT:
2173 case ASIO_STATE_CANCELLED:
2174 D("SDKCtl %s: endianness failed: I/O state %d. Error: %d -> %s",
2175 sdkctl->service_name, status, errno, strerror(errno));
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07002176 sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07002177 break;
2178
2179 default:
2180 break;
2181 }
2182 }
2183 return ASIO_ACTION_DONE;
2184}
2185
2186static void
2187_sdkctl_do_handshake(SDKCtlSocket* sdkctl)
2188{
2189#ifndef HOST_WORDS_BIGENDIAN
2190static const char _host_end = 0;
2191#else
2192static const char _host_end = 1;
2193#endif
2194
Vladimir Chtchetkine7136b052012-04-10 13:39:24 -07002195 D("SDKCtl %s: Sending endianness: %d", sdkctl->service_name, _host_end);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -07002196
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}