1c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/*
2c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Copyright (C) 2012 The Android Open Source Project
3c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
4c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Licensed under the Apache License, Version 2.0 (the "License");
5c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * you may not use this file except in compliance with the License.
6c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * You may obtain a copy of the License at
7c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
8c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *      http://www.apache.org/licenses/LICENSE-2.0
9c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
10c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Unless required by applicable law or agreed to in writing, software
11c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * distributed under the License is distributed on an "AS IS" BASIS,
12c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * See the License for the specific language governing permissions and
14c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * limitations under the License.
15c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
16c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
17c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/*
18c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Encapsulates exchange protocol between the emulator, and an Android device
19c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * that is connected to the host via USB. The communication is established over
20c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * a TCP port forwarding, enabled by ADB.
21c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
22c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
23c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "qemu-common.h"
24c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "android/async-utils.h"
25c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "android/utils/debug.h"
26c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "android/async-socket-connector.h"
27c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "android/async-socket.h"
28c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "android/sdk-controller-socket.h"
29c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "utils/panic.h"
30c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "iolooper.h"
31c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
32c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  E(...)    derror(__VA_ARGS__)
33c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  W(...)    dwarning(__VA_ARGS__)
34c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  D(...)    VERBOSE_PRINT(sdkctlsocket,__VA_ARGS__)
35c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  D_ACTIVE  VERBOSE_CHECK(sdkctlsocket)
36c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
37c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define TRACE_ON    1
38c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
39c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#if TRACE_ON
40c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  T(...)    VERBOSE_PRINT(sdkctlsocket,__VA_ARGS__)
41c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#else
42c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  T(...)
43c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#endif
44c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
45c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Recycling memory descriptor. */
46c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef struct SDKCtlRecycled SDKCtlRecycled;
47c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestruct SDKCtlRecycled {
48c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    union {
49c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Next recycled descriptor (while listed in recycler). */
50c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlRecycled* next;
51c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Allocated memory size (while outside of the recycler). */
52c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        uint32_t        size;
53c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    };
54c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine};
55c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
56c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
57c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlPacket declarations
58c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
59c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
60c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/*
61c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Types of the packets of data sent via SDK controller socket.
62c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
63c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
64c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* The packet is a message. */
65c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define SDKCTL_PACKET_MESSAGE           1
66c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* The packet is a query. */
67c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define SDKCTL_PACKET_QUERY             2
68c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* The packet is a response to a query. */
69c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define SDKCTL_PACKET_QUERY_RESPONSE    3
70c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
71c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Data packet descriptor.
72c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
73c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * All packets, sent and received via SDK controller socket begin with this
74c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * header, with packet data immediately following this header.
75c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
76c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef struct SDKCtlPacketHeader {
77c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Total size of the data to transfer with this packet, including this
78c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * header. The transferring data should immediatelly follow this header. */
79c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int     size;
80c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Encodes packet type. See SDKCTL_PACKET_XXX for the list of packet types
81c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * used by SDK controller. */
82c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int     type;
83c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlPacketHeader;
84c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
85c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Packet descriptor, allocated by this API for data packets to be sent to SDK
86c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * controller service on the device.
87c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
88c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * When packet descriptors are allocated by this API, they are allocated large
89c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * enough to contain this header, and packet data to send to the service,
90c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * immediately following this descriptor.
91c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
92c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestruct SDKCtlPacket {
93c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Supports recycling. Don't put anything in front: recycler expects this
94c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * to be the first field in recyclable descriptor. */
95c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlRecycled      recycling;
96c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
97c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Next packet in the list of packets to send. */
98c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlPacket*       next;
99c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* SDK controller socket that transmits this packet. */
100c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket*       sdkctl;
101c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Number of outstanding references to the packet. */
102c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                 ref_count;
103c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
104c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Common packet header. Packet data immediately follows this header, so it
105c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * must be last field in SDKCtlPacket descriptor. */
106c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlPacketHeader  header;
107c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine};
108c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
109c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
110c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlQuery declarations
111c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
112c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
113c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/*
114c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Types of queries sent via SDK controller socket.
115c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
116c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
117c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Handshake query.
118c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * This query is sent to SDK controller service as part of the connection
119c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * protocol implementation.
120c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
121c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define SDKCTL_QUERY_HANDSHAKE          -1
122c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
123c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Query packet descriptor.
124c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
125c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * All queries, sent and received via SDK controller socket begin with this
126c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * header, with query data immediately following this header.
127c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
128c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef struct SDKCtlQueryHeader {
129c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Data packet header for this query. */
130c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlPacketHeader  packet;
131c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A unique query identifier. This ID is used to track the query in the
132c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * asynchronous environment in whcih SDK controller socket operates. */
133c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                 query_id;
134c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Query type. See SDKCTL_QUERY_XXX for the list of query types used by SDK
135c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * controller. */
136c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                 query_type;
137c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlQueryHeader;
138c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
139c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Query descriptor, allocated by this API for queries to be sent to SDK
140c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * controller service on the device.
141c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
142c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * When query descriptors are allocated by this API, they are allocated large
143c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * enough to contain this header, and query data to send to the service,
144c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * immediately following this descriptor.
145c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
146c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestruct SDKCtlQuery {
147c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Supports recycling. Don't put anything in front: recycler expects this
148c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * to be the first field in recyclable descriptor. */
149c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlRecycled          recycling;
150c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
151c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Next query in the list of active, or recycled queries. */
152c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery*            next;
153c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A timer to run time out on this query after it has been sent. */
154c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    LoopTimer               timer[1];
155c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Absolute time for this query's deadline. This is the value that query's
156c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * timer is set for after query has been transmitted to the service. */
157c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    Duration                deadline;
158c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* SDK controller socket that owns the query. */
159c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket*           sdkctl;
160c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A callback to invoke on query state changes. */
161c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    on_sdkctl_query_cb      query_cb;
162c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* An opaque pointer associated with this query. */
163c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    void*                   query_opaque;
164c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Points to an address of a buffer where to save query response. */
165c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    void**                  response_buffer;
166c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Points to a variable containing size of the response buffer (on the way in),
167c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * or actual query response size (when query is completed). */
168c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    uint32_t*               response_size;
169c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Internal response buffer, allocated if query creator didn't provide its
170c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * own. This field is valid only if response_buffer field is NULL, or is
171c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * pointing to this field. */
172c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    void*                   internal_resp_buffer;
173c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Internal response buffer size This field is valid only if response_size
174c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * field is NULL, or is pointing to this field. */
175c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    uint32_t                internal_resp_size;
176c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Number of outstanding references to the query. */
177c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                     ref_count;
178c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
179c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Common packet header. Query data immediately follows this header, so it
180c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * must be last field in SDKCtlQuery descriptor. */
181c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQueryHeader       header;
182c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine};
183c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
184c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Query reply descriptor.
185c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
186c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * All replies to a query, sent and received via SDK controller socket begin with
187c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * this header, with query reply data immediately following this header.
188c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
189c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef struct SDKCtlQueryReplyHeader {
190c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Data packet header for this reply. */
191c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlPacketHeader  packet;
192c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
193c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* An identifier for the query that is addressed with this reply. */
194c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                 query_id;
195c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlQueryReplyHeader;
196c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
197c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
198c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDK Control Socket declarations
199c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
200c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
201c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Enumerates SDKCtlSocket states. */
202c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef enum SDKCtlSocketState {
203c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Socket is disconnected from SDK controller. */
204c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_SOCKET_DISCONNECTED,
205c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Connection to SDK controller is in progress. */
206c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_SOCKET_CONNECTING,
207c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Socket is connected to an SDK controller service. */
208c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_SOCKET_CONNECTED
209c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlSocketState;
210c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
211c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Enumerates SDKCtlSocket I/O dispatcher states. */
212c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef enum SDKCtlIODispatcherState {
213c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O dispatcher expects a packet header. */
214c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_IODISP_EXPECT_HEADER,
215c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O dispatcher expects packet data. */
216c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_IODISP_EXPECT_DATA,
217c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O dispatcher expects query response header. */
218c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER,
219c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O dispatcher expects query response data. */
220c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA,
221c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlIODispatcherState;
222c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
223c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* SDKCtlSocket I/O dispatcher descriptor. */
224c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef struct SDKCtlIODispatcher {
225c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* SDKCtlSocket instance for this dispatcher. */
226c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket*               sdkctl;
227c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Dispatcher state. */
228c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcherState     state;
229c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Unites all types of headers used in SDK controller data exchange. */
230c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    union {
231c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Common packet header. */
232c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlPacketHeader      header;
233c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Header for a query packet. */
234c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQueryHeader       query_header;
235c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Header for a query response packet. */
236c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQueryReplyHeader  query_reply_header;
237c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    };
238c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Descriptor of a packet packet received from SDK controller. */
239c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlPacket*               packet;
240c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A query for which a reply is currently being received. */
241c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery*                current_query;
242c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlIODispatcher;
243c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
244c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* SDK controller socket descriptor. */
245c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestruct SDKCtlSocket {
246c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* SDK controller socket state */
247c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocketState           state;
248c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O dispatcher for the socket. */
249c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcher          io_dispatcher;
250c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Asynchronous socket connected to SDK Controller on the device. */
251c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    AsyncSocket*                as;
252c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Client callback that monitors this socket connection. */
253c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    on_sdkctl_connection_cb     on_connection;
254c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A callback to invoke when handshake message is received from the
255c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * SDK controller. */
256c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    on_sdkctl_handshake_cb      on_handshake;
257c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A callback to invoke when a message is received from the SDK controller. */
258c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    on_sdkctl_message_cb        on_message;
259c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* An opaque pointer associated with this socket. */
260c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    void*                       opaque;
261c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Name of an SDK controller service this socket is connected to. */
262c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    char*                       service_name;
263c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O looper for timers. */
264c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    Looper*                     looper;
265c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Head of the active query list. */
266c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery*                query_head;
267c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Tail of the active query list. */
268c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery*                query_tail;
269c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Query ID generator that gets incremented for each new query. */
270c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                         next_query_id;
271c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Timeout before trying to reconnect after disconnection. */
272c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                         reconnect_to;
273c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Number of outstanding references to this descriptor. */
274c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                         ref_count;
275c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Head of the recycled memory */
276c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlRecycled*             recycler;
277c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Recyclable block size. */
278c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    uint32_t                    recycler_block_size;
279c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Maximum number of blocks to recycle. */
280c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                         recycler_max;
281c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Number of blocs in the recycler. */
282c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                         recycler_count;
283c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine};
284c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
285c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
286c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlSocket recycling management
287c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
288c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
289c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Gets a recycled block for a given SDKCtlSocket, or allocates new memory
290c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * block. */
291c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void*
292c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_alloc_recycler(SDKCtlSocket* sdkctl, uint32_t size)
293c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
294c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlRecycled* block = NULL;
295c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
296c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->recycler != NULL && size <= sdkctl->recycler_block_size) {
297c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* There are blocks in the recycler, and requested size fits. */
298c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block = sdkctl->recycler;
299c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->recycler = block->next;
300c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block->size = sdkctl->recycler_block_size;
301c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->recycler_count--;
302c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else if (size <= sdkctl->recycler_block_size) {
303c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* There are no blocks in the recycler, but requested size fits. */
304c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block = malloc(sdkctl->recycler_block_size);
305c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (block == NULL) {
306c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            APANIC("SDKCtl %s: Unable to allocate %d bytes block",
307c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                   sdkctl->service_name, sdkctl->recycler_block_size);
308c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
309c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block->size = sdkctl->recycler_block_size;
310c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
311c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Requested size doesn't fit the recycler. */
312c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block = malloc(size);
313c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (block == NULL) {
314c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            APANIC("SDKCtl %s: Unable to allocate %d bytes block",
315c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                   sdkctl->service_name, size);
316c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
317c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block->size = size;
318c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
319c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
320c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return block;
321c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
322c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
323c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Recycles, or frees a block of memory for a given SDKCtlSocket. */
324c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
325c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_free_recycler(SDKCtlSocket* sdkctl, void* mem)
326c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
327c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlRecycled* block = (SDKCtlRecycled*)mem;
328c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
329c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->recycler_count == sdkctl->recycler_max ||
330c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block->size != sdkctl->recycler_block_size) {
331c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Recycler is full, or block cannot be recycled. */
332c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        free(mem);
333c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return;
334c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
335c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
336c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    block->next = sdkctl->recycler;
337c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler = block;
338c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_count++;
339c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
340c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
341c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Empties the recycler for a given SDKCtlSocket. */
342c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
343c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_empty_recycler(SDKCtlSocket* sdkctl)
344c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
345c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlRecycled* block = sdkctl->recycler;
346c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    while (block != NULL) {
347c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        void* to_free = block;
348c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block = block->next;
349c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        free(to_free);
350c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
351c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler = NULL;
352c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_count = 0;
353c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
354c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
355c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
356c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlSocket query list management
357c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
358c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
359c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Adds a query to the list of active queries.
360c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
361c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  sdkctl - SDKCtlSocket instance for the query.
362c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  query - Query to add to the list.
363c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
364c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
365c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_add_query(SDKCtlQuery* query)
366c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
367c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = query->sdkctl;
368c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->query_head == NULL) {
369c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->query_head = sdkctl->query_tail = query;
370c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
371c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->query_tail->next = query;
372c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->query_tail = query;
373c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
374c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
375c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Keep the query referenced while it's in the list. */
376c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_reference(query);
377c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
378c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
379c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Removes a query from the list of active queries.
380c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
381c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  query - Query to remove from the list of active queries.
382c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Return:
383c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  Boolean: 1 if query has been removed, or 0 if query has not been found in the
384c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  list of active queries.
385c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
386c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic int
387c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_remove_query(SDKCtlQuery* query)
388c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
389c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = query->sdkctl;
390c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* prev = NULL;
391c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* head = sdkctl->query_head;
392c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
393c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Quick check: the query could be currently handled by dispatcher. */
394c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->io_dispatcher.current_query == query) {
395c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Release the query from dispatcher. */
396c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
397c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->io_dispatcher.current_query = NULL;
398c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return 1;
399c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
400c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
401c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Remove query from the list. */
402c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    while (head != NULL && query != head) {
403c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        prev = head;
404c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        head = head->next;
405c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
406c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (head != NULL) {
407c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (prev == NULL) {
408c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Query is at the head of the list. */
409c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            assert(query == sdkctl->query_head);
410c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl->query_head = query->next;
411c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        } else {
412c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Query is in the middle / at the end of the list. */
413c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            assert(query != sdkctl->query_head);
414c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            prev->next = query->next;
415c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
416c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (sdkctl->query_tail == query) {
417c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Query is at the tail of the list. */
418c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            assert(query->next == NULL);
419c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl->query_tail = prev;
420c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
421c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->next = NULL;
422c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
423c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Release query that is now removed from the list. Note that query
424c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * passed to this routine should hold an extra reference, owned by the
425c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * caller. */
426c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
427c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return 1;
428c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
429c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("%s: Query %p is not found in the list.", sdkctl->service_name, query);
430c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return 0;
431c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
432c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
433c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
434c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Removes a query (based on query ID) from the list of active queries.
435c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
436c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  sdkctl - SDKCtlSocket instance that owns the query.
437c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  query_id - Identifies the query to remove.
438c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Return:
439c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  A query removed from the list of active queries, or NULL if query with the
440c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  given ID has not been found in the list.
441c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
442c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic SDKCtlQuery*
443c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_remove_query_id(SDKCtlSocket* sdkctl, int query_id)
444c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
445c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* prev = NULL;
446c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* head = sdkctl->query_head;
447c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
448c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Quick check: the query could be currently handled by dispatcher. */
449c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->io_dispatcher.current_query != NULL &&
450c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->io_dispatcher.current_query->header.query_id == query_id) {
451c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Release the query from dispatcher. */
452c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQuery* const query = sdkctl->io_dispatcher.current_query;
453c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->io_dispatcher.current_query = NULL;
454c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return query;
455c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
456c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
457c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Remove query from the list. */
458c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    while (head != NULL && head->header.query_id != query_id) {
459c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        prev = head;
460c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        head = head->next;
461c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
462c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (head != NULL) {
463c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Query is found in the list. */
464c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQuery* const query = head;
465c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (prev == NULL) {
466c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Query is at the head of the list. */
467c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            assert(query == sdkctl->query_head);
468c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl->query_head = query->next;
469c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        } else {
470c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Query is in the middle, or at the end of the list. */
471c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            assert(query != sdkctl->query_head);
472c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            prev->next = query->next;
473c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
474c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (sdkctl->query_tail == query) {
475c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Query is at the tail of the list. */
476c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            assert(query->next == NULL);
477c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl->query_tail = prev;
478c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
479c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->next = NULL;
480c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return query;
481c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
482c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("%s: Query ID %d is not found in the list.",
483c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          sdkctl->service_name, query_id);
484c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return NULL;
485c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
486c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
487c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
488c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Pulls the first query from the list of active queries.
489c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
490c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  sdkctl - SDKCtlSocket instance that owns the query.
491c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Return:
492c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  A query removed pulled from the list of active queries, or NULL if query
493c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  list is empty.
494c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
495c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic SDKCtlQuery*
496c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_pull_first_query(SDKCtlSocket* sdkctl)
497c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
498c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = sdkctl->query_head;
499c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
500c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query != NULL) {
501c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->query_head = query->next;
502c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (sdkctl->query_head == NULL) {
503c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl->query_tail = NULL;
504c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
505c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
506c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query;
507c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
508c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
509c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Generates new query ID for the given SDKCtl. */
510c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic int
511c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_next_query_id(SDKCtlSocket* sdkctl)
512c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
513c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ++sdkctl->next_query_id;
514c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
515c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
516c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
517c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlPacket implementation
518c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
519c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
520c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Alocates a packet. */
521c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic SDKCtlPacket*
522c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_packet_new(SDKCtlSocket* sdkctl, int size, int type)
523c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
524c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    const uint32_t total_size = sizeof(SDKCtlPacket) + size;
525c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlPacket* const packet = _sdkctl_socket_alloc_recycler(sdkctl, total_size);
526c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
527c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    packet->sdkctl      = sdkctl;
528c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    packet->ref_count   = 1;
529c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    packet->header.size = size;
530c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    packet->header.type = type;
531c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
532c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Refence SDKCTlSocket that owns this packet. */
533c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_reference(sdkctl);
534c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
535c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return packet;
536c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
537c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
538c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Frees a packet. */
539c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
540c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_packet_free(SDKCtlPacket* packet)
541c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
542c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = packet->sdkctl;
543c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
544c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Free allocated resources. */
545c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_free_recycler(packet->sdkctl, packet);
546c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
547c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Release SDKCTlSocket that owned this packet. */
548c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_release(sdkctl);
549c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
550c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
551c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint
552c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_packet_reference(SDKCtlPacket* packet)
553c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
554c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(packet->ref_count > 0);
555c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    packet->ref_count++;
556c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return packet->ref_count;
557c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
558c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
559c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint
560c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_packet_release(SDKCtlPacket* packet)
561c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
562c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(packet->ref_count > 0);
563c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    packet->ref_count--;
564c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (packet->ref_count == 0) {
565c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Last reference has been dropped. Destroy this object. */
566c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_packet_free(packet);
567c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return 0;
568c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
569c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return packet->ref_count;
570c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
571c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
572c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
573c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                    SDKCtlQuery implementation
574c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
575c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
576c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Frees query descriptor. */
577c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
578c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_query_free(SDKCtlQuery* query)
579c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
580c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query != NULL) {
581c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlSocket* const sdkctl = query->sdkctl;
582c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        T("SDKCtl %s: Query %p ID %d is freed.",
583c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          sdkctl->service_name, query, query->header.query_id);
584c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
585c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Free allocated resources. */
586c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (query->internal_resp_buffer != NULL &&
587c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            (query->response_buffer == NULL ||
588c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine             query->response_buffer == &query->internal_resp_buffer)) {
589c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            free(query->internal_resp_buffer);
590c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
591c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
592c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        loopTimer_done(query->timer);
593c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_free_recycler(sdkctl, query);
594c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
595c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Release socket that owned this query. */
596c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_socket_release(sdkctl);
597c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
598c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
599c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
600c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Cancels timeout for the query.
601c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
602c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * For the simplicity of implementation, the dispatcher will cancel query timer
603c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * when query response data begins to flow in. If we let the timer to expire at
604c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * that stage, we will end up with data flowing in without real place to
605c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * accomodate it.
606c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
607c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
608c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_query_cancel_timeout(SDKCtlQuery* query)
609c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
610c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    loopTimer_stop(query->timer);
611c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
612c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Query %p ID %d deadline is cancelled.",
613c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query, query->header.query_id);
614c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
615c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
616c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/*
617c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Query I/O callbacks.
618c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
619c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
620c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Callback that is invoked by the I/O dispatcher when query is successfuly
621c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * completed (i.e. response to the query is received).
622c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
623c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
624c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_query_completed(SDKCtlQuery* query)
625c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
626c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Query %p ID %d is completed.",
627c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query, query->header.query_id);
628c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
629c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Cancel deadline, and inform the client about query completion. */
630c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_query_cancel_timeout(query);
631c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->query_cb(query->query_opaque, query, ASIO_STATE_SUCCEEDED);
632c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
633c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
634c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A callback that is invoked on query cancellation. */
635c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
636c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_query_cancelled(SDKCtlQuery* query)
637c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
638c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /*
639c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * Query cancellation means that SDK controller is disconnected. In turn,
640c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * this means that SDK controller socket will handle disconnection in its
641c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * connection callback. So, at this point all we need to do here is to inform
642c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * the client, and then unlist the query.
643c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     */
644c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
645c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Cancel deadline, and inform the client about query cancellation. */
646c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_query_cancel_timeout(query);
647c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->query_cb(query->query_opaque, query, ASIO_STATE_CANCELLED);
648c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
649c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
650c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A timer callback that is invoked on query timeout.
651c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
652c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  opaque - SDKCtlQuery instance.
653c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
654c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
655c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_skdctl_query_timeout(void* opaque)
656c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
657c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = (SDKCtlQuery*)opaque;
658c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
659c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("SDKCtl %s: Query %p ID %d with deadline %lld has timed out at %lld",
660c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query, query->header.query_id,
661c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->deadline, async_socket_deadline(query->sdkctl->as, 0));
662c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
663c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference the query while we're in this callback. */
664c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_reference(query);
665c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
666c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Inform the client about deadline expiration. Note that client may
667c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * extend the deadline, and retry the query. */
668c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    const AsyncIOAction action =
669c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->query_cb(query->query_opaque, query, ASIO_STATE_TIMED_OUT);
670c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
671c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* For actions other than retry we will destroy the query. */
672c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (action != ASIO_ACTION_RETRY) {
673c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_remove_query(query);
674c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
675c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
676c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_release(query);
677c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
678c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
679c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A callback that is invoked when query has been sent to the SDK controller
680c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * service. */
681c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
682c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_query_sent(SDKCtlQuery* query)
683c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
684c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: sent %d bytes of query %p ID %d of type %d",
685c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query->header.packet.size, query,
686c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->header.query_id, query->header.query_type);
687c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
688c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Inform the client about the event. */
689c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->query_cb(query->query_opaque, query, ASIO_STATE_CONTINUES);
690c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
691c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Set a timer to expire at query's deadline, and let the response to come
692c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * through the dispatcher loop. */
693c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    loopTimer_startAbsolute(query->timer, query->deadline);
694c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
695c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
696c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* An I/O callback invoked on query transmission.
697c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
698c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  io_opaque SDKCtlQuery instance of the query that's being sent with this I/O.
699c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  asio - Write I/O descriptor.
700c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  status - I/O status.
701c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
702c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
703c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_query_send_io(void* io_opaque,
704c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                         AsyncSocketIO* asio,
705c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                         AsyncIOState status)
706c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
707c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = (SDKCtlQuery*)io_opaque;
708c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    AsyncIOAction action = ASIO_ACTION_DONE;
709c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
710c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference the query while we're in this callback. */
711c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_reference(query);
712c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
713c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (status == ASIO_STATE_SUCCEEDED) {
714c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Query has been sent to the service. */
715c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _on_sdkctl_query_sent(query);
716c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
717c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
718c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
719c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return ASIO_ACTION_DONE;
720c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
721c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
722c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Lets see what's going on with query transmission. */
723c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    switch (status) {
724c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_CANCELLED:
725c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            T("SDKCtl %s: Query %p ID %d is cancelled in %s I/O.",
726c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              query->sdkctl->service_name, query, query->header.query_id,
727c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              async_socket_io_is_read(asio) ? "READ" : "WRITE");
728c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Remove the query from the list of active queries. */
729c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _sdkctl_socket_remove_query(query);
730c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _on_sdkctl_query_cancelled(query);
731c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
732c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
733c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_TIMED_OUT:
734c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            D("SDKCtl %s: Query %p ID %d with deadline %lld has timed out in %s I/O at %lld",
735c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              query->sdkctl->service_name, query, query->header.query_id,
736c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              query->deadline, async_socket_io_is_read(asio) ? "READ" : "WRITE",
737c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              async_socket_deadline(query->sdkctl->as, 0));
738c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Invoke query's callback. */
739c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = query->query_cb(query->query_opaque, query, status);
740c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* For actions other than retry we need to stop the query. */
741c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            if (action != ASIO_ACTION_RETRY) {
742c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _sdkctl_socket_remove_query(query);
743c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            }
744c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
745c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
746c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_FAILED:
747c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            T("SDKCtl %s: Query %p ID %d failed in %s I/O: %d -> %s",
748c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              query->sdkctl->service_name, query, query->header.query_id,
749c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              async_socket_io_is_read(asio) ? "READ" : "WRITE",
750c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              errno, strerror(errno));
751c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Invoke query's callback. Note that we will let the client to
752c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine             * decide what to do on I/O failure. */
753c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = query->query_cb(query->query_opaque, query, status);
754c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* For actions other than retry we need to stop the query. */
755c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            if (action != ASIO_ACTION_RETRY) {
756c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _sdkctl_socket_remove_query(query);
757c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            }
758c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
759c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
760c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_FINISHED:
761c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Time to disassociate with the I/O. */
762c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl_query_release(query);
763c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
764c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
765c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        default:
766c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Transitional state. */
767c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
768c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
769c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
770c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_release(query);
771c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
772c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return action;
773c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
774c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
775c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
776c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                    SDKCtlQuery public API implementation
777c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine ********************************************************************************/
778c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
779c8aa2c570d30098da59f1967d5158024ed28570dVladimir ChtchetkineSDKCtlQuery*
780c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_new(SDKCtlSocket* sdkctl, int query_type, uint32_t in_data_size)
781c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
782c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    const uint32_t total_size = sizeof(SDKCtlQuery) + in_data_size;
783c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
784c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = _sdkctl_socket_alloc_recycler(sdkctl, total_size);
785c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->next                 = NULL;
786c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->sdkctl               = sdkctl;
787c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->response_buffer      = NULL;
788c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->response_size        = NULL;
789c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->internal_resp_buffer = NULL;
790c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->internal_resp_size   = 0;
791c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->query_cb             = NULL;
792c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->query_opaque         = NULL;
793c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->deadline             = DURATION_INFINITE;
794c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->ref_count            = 1;
795c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->header.packet.size   = sizeof(SDKCtlQueryHeader) + in_data_size;
796c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->header.packet.type   = SDKCTL_PACKET_QUERY;
797c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->header.query_id      = _sdkctl_socket_next_query_id(sdkctl);
798c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->header.query_type    = query_type;
799c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
800c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Initialize timer to fire up on query deadline expiration. */
801c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    loopTimer_init(query->timer, sdkctl->looper, _on_skdctl_query_timeout, query);
802c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
803c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference socket that owns this query. */
804c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_reference(sdkctl);
805c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
806c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Query %p ID %d type %d is created for %d bytes of data.",
807c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query, query->header.query_id,
808c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query_type, in_data_size);
809c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
810c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query;
811c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
812c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
813c8aa2c570d30098da59f1967d5158024ed28570dVladimir ChtchetkineSDKCtlQuery*
814c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_new_ex(SDKCtlSocket* sdkctl,
815c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    int query_type,
816c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    uint32_t in_data_size,
817c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    const void* in_data,
818c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    void** response_buffer,
819c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    uint32_t* response_size,
820c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    on_sdkctl_query_cb query_cb,
821c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    void* query_opaque)
822c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
823c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = sdkctl_query_new(sdkctl, query_type, in_data_size);
824c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
825c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->response_buffer  = response_buffer;
826c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query->response_buffer == NULL) {
827c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Creator didn't supply a buffer. Use internal one instead. */
828c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->response_buffer = &query->internal_resp_buffer;
829c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->internal_resp_buffer = NULL;
830c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
831c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->response_size    = response_size;
832c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query->response_size == NULL) {
833c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Creator didn't supply a buffer for response size. Use internal one
834c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * instead. */
835c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->response_size = &query->internal_resp_size;
836c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->internal_resp_size = 0;
837c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
838c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->query_cb         = query_cb;
839c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->query_opaque     = query_opaque;
840c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Init query's input buffer. */
841c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (in_data_size != 0 && in_data != NULL) {
842c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        memcpy(query + 1, in_data, in_data_size);
843c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
844c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
845c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query;
846c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
847c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
848c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinevoid
849c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_send(SDKCtlQuery* query, int to)
850c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
851c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = query->sdkctl;
852c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
853c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Initialize the deadline. */
854c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->deadline = async_socket_deadline(query->sdkctl->as, to);
855c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
856c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* List the query in the list of active queries. */
857c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_add_query(query);
858c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
859c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference query associated with write I/O. */
860c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_reference(query);
861c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
862c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Transmit the query to SDK controller. */
863c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    async_socket_write_abs(sdkctl->as, &query->header, query->header.packet.size,
864c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                           _on_sdkctl_query_send_io, query, query->deadline);
865c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
866c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Query %p ID %d type %d is sent with deadline at %lld",
867c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query, query->header.query_id,
868c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->header.query_type, query->deadline);
869c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
870c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
871c8aa2c570d30098da59f1967d5158024ed28570dVladimir ChtchetkineSDKCtlQuery*
872c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_build_and_send(SDKCtlSocket* sdkctl,
873c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            int query_type,
874c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            uint32_t in_data_size,
875c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            const void* in_data,
876c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            void** response_buffer,
877c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            uint32_t* response_size,
878c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            on_sdkctl_query_cb query_cb,
879c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            void* query_opaque,
880c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            int to)
881c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
882c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query =
883c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_new_ex(sdkctl, query_type, in_data_size, in_data,
884c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            response_buffer, response_size, query_cb,
885c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            query_opaque);
886c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_send(query, to);
887c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query;
888c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
889c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
890c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint
891c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_reference(SDKCtlQuery* query)
892c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
893c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(query->ref_count > 0);
894c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->ref_count++;
895c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query->ref_count;
896c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
897c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
898c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint
899c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_release(SDKCtlQuery* query)
900c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
901c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(query->ref_count > 0);
902c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->ref_count--;
903c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query->ref_count == 0) {
904c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Last reference has been dropped. Destroy this object. */
905c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_query_free(query);
906c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return 0;
907c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
908c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query->ref_count;
909c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
910c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
911c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
912c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlPacket implementation
913c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
914c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
915c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A packet has been received from SDK controller. */
916c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
917c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_packet_received(SDKCtlSocket* sdkctl, SDKCtlPacket* packet)
918c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
919c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Received packet size: %d, type: %d",
920c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      sdkctl->service_name, packet->header.size, packet->header.type);
921c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
922c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Dispatch received packet to the client. */
923c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->on_message(sdkctl->opaque, sdkctl, packet, packet->header.type,
924c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                       packet + 1, packet->header.size - sizeof(SDKCtlPacketHeader));
925c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
926c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
927c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
928c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlIODispatcher implementation
929c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
930c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
931c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* An I/O callback invoked when data gets received from the socket.
932c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
933c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  io_opaque SDKCtlIODispatcher instance associated with the reader.
934c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  asio - Read I/O descriptor.
935c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  status - I/O status.
936c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
937c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction _on_sdkctl_io_dispatcher_io(void* io_opaque,
938c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                                 AsyncSocketIO* asio,
939c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                                 AsyncIOState status);
940c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
941c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Starts I/O dispatcher for SDK controller socket. */
942c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
943c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_io_dispatcher_start(SDKCtlSocket* sdkctl) {
944c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
945c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
946c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->state           = SDKCTL_IODISP_EXPECT_HEADER;
947c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->sdkctl          = sdkctl;
948c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->packet          = NULL;
949c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->current_query   = NULL;
950c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
951c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Register a packet header reader with the socket. */
952c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    async_socket_read_rel(dispatcher->sdkctl->as, &dispatcher->header,
953c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                          sizeof(SDKCtlPacketHeader), _on_sdkctl_io_dispatcher_io,
954c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                          dispatcher, -1);
955c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
956c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
957c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Resets I/O dispatcher for SDK controller socket. */
958c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
959c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_io_dispatcher_reset(SDKCtlSocket* sdkctl) {
960c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
961c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
962c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Cancel current query. */
963c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (dispatcher->current_query != NULL) {
964c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQuery* const query = dispatcher->current_query;
965c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->current_query = NULL;
966c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _on_sdkctl_query_cancelled(query);
967c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
968c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
969c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
970c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Free packet data buffer. */
971c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (dispatcher->packet != NULL) {
972c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_packet_release(dispatcher->packet);
973c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->packet = NULL;
974c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
975c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
976c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reset dispatcher state. */
977c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
978c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
979c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
980c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/*
981c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * I/O dispatcher callbacks.
982c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
983c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
984c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A callback that is invoked when a failure occurred while dispatcher was
985c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * reading data from the socket.
986c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
987c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
988c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_io_failure(SDKCtlIODispatcher* dispatcher,
989c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                             AsyncSocketIO* asio)
990c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
991c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
992c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
993c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("SDKCtl %s: Dispatcher I/O failure: %d -> %s",
994c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      sdkctl->service_name, errno, strerror(errno));
995c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
996c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* We treat all I/O failures same way we treat disconnection. Just cancel
997c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * everything, disconnect, and let the client to decide what to do next. */
998c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_disconnect(sdkctl);
999c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1000c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Report disconnection to the client, and let it restore connection in this
1001c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * callback. */
1002c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->on_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED);
1003c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1004c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1005c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A callback that is invoked when dispatcher's reader has been cancelled. */
1006c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1007c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_io_cancelled(SDKCtlIODispatcher* dispatcher,
1008c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                               AsyncSocketIO* asio)
1009c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1010c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Dispatcher I/O cancelled.", dispatcher->sdkctl->service_name);
1011c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1012c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* If we're in the middle of receiving query reply we need to cancel the
1013c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * query. */
1014c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (dispatcher->current_query != NULL) {
1015c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQuery* const query = dispatcher->current_query;
1016c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->current_query = NULL;
1017c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _on_sdkctl_query_cancelled(query);
1018c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
1019c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1020c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1021c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Discard packet data we've received so far. */
1022c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (dispatcher->packet != NULL) {
1023c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_packet_release(dispatcher->packet);
1024c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->packet = NULL;
1025c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1026c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1027c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1028c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A generic packet header has been received by I/O dispatcher. */
1029c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1030c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_packet_header(SDKCtlIODispatcher* dispatcher,
1031c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                AsyncSocketIO* asio)
1032c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1033c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1034c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1035c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Packet header type %d, size %d is received.",
1036c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      dispatcher->sdkctl->service_name, dispatcher->header.type,
1037c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      dispatcher->header.size);
1038c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1039c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Here we have three choices for the packet, that define the rest of
1040c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * the data that follow it:
1041c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * - Regular packet,
1042c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * - Response to a query that has been sent to SDK controller,
1043c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * - A query from SDK controller.
1044c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * Update the state accordingly, and initiate reading of the
1045c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * remaining of the packet.
1046c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     */
1047c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     if (dispatcher->header.type == SDKCTL_PACKET_QUERY_RESPONSE) {
1048c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* This is a response to the query. Before receiving response data we
1049c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * need to locate the relevant query, and use its response buffer to read
1050c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * the data. For that we need to obtain query ID firts. So, initiate
1051c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * reading of the remaining part of SDKCtlQueryReplyHeader. */
1052c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER;
1053c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_read_rel(sdkctl->as, &dispatcher->query_reply_header.query_id,
1054c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                              sizeof(SDKCtlQueryReplyHeader) - sizeof(SDKCtlPacketHeader),
1055c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                             _on_sdkctl_io_dispatcher_io, dispatcher, -1);
1056c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1057c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* For regular packets, as well as queries, we simply allocate buffer,
1058c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * that fits the entire packet, and read the remainder of the data in
1059c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * there. */
1060c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->state = SDKCTL_IODISP_EXPECT_DATA;
1061c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->packet =
1062c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _sdkctl_packet_new(sdkctl, dispatcher->header.size,
1063c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                               dispatcher->header.type);
1064c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Initiate reading of the packet data. */
1065c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_read_rel(sdkctl->as, dispatcher->packet + 1,
1066c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                              dispatcher->header.size - sizeof(SDKCtlPacketHeader),
1067c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                              _on_sdkctl_io_dispatcher_io, dispatcher, -1);
1068c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1069c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1070c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
1071c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1072c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1073c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A generic packet has been received by I/O dispatcher. */
1074c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1075c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_packet(SDKCtlIODispatcher* dispatcher, AsyncSocketIO* asio)
1076c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1077c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1078c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1079c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Packet type %d, size %d is received.",
1080c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      dispatcher->sdkctl->service_name, dispatcher->header.type,
1081c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      dispatcher->header.size);
1082c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1083c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _on_sdkctl_packet_received(sdkctl, dispatcher->packet);
1084c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_packet_release(dispatcher->packet);
1085c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->packet = NULL;
1086c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1087c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Get ready for the next I/O cycle. */
1088c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
1089c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    async_socket_read_rel(sdkctl->as, &dispatcher->header, sizeof(SDKCtlPacketHeader),
1090c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                          _on_sdkctl_io_dispatcher_io, dispatcher, -1);
1091c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
1092c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1093c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1094c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A query reply header has been received by I/O dispatcher. */
1095c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1096c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_query_reply_header(SDKCtlIODispatcher* dispatcher,
1097c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                     AsyncSocketIO* asio)
1098c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1099c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1100c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* query;
1101c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1102c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Query reply header is received for query ID %d",
1103c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      dispatcher->sdkctl->service_name, dispatcher->query_reply_header.query_id);
1104c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1105c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Pull the query out of the list of active queries. It's the dispatcher that
1106c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * owns this query now. */
1107c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->current_query =
1108c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_remove_query_id(sdkctl, dispatcher->query_reply_header.query_id);
1109c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query = dispatcher->current_query;
1110c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1111c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query == NULL) {
1112c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("%s: Query #%d is not found by dispatcher",
1113c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          dispatcher->sdkctl->service_name, dispatcher->query_reply_header.query_id);
1114c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1115c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Query is not found. Just read the remainder of reply up in the air,
1116c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * and then discard when it's over. */
1117c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA;
1118c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->packet =
1119c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _sdkctl_packet_new(sdkctl, dispatcher->header.size,
1120c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                               dispatcher->header.type);
1121c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Copy query reply info to the packet. */
1122c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        memcpy(&dispatcher->packet->header, &dispatcher->query_reply_header,
1123c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine               sizeof(SDKCtlQueryReplyHeader));
1124c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_read_rel(sdkctl->as, &dispatcher->query_header + 1,
1125c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                              dispatcher->header.size - sizeof(SDKCtlQueryReplyHeader),
1126c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                             _on_sdkctl_io_dispatcher_io, dispatcher, -1);
1127c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1128c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Prepare to receive query reply. For the simplicity sake, cancel query
1129c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * time out, so it doesn't expire on us while we're in the middle of
1130c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * receiving query's reply. */
1131c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_query_cancel_timeout(query);
1132c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1133c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Adjust the reply buffer set for the query (if needed). */
1134c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        const uint32_t query_data_size =
1135c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            dispatcher->header.size - sizeof(SDKCtlQueryReplyHeader);
1136c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (*query->response_size < query_data_size) {
1137c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            *query->response_buffer = malloc(query_data_size);
1138c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            if (*query->response_buffer == NULL) {
1139c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                APANIC("%s: Unable to allocate %d bytes for query response",
1140c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                       sdkctl->service_name, query_data_size);
1141c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            }
1142c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1143c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Save the actual query response size. */
1144c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        *query->response_size = query_data_size;
1145c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1146c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Start reading query response. */
1147c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA;
1148c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_read_rel(sdkctl->as, *query->response_buffer,
1149c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                              *query->response_size, _on_sdkctl_io_dispatcher_io,
1150c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                              dispatcher, -1);
1151c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1152c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1153c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
1154c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1155c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1156c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A query reply header has been received by I/O dispatcher. */
1157c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1158c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_query_reply(SDKCtlIODispatcher* dispatcher, AsyncSocketIO* asio)
1159c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1160c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1161c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = dispatcher->current_query;
1162c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->current_query = NULL;
1163c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1164c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query != NULL) {
1165c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _ANDROID_ASSERT(query->header.query_id == dispatcher->query_reply_header.query_id,
1166c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                        "SDKCtl %s: Query ID mismatch in I/O dispatcher",
1167c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                        sdkctl->service_name);
1168c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        T("SDKCtl %s: Query reply is received for query %p ID %d. Reply size is %d",
1169c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          dispatcher->sdkctl->service_name, query, query->header.query_id,
1170c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          *query->response_size);
1171c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1172c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Complete the query, and release it from the dispatcher. */
1173c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _on_sdkctl_query_completed(query);
1174c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
1175c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1176c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* This was "read up in the air" for a cancelled query. Just discard the
1177c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * read data. */
1178c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (dispatcher->packet != NULL) {
1179c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl_packet_release(dispatcher->packet);
1180c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            dispatcher->packet = NULL;
1181c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1182c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1183c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1184c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Get ready for the next I/O cycle. */
1185c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
1186c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    async_socket_read_rel(sdkctl->as, &dispatcher->header, sizeof(SDKCtlPacketHeader),
1187c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                          _on_sdkctl_io_dispatcher_io, dispatcher, -1);
1188c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
1189c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1190c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1191c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* An I/O callback invoked when data gets received from the socket.
1192c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * This is main I/O dispatcher loop.
1193c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
1194c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  io_opaque SDKCtlIODispatcher instance associated with the reader.
1195c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  asio - Read I/O descriptor.
1196c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  status - I/O status.
1197c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1198c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1199c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_io_dispatcher_io(void* io_opaque,
1200c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            AsyncSocketIO* asio,
1201c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            AsyncIOState status)
1202c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1203c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    AsyncIOAction action = ASIO_ACTION_DONE;
1204c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcher* const dispatcher = (SDKCtlIODispatcher*)io_opaque;
1205c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1206c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1207c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference SDKCtlSocket while we're in this callback. */
1208c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_reference(sdkctl);
1209c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1210c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (status != ASIO_STATE_SUCCEEDED) {
1211c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Something going on with I/O other than receiving data.. */
1212c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        switch (status) {
1213c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_STARTED:
1214c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* Data has started flowing in. Cancel timeout on I/O that has
1215c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 * started, so we can complete the current state of the
1216c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 * dispatcher without interruptions other than I/O failures. */
1217c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                async_socket_io_cancel_time_out(asio);
1218c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1219c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1220c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_FAILED:
1221c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* I/O failure has occurred. Handle the failure. */
1222c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _on_io_dispatcher_io_failure(dispatcher, asio);
1223c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1224c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1225c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_TIMED_OUT:
1226c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 /* The way I/O dispatcher is implemented, this should never
1227c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  * happen, because dispatcher doesn't set I/O expiration time
1228c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  * when registering its readers. */
1229c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _ANDROID_ASSERT(0,
1230c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    "SDKCtl %s: We should never receive ASIO_STATE_TIMED_OUT in SDKCtl I/O dispatcher.",
1231c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    sdkctl->service_name);
1232c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1233c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1234c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_CANCELLED:
1235c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* Cancellation means that we're in the middle of handling
1236c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 * disconnection. Sooner or later, this dispatcher will be reset,
1237c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 * so we don't really care about keeping its state at this point.
1238c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 */
1239c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _on_io_dispatcher_io_cancelled(dispatcher, asio);
1240c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1241c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1242c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_FINISHED:
1243c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1244c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1245c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            default:
1246c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _ANDROID_ASSERT(0, "SDKCtl %s: Unexpected I/O status %d in the dispatcher",
1247c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                sdkctl->service_name, status);
1248c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* Handle this as protocol failure. */
1249c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                errno = EINVAL;
1250c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _on_io_dispatcher_io_failure(dispatcher, asio);
1251c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                action = ASIO_ACTION_ABORT;
1252c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1253c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1254c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1255c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_socket_release(sdkctl);
1256c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1257c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return action;
1258c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1259c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1260c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Requested data has been read. Handle the chunk depending on dispatcher's
1261c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * state. */
1262c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    switch (dispatcher->state) {
1263c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case SDKCTL_IODISP_EXPECT_HEADER:
1264c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* A generic packet header is received. */
1265c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = _on_io_dispatcher_packet_header(dispatcher, asio);
1266c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1267c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1268c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER:
1269c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Query reply header is received. */
1270c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = _on_io_dispatcher_query_reply_header(dispatcher, asio);
1271c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1272c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1273c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA:
1274c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Query reply is received. Complete the query. */
1275c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = _on_io_dispatcher_query_reply(dispatcher, asio);
1276c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1277c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1278c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case SDKCTL_IODISP_EXPECT_DATA:
1279c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* A generic packet is received. */
1280c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = _on_io_dispatcher_packet(dispatcher, asio);
1281c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1282c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1283c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        default:
1284c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _ANDROID_ASSERT(0, "SDKCtl %s: Unexpected I/O dispacher state %d",
1285c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            sdkctl->service_name, dispatcher->state);
1286c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1287c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1288c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1289c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_release(sdkctl);
1290c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1291c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return action;
1292c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1293c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1294c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1295c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                       SDKCtlSocket internals.
1296c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
1297c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1298c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Cancels all queries that is active on this socket. */
1299c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1300c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_cancel_all_queries(SDKCtlSocket* sdkctl)
1301c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1302c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
1303c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* query;
1304c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1305c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Cancel query that is being completed in dispatcher. */
1306c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (dispatcher->current_query != NULL) {
1307c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQuery* const query = dispatcher->current_query;
1308c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->current_query = NULL;
1309c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _on_sdkctl_query_cancelled(query);
1310c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
1311c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1312c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1313c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* One by one empty query list cancelling pulled queries. */
1314c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query = _sdkctl_socket_pull_first_query(sdkctl);
1315c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    while (query != NULL) {
1316c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_query_cancel_timeout(query);
1317c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->query_cb(query->query_opaque, query, ASIO_STATE_CANCELLED);
1318c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
1319c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query = _sdkctl_socket_pull_first_query(sdkctl);
1320c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1321c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1322c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1323c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Cancels all packets that is active on this socket. */
1324c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1325c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_cancel_all_packets(SDKCtlSocket* sdkctl)
1326c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1327c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1328c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1329c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Cancels all I/O that is active on this socket. */
1330c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1331c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_cancel_all_io(SDKCtlSocket* sdkctl)
1332c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1333c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Cancel all queries, and packets that are active for this I/O. */
1334c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_cancel_all_queries(sdkctl);
1335c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_cancel_all_packets(sdkctl);
1336c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1337c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1338c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Disconnects AsyncSocket for SDKCtlSocket. */
1339c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1340c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_disconnect_socket(SDKCtlSocket* sdkctl)
1341c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1342c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->as != NULL) {
1343c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Disconnect the socket. This will trigger I/O cancellation callbacks. */
1344c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_disconnect(sdkctl->as);
1345c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1346c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Cancel all I/O that is active on this socket. */
1347c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_cancel_all_io(sdkctl);
1348c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1349c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Reset I/O dispatcher. */
1350c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_io_dispatcher_reset(sdkctl);
1351c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1352c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1353c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->state = SDKCTL_SOCKET_DISCONNECTED;
1354c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1355c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1356c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Frees SDKCtlSocket instance. */
1357c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1358c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_free(SDKCtlSocket* sdkctl)
1359c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1360c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl != NULL) {
1361c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Disconnect, and release the socket. */
1362c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (sdkctl->as != NULL) {
1363c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            async_socket_disconnect(sdkctl->as);
1364c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            async_socket_release(sdkctl->as);
1365c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1366c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1367c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Free allocated resources. */
1368c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (sdkctl->looper != NULL) {
1369c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            looper_free(sdkctl->looper);
1370c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1371c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (sdkctl->service_name != NULL) {
1372c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            free(sdkctl->service_name);
1373c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1374c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_empty_recycler(sdkctl);
1375c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1376c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        AFREE(sdkctl);
1377c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1378c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1379c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1380c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1381c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                    SDK Control Socket connection callbacks.
1382c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
1383c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1384c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Initiates handshake query when SDK controller socket is connected. */
1385c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void _sdkctl_do_handshake(SDKCtlSocket* sdkctl);
1386c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1387c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A socket connection is established.
1388c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Here we will start I/O dispatcher, and will initiate a handshake with
1389c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * the SdkController service for this socket. */
1390c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1391c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_async_socket_connected(SDKCtlSocket* sdkctl)
1392c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1393c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("SDKCtl %s: Socket is connected.", sdkctl->service_name);
1394c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1395c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Notify the client that connection is established. */
1396c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    const AsyncIOAction action =
1397c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->on_connection(sdkctl->opaque, sdkctl, ASIO_STATE_SUCCEEDED);
1398c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1399c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (action == ASIO_ACTION_DONE) {
1400c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Initialize, and start main I/O dispatcher. */
1401c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_io_dispatcher_start(sdkctl);
1402c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1403c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Initiate handshake. */
1404c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_do_handshake(sdkctl);
1405c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1406c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return action;
1407c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1408c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Client didn't like something about this connection. */
1409c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return action;
1410c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1411c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1412c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1413c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Handles lost connection with SdkController service. */
1414c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1415c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_async_socket_disconnected(SDKCtlSocket* sdkctl)
1416c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1417c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("SDKCtl %s: Socket has been disconnected.", sdkctl->service_name);
1418c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1419c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_disconnect_socket(sdkctl);
1420c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1421c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    AsyncIOAction action = sdkctl->on_connection(sdkctl->opaque, sdkctl,
1422c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                                 ASIO_STATE_FAILED);
1423c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (action == ASIO_ACTION_DONE) {
1424c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Default action for disconnect is to reestablish the connection. */
1425c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        action = ASIO_ACTION_RETRY;
1426c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1427c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (action == ASIO_ACTION_RETRY) {
1428c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->state = SDKCTL_SOCKET_CONNECTING;
1429c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1430c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return action;
1431c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1432c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1433c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* An entry point for all socket connection events.
1434c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Here we will dispatch connection events to appropriate handlers.
1435c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
1436c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  client_opaque - SDKCtlSocket isntance.
1437c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1438c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1439c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_async_socket_connection(void* client_opaque,
1440c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            AsyncSocket* as,
1441c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            AsyncIOState status)
1442c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1443c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    AsyncIOAction action = ASIO_ACTION_DONE;
1444c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = (SDKCtlSocket*)client_opaque;
1445c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1446c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference the socket while in this callback. */
1447c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_reference(sdkctl);
1448c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1449c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    switch (status) {
1450c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_SUCCEEDED:
1451c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl->state = SDKCTL_SOCKET_CONNECTED;
1452c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _on_async_socket_connected(sdkctl);
1453c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1454c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1455c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_FAILED:
1456c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            if (sdkctl->state == SDKCTL_SOCKET_CONNECTED) {
1457c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* This is disconnection condition. */
1458c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                action = _on_async_socket_disconnected(sdkctl);
1459c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            } else {
1460c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* An error has occurred while attempting to connect to socket.
1461c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 * Lets try again... */
1462c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                action = ASIO_ACTION_RETRY;
1463c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            }
1464c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1465c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1466c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_RETRYING:
1467c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        default:
1468c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = ASIO_ACTION_RETRY;
1469c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1470c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1471c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1472c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_release(sdkctl);
1473c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1474c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return action;
1475c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1476c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1477c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1478c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDK Control Socket public API
1479c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
1480c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1481c8aa2c570d30098da59f1967d5158024ed28570dVladimir ChtchetkineSDKCtlSocket*
1482c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_socket_new(int reconnect_to,
1483c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  const char* service_name,
1484c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  on_sdkctl_connection_cb on_connection,
1485c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  on_sdkctl_handshake_cb on_handshake,
1486c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  on_sdkctl_message_cb on_message,
1487c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  void* opaque)
1488c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1489c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* sdkctl;
1490c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    ANEW0(sdkctl);
1491c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1492c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->state               = SDKCTL_SOCKET_DISCONNECTED;
1493c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->opaque              = opaque;
1494c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->service_name        = ASTRDUP(service_name);
1495c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->on_connection       = on_connection;
1496c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->on_handshake        = on_handshake;
1497c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->on_message          = on_message;
1498c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->reconnect_to        = reconnect_to;
1499c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->as                  = NULL;
1500c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->next_query_id       = 0;
1501c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->query_head          = sdkctl->query_tail = NULL;
1502c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->ref_count           = 1;
1503c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler            = NULL;
1504c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_block_size = 0;
1505c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_max        = 0;
1506c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_count      = 0;
1507c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1508c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->looper = looper_newCore();
1509c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->looper == NULL) {
1510c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        E("Unable to create I/O looper for SDKCtl socket '%s'",
1511c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          service_name);
1512c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        on_connection(opaque, sdkctl, ASIO_STATE_FAILED);
1513c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_free(sdkctl);
1514c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return NULL;
1515c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1516c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1517c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return sdkctl;
1518c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1519c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1520c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint sdkctl_socket_reference(SDKCtlSocket* sdkctl)
1521c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1522c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(sdkctl->ref_count > 0);
1523c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->ref_count++;
1524c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return sdkctl->ref_count;
1525c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1526c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1527c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint
1528c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_socket_release(SDKCtlSocket* sdkctl)
1529c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1530c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(sdkctl->ref_count > 0);
1531c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->ref_count--;
1532c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->ref_count == 0) {
1533c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Last reference has been dropped. Destroy this object. */
1534c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_free(sdkctl);
1535c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return 0;
1536c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1537c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return sdkctl->ref_count;
1538c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1539c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1540c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinevoid
1541c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_init_recycler(SDKCtlSocket* sdkctl,
1542c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                     uint32_t data_size,
1543c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                     int max_recycled_num)
1544c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1545c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->recycler != NULL) {
1546c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("SDKCtl %s: Recycler is already initialized. Ignoring recycler init.",
1547c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          sdkctl->service_name);
1548c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return;
1549c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1550c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1551c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* SDKCtlQuery is max descriptor sizeof. */
1552c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    data_size += sizeof(SDKCtlQuery);
1553c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1554c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_block_size = data_size;
1555c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_max        = max_recycled_num;
1556c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_count      = 0;
1557c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1558c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1559c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinevoid
1560c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_socket_connect(SDKCtlSocket* sdkctl, int port, int retry_to)
1561c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1562c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Handling connect request to port %d, retrying in %dms...",
1563c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      sdkctl->service_name, port, retry_to);
1564c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1565c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->state = SDKCTL_SOCKET_CONNECTING;
1566c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->as = async_socket_new(port, sdkctl->reconnect_to,
1567c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                  _on_async_socket_connection, sdkctl,
1568c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                  sdkctl->looper);
1569c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->as == NULL) {
1570c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        E("Unable to allocate AsyncSocket for SDKCtl socket '%s'",
1571c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine           sdkctl->service_name);
1572c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->on_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED);
1573c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1574c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_connect(sdkctl->as, retry_to);
1575c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1576c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1577c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1578c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinevoid
1579c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_socket_reconnect(SDKCtlSocket* sdkctl, int port, int retry_to)
1580c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1581c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Handling reconnection request to port %d, retrying in %dms...",
1582c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      sdkctl->service_name, port, retry_to);
1583c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1584c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_disconnect_socket(sdkctl);
1585c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1586c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->as == NULL) {
1587c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_socket_connect(sdkctl, port, retry_to);
1588c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1589c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->state = SDKCTL_SOCKET_CONNECTING;
1590c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_reconnect(sdkctl->as, retry_to);
1591c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1592c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1593c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1594c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinevoid
1595c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_socket_disconnect(SDKCtlSocket* sdkctl)
1596c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1597c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Handling disconnect request.", sdkctl->service_name);
1598c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1599c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_disconnect_socket(sdkctl);
1600c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1601c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1602c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1603c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1604c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                       Handshake query
1605c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
1606c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1607c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A callback that is ivoked on handshake I/O events. */
1608c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1609c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_handshake_io(void* query_opaque,
1610c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 SDKCtlQuery* query,
1611c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 AsyncIOState status)
1612c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1613c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = (SDKCtlSocket*)query_opaque;
1614c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1615c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (status == ASIO_STATE_SUCCEEDED) {
1616c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("SDKCtl %s: %d bytes of handshake reply is received.",
1617c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          sdkctl->service_name, *query->response_size);
1618c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1619c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Handshake is received. Inform the client. */
1620c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->on_handshake(sdkctl->opaque, sdkctl, *query->response_buffer,
1621c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                             *query->response_size, status);
1622c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1623c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Something is going on with the handshake... */
1624c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        switch (status) {
1625c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_FAILED:
1626c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_TIMED_OUT:
1627c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_CANCELLED:
1628c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              D("SDKCtl %s: Handshake failed: I/O state %d. Error: %d -> %s",
1629c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                sdkctl->service_name, status, errno, strerror(errno));
1630c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                sdkctl->on_handshake(sdkctl->opaque, sdkctl,
1631c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                     *query->response_buffer,
1632c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                     *query->response_size, status);
1633c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1634c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1635c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            default:
1636c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1637c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1638c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1639c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
1640c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1641c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1642c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1643c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_endianness_io(void* io_opaque,
1644c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                         AsyncSocketIO* asio,
1645c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                         AsyncIOState status) {
1646c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = (SDKCtlSocket*)io_opaque;
1647c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1648c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (status == ASIO_STATE_SUCCEEDED) {
1649c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Now it's time to initiate handshake message. */
1650c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("SDKCtl %s: Sending handshake query...", sdkctl->service_name);
1651c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQuery* query =
1652c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl_query_build_and_send(sdkctl, SDKCTL_QUERY_HANDSHAKE,
1653c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                        strlen(sdkctl->service_name),
1654c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                        sdkctl->service_name, NULL, NULL,
1655c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                        _on_handshake_io, sdkctl, 3000);
1656c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
1657c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return ASIO_ACTION_DONE;
1658c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1659c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Something is going on with the endianness... */
1660c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        switch (status) {
1661c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                case ASIO_STATE_FAILED:
1662c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                case ASIO_STATE_TIMED_OUT:
1663c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                case ASIO_STATE_CANCELLED:
1664c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  D("SDKCtl %s: endianness failed: I/O state %d. Error: %d -> %s",
1665c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    sdkctl->service_name, status, errno, strerror(errno));
1666c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    sdkctl->on_handshake(sdkctl->opaque, sdkctl, NULL, 0, status);
1667c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    break;
1668c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1669c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                default:
1670c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    break;
1671c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1672c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1673c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
1674c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1675c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1676c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1677c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_do_handshake(SDKCtlSocket* sdkctl)
1678c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1679c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#ifndef HOST_WORDS_BIGENDIAN
1680c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic const char _host_end = 0;
1681c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#else
1682c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic const char _host_end = 1;
1683c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#endif
1684c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1685c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("SDKCtl %s: Sending endianness: %d...", sdkctl->service_name, _host_end);
1686c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1687c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Before we can send any structured data to the SDK controller we need to
1688c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * report endianness of the host. */
1689c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    async_socket_write_rel(sdkctl->as, &_host_end, 1,
1690c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                           _on_sdkctl_endianness_io, sdkctl, 3000);
1691c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1692