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 "android/utils/debug.h"
24c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "android/async-socket-connector.h"
25c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "android/async-socket.h"
26c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "android/sdk-controller-socket.h"
27c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#include "utils/panic.h"
28d413fa5f2916a2a46494edb320340486b262644cDavid 'Digit' Turner#include "android/iolooper.h"
29c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
30c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  E(...)    derror(__VA_ARGS__)
31c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  W(...)    dwarning(__VA_ARGS__)
32c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  D(...)    VERBOSE_PRINT(sdkctlsocket,__VA_ARGS__)
33c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  D_ACTIVE  VERBOSE_CHECK(sdkctlsocket)
34c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
357136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine#define TRACE_ON    0
36c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
37c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#if TRACE_ON
38c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  T(...)    VERBOSE_PRINT(sdkctlsocket,__VA_ARGS__)
39c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#else
40c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  T(...)
41c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#endif
42c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
43c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Recycling memory descriptor. */
44c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef struct SDKCtlRecycled SDKCtlRecycled;
45c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestruct SDKCtlRecycled {
46c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    union {
47c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Next recycled descriptor (while listed in recycler). */
48c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlRecycled* next;
49c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Allocated memory size (while outside of the recycler). */
50c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        uint32_t        size;
51c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    };
52c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine};
53c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
54c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/*
557136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * Types of the data packets sent via SDK controller socket.
56c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
57c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
58c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* The packet is a message. */
59c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define SDKCTL_PACKET_MESSAGE           1
60c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* The packet is a query. */
61c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define SDKCTL_PACKET_QUERY             2
62c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* The packet is a response to a query. */
63c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define SDKCTL_PACKET_QUERY_RESPONSE    3
64c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/*
667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * Types of intenal port messages sent via SDK controller socket.
677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Port is connected.
707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * This message is sent by SDK controller when the service connects a socket with
717136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * a port that provides requested emulation functionality.
727136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
737136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine#define SDKCTL_MSG_PORT_CONNECTED       -1
747136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Port is disconnected.
757136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * This message is sent by SDK controller when a port that provides requested
767136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * emulation functionality disconnects from the socket.
777136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
787136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine#define SDKCTL_MSG_PORT_DISCONNECTED    -2
797136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Port is enabled.
807136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * This message is sent by SDK controller when a port that provides requested
817136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * emulation functionality is ready to do the emulation.
827136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
837136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine#define SDKCTL_MSG_PORT_ENABLED         -3
847136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Port is disabled.
857136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * This message is sent by SDK controller when a port that provides requested
867136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * emulation functionality is not ready to do the emulation.
877136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
887136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine#define SDKCTL_MSG_PORT_DISABLED        -4
897136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
907136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/*
917136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * Types of internal queries sent via SDK controller socket.
927136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
937136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
947136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Handshake query.
957136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * This query is sent to SDK controller service as part of the connection
967136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * protocol implementation.
977136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
987136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine#define SDKCTL_QUERY_HANDSHAKE          -1
997136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
1007136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/********************************************************************************
1017136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *                      SDKCtlPacket declarations
1027136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *******************************************************************************/
1037136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
1047136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Packet signature value ('SDKC'). */
1057136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinestatic const int _sdkctl_packet_sig = 0x53444B43;
1067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
107c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Data packet descriptor.
108c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
109c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * All packets, sent and received via SDK controller socket begin with this
110c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * header, with packet data immediately following this header.
111c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
112c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef struct SDKCtlPacketHeader {
1137136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Signature. */
1147136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    int     signature;
115c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Total size of the data to transfer with this packet, including this
116c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * header. The transferring data should immediatelly follow this header. */
117c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int     size;
118c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Encodes packet type. See SDKCTL_PACKET_XXX for the list of packet types
119c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * used by SDK controller. */
120c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int     type;
121c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlPacketHeader;
122c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
123c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Packet descriptor, allocated by this API for data packets to be sent to SDK
1247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * controller.
125c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
126c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * When packet descriptors are allocated by this API, they are allocated large
127c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * enough to contain this header, and packet data to send to the service,
128c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * immediately following this descriptor.
129c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1307136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinetypedef struct SDKCtlPacket {
131c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Supports recycling. Don't put anything in front: recycler expects this
132c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * to be the first field in recyclable descriptor. */
1337136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlRecycled          recycling;
134c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
135c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* SDK controller socket that transmits this packet. */
1367136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlSocket*           sdkctl;
137c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Number of outstanding references to the packet. */
1387136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    int                     ref_count;
139c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
140c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Common packet header. Packet data immediately follows this header, so it
1417136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine     * must be the last field in SDKCtlPacket descriptor. */
1427136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlPacketHeader      header;
1437136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine} SDKCtlPacket;
144c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
145c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1467136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *                      SDKCtlDirectPacket declarations
147c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
148c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1497136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Direct packet descriptor, allocated by this API for direct data packets to be
1507136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * sent to SDK controller service on the device.
1517136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *
1527136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * Direct packet (unlike SDKCtlPacket) don't contain data buffer, but rather
1537136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * reference data allocated by the client. This is useful when client sends large
1547136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * amount of data (such as framebuffer updates sent my multi-touch port), and
1557136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * regular packet descriptors for such large transfer cannot be obtained from the
1567136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * recycler.
157c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinestruct SDKCtlDirectPacket {
1597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Supports recycling. Don't put anything in front: recycler expects this
1607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine     * to be the first field in recyclable descriptor. */
1617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlRecycled          recycling;
162c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1637136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* SDKCtlSocket that owns this packet. */
1647136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlSocket*           sdkctl;
1657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Packet to send. */
1667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlPacketHeader*     packet;
1677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Callback to invoke on packet transmission events. */
1687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    on_sdkctl_direct_cb     on_sent;
1697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* An opaque pointer to pass to on_sent callback. */
1707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    void*                   on_sent_opaque;
1717136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Number of outstanding references to the packet. */
1727136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    int                     ref_count;
1737136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine};
1747136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
1757136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/********************************************************************************
1767136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *                      SDKCtlQuery declarations
1777136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *******************************************************************************/
178c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
179c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Query packet descriptor.
180c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
181c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * All queries, sent and received via SDK controller socket begin with this
182c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * header, with query data immediately following this header.
183c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
184c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef struct SDKCtlQueryHeader {
185c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Data packet header for this query. */
186c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlPacketHeader  packet;
187c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A unique query identifier. This ID is used to track the query in the
188c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * asynchronous environment in whcih SDK controller socket operates. */
189c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                 query_id;
1907136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Query type. */
191c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                 query_type;
192c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlQueryHeader;
193c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
194c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Query descriptor, allocated by this API for queries to be sent to SDK
195c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * controller service on the device.
196c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
197c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * When query descriptors are allocated by this API, they are allocated large
198c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * enough to contain this header, and query data to send to the service,
199c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * immediately following this descriptor.
200c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
201c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestruct SDKCtlQuery {
202c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Supports recycling. Don't put anything in front: recycler expects this
203c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * to be the first field in recyclable descriptor. */
204c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlRecycled          recycling;
205c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Next query in the list of active queries. */
207c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery*            next;
208c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A timer to run time out on this query after it has been sent. */
209c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    LoopTimer               timer[1];
210c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Absolute time for this query's deadline. This is the value that query's
2117136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine     * timer is set to after query has been transmitted to the service. */
212c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    Duration                deadline;
213c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* SDK controller socket that owns the query. */
214c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket*           sdkctl;
215c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A callback to invoke on query state changes. */
216c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    on_sdkctl_query_cb      query_cb;
217c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* An opaque pointer associated with this query. */
218c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    void*                   query_opaque;
219c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Points to an address of a buffer where to save query response. */
220c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    void**                  response_buffer;
2217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Points to a variable containing size of the response buffer (on the way
2227136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine     * in), or actual query response size (when query is completed). */
223c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    uint32_t*               response_size;
224c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Internal response buffer, allocated if query creator didn't provide its
225c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * own. This field is valid only if response_buffer field is NULL, or is
226c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * pointing to this field. */
227c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    void*                   internal_resp_buffer;
2287136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Internal response buffer size used if query creator didn't provide its
2297136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine     * own. This field is valid only if response_size field is NULL, or is
2307136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine     * pointing to this field. */
231c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    uint32_t                internal_resp_size;
232c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Number of outstanding references to the query. */
233c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                     ref_count;
234c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2357136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Common query header. Query data immediately follows this header, so it
236c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * must be last field in SDKCtlQuery descriptor. */
237c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQueryHeader       header;
238c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine};
239c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
240c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Query reply descriptor.
241c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
242c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * All replies to a query, sent and received via SDK controller socket begin with
243c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * this header, with query reply data immediately following this header.
244c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
245c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef struct SDKCtlQueryReplyHeader {
246c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Data packet header for this reply. */
247c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlPacketHeader  packet;
248c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
249c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* An identifier for the query that is addressed with this reply. */
250c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                 query_id;
251c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlQueryReplyHeader;
252c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
253c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
2547136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *                      SDKCtlMessage declarations
2557136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *******************************************************************************/
2567136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
2577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Message packet descriptor.
2587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *
2597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * All messages, sent and received via SDK controller socket begin with this
2607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * header, with message data immediately following this header.
2617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
2627136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinetypedef struct SDKCtlMessageHeader {
2637136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Data packet header for this query. */
2647136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlPacketHeader  packet;
2657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Message type. */
2667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    int                 msg_type;
2677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine} SDKCtlMessageHeader;
2687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
2697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Message packet descriptor.
2707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *
2717136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * All messages, sent and received via SDK controller socket begin with this
2727136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * header, with message data immediately following this header.
2737136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
2744732aee0622005bc612f75d0319e6e3a057301b4Vladimir Chtchetkinestruct SDKCtlMessage {
2757136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Data packet descriptor for this message. */
2767136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlPacket  packet;
2777136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Message type. */
2787136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    int           msg_type;
2794732aee0622005bc612f75d0319e6e3a057301b4Vladimir Chtchetkine};
2807136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
2817136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/********************************************************************************
282c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDK Control Socket declarations
283c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
284c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
285c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Enumerates SDKCtlSocket states. */
286c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef enum SDKCtlSocketState {
287c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Socket is disconnected from SDK controller. */
288c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_SOCKET_DISCONNECTED,
289c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Connection to SDK controller is in progress. */
290c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_SOCKET_CONNECTING,
291c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Socket is connected to an SDK controller service. */
292c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_SOCKET_CONNECTED
293c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlSocketState;
294c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
295c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Enumerates SDKCtlSocket I/O dispatcher states. */
296c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef enum SDKCtlIODispatcherState {
297c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O dispatcher expects a packet header. */
298c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_IODISP_EXPECT_HEADER,
299c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O dispatcher expects packet data. */
300c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_IODISP_EXPECT_DATA,
301c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O dispatcher expects query response header. */
302c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER,
303c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O dispatcher expects query response data. */
304c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA,
305c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlIODispatcherState;
306c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
307c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* SDKCtlSocket I/O dispatcher descriptor. */
308c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinetypedef struct SDKCtlIODispatcher {
309c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* SDKCtlSocket instance for this dispatcher. */
310c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket*               sdkctl;
311c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Dispatcher state. */
312c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcherState     state;
313c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Unites all types of headers used in SDK controller data exchange. */
314c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    union {
315c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Common packet header. */
3167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        SDKCtlPacketHeader      packet_header;
317c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Header for a query packet. */
318c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQueryHeader       query_header;
3197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Header for a message packet. */
3207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        SDKCtlMessageHeader     message_header;
321c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Header for a query response packet. */
322c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQueryReplyHeader  query_reply_header;
323c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    };
3247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Descriptor of a packet that is being received from SDK controller. */
325c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlPacket*               packet;
326c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A query for which a reply is currently being received. */
327c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery*                current_query;
328c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine} SDKCtlIODispatcher;
329c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
330c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* SDK controller socket descriptor. */
331c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestruct SDKCtlSocket {
332c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* SDK controller socket state */
3337136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlSocketState               state;
3347136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* SDK controller port status */
3357136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SdkCtlPortStatus                port_status;
336c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O dispatcher for the socket. */
3377136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlIODispatcher              io_dispatcher;
338c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Asynchronous socket connected to SDK Controller on the device. */
3397136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    AsyncSocket*                    as;
340c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Client callback that monitors this socket connection. */
3417136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    on_sdkctl_socket_connection_cb  on_socket_connection;
3427136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Client callback that monitors SDK controller prt connection. */
3437136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    on_sdkctl_port_connection_cb    on_port_connection;
344c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* A callback to invoke when a message is received from the SDK controller. */
3457136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    on_sdkctl_message_cb            on_message;
346c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* An opaque pointer associated with this socket. */
3477136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    void*                           opaque;
3487136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Name of an SDK controller port this socket is connected to. */
3497136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    char*                           service_name;
350c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* I/O looper for timers. */
3517136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    Looper*                         looper;
352c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Head of the active query list. */
3537136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlQuery*                    query_head;
354c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Tail of the active query list. */
3557136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlQuery*                    query_tail;
356c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Query ID generator that gets incremented for each new query. */
3577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    int                             next_query_id;
358c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Timeout before trying to reconnect after disconnection. */
3597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    int                             reconnect_to;
360c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Number of outstanding references to this descriptor. */
3617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    int                             ref_count;
362c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Head of the recycled memory */
3637136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlRecycled*                 recycler;
364c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Recyclable block size. */
3657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    uint32_t                        recycler_block_size;
366c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Maximum number of blocks to recycle. */
3677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    int                             recycler_max;
368c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Number of blocs in the recycler. */
3697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    int                             recycler_count;
370c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine};
371c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
372c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
373c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlSocket recycling management
374c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
375c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
376c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Gets a recycled block for a given SDKCtlSocket, or allocates new memory
377c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * block. */
378c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void*
379c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_alloc_recycler(SDKCtlSocket* sdkctl, uint32_t size)
380c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
381c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlRecycled* block = NULL;
382c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
383c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->recycler != NULL && size <= sdkctl->recycler_block_size) {
3847136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        assert(sdkctl->recycler_count > 0);
385c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* There are blocks in the recycler, and requested size fits. */
386c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block = sdkctl->recycler;
387c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->recycler = block->next;
388c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block->size = sdkctl->recycler_block_size;
389c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->recycler_count--;
390c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else if (size <= sdkctl->recycler_block_size) {
3917136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* There are no blocks in the recycler, but requested size fits. Lets
3927136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine         * allocate block that we can later recycle. */
393c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block = malloc(sdkctl->recycler_block_size);
394c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (block == NULL) {
3957136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            APANIC("SDKCtl %s: Unable to allocate %d bytes block.",
396c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                   sdkctl->service_name, sdkctl->recycler_block_size);
397c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
398c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block->size = sdkctl->recycler_block_size;
399c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
400c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Requested size doesn't fit the recycler. */
401c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block = malloc(size);
402c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (block == NULL) {
403c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            APANIC("SDKCtl %s: Unable to allocate %d bytes block",
404c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                   sdkctl->service_name, size);
405c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
406c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block->size = size;
407c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
408c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
409c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return block;
410c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
411c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
412c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Recycles, or frees a block of memory for a given SDKCtlSocket. */
413c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
414c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_free_recycler(SDKCtlSocket* sdkctl, void* mem)
415c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
4167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlRecycled* const block = (SDKCtlRecycled*)mem;
417c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
4187136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (block->size != sdkctl->recycler_block_size ||
4197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->recycler_count == sdkctl->recycler_max) {
4207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Recycler is full, or block cannot be recycled. Just free the memory. */
421c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        free(mem);
4227136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    } else {
4237136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Add that block to the recycler. */
4247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        assert(sdkctl->recycler_count >= 0);
4257136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        block->next = sdkctl->recycler;
4267136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->recycler = block;
4277136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->recycler_count++;
428c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
429c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
430c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
431c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Empties the recycler for a given SDKCtlSocket. */
432c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
433c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_empty_recycler(SDKCtlSocket* sdkctl)
434c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
435c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlRecycled* block = sdkctl->recycler;
436c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    while (block != NULL) {
4377136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        void* const to_free = block;
438c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        block = block->next;
439c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        free(to_free);
440c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
441c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler = NULL;
442c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_count = 0;
443c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
444c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
445c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
446c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlSocket query list management
447c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
448c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
449c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Adds a query to the list of active queries.
450c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
451c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  sdkctl - SDKCtlSocket instance for the query.
452c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  query - Query to add to the list.
453c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
454c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
455c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_add_query(SDKCtlQuery* query)
456c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
457c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = query->sdkctl;
458c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->query_head == NULL) {
4597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        assert(sdkctl->query_tail == NULL);
460c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->query_head = sdkctl->query_tail = query;
461c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
462c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->query_tail->next = query;
463c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->query_tail = query;
464c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
465c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
466c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Keep the query referenced while it's in the list. */
467c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_reference(query);
468c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
469c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
470c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Removes a query from the list of active queries.
471c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
4727136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  query - Query to remove from the list of active queries. If query has been
4737136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *      removed from the list, it will be dereferenced to offset the reference
4747136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *      that wad made when the query has been added to the list.
475c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Return:
476c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  Boolean: 1 if query has been removed, or 0 if query has not been found in the
477c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  list of active queries.
478c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
479c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic int
480c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_remove_query(SDKCtlQuery* query)
481c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
482c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = query->sdkctl;
483c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* prev = NULL;
484c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* head = sdkctl->query_head;
485c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
4867136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Quick check: the query could be currently handled by the dispatcher. */
487c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->io_dispatcher.current_query == query) {
488c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Release the query from dispatcher. */
489c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->io_dispatcher.current_query = NULL;
4907136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl_query_release(query);
491c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return 1;
492c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
493c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
494c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Remove query from the list. */
495c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    while (head != NULL && query != head) {
496c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        prev = head;
497c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        head = head->next;
498c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
4997136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (head == NULL) {
5007136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        D("SDKCtl %s: Query %p is not found in the list.",
5017136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine          sdkctl->service_name, query);
5027136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        return 0;
5037136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
504c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
5057136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (prev == NULL) {
5067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Query is at the head of the list. */
5077136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        assert(query == sdkctl->query_head);
5087136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->query_head = query->next;
509c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
5107136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Query is in the middle / at the end of the list. */
5117136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        assert(query != sdkctl->query_head);
5127136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        prev->next = query->next;
513c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
5147136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (sdkctl->query_tail == query) {
5157136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Query is at the tail of the list. */
5167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        assert(query->next == NULL);
5177136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->query_tail = prev;
5187136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
5197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->next = NULL;
5207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
5217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Release query that is now removed from the list. Note that query
5227136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine     * passed to this routine should hold an extra reference, owned by the
5237136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine     * caller. */
5247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl_query_release(query);
5257136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
5267136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return 1;
527c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
528c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
529c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Removes a query (based on query ID) from the list of active queries.
530c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
531c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  sdkctl - SDKCtlSocket instance that owns the query.
532c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  query_id - Identifies the query to remove.
533c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Return:
534c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  A query removed from the list of active queries, or NULL if query with the
5357136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  given ID has not been found in the list. Note that query returned from this
5367136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  routine still holds the reference made when the query has been added to the
5377136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  list.
538c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
539c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic SDKCtlQuery*
540c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_remove_query_id(SDKCtlSocket* sdkctl, int query_id)
541c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
5427136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlQuery* query = NULL;
543c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* prev = NULL;
544c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* head = sdkctl->query_head;
545c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
546c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Quick check: the query could be currently handled by dispatcher. */
547c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->io_dispatcher.current_query != NULL &&
548c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->io_dispatcher.current_query->header.query_id == query_id) {
549c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Release the query from dispatcher. */
5507136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        query = sdkctl->io_dispatcher.current_query;
551c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->io_dispatcher.current_query = NULL;
552c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return query;
553c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
554c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
555c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Remove query from the list. */
556c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    while (head != NULL && head->header.query_id != query_id) {
557c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        prev = head;
558c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        head = head->next;
559c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
5607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (head == NULL) {
5617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        D("SDKCtl %s: Query ID %d is not found in the list.",
562c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          sdkctl->service_name, query_id);
563c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return NULL;
564c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
5657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
5667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Query is found in the list. */
5677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query = head;
5687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (prev == NULL) {
5697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Query is at the head of the list. */
5707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        assert(query == sdkctl->query_head);
5717136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->query_head = query->next;
5727136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    } else {
5737136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Query is in the middle, or at the end of the list. */
5747136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        assert(query != sdkctl->query_head);
5757136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        prev->next = query->next;
5767136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
5777136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (sdkctl->query_tail == query) {
5787136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Query is at the tail of the list. */
5797136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        assert(query->next == NULL);
5807136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->query_tail = prev;
5817136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
5827136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->next = NULL;
5837136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
5847136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return query;
585c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
586c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
587c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Pulls the first query from the list of active queries.
588c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
589c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  sdkctl - SDKCtlSocket instance that owns the query.
590c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Return:
5917136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  A query removed from the head of the list of active queries, or NULL if query
592c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  list is empty.
593c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
594c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic SDKCtlQuery*
595c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_pull_first_query(SDKCtlSocket* sdkctl)
596c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
597c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = sdkctl->query_head;
598c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
599c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query != NULL) {
600c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->query_head = query->next;
601c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (sdkctl->query_head == NULL) {
602c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl->query_tail = NULL;
603c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
604c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
605c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query;
606c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
607c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
608c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Generates new query ID for the given SDKCtl. */
609c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic int
610c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_next_query_id(SDKCtlSocket* sdkctl)
611c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
612c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ++sdkctl->next_query_id;
613c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
614c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
615c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
616c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlPacket implementation
617c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
618c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
619c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Alocates a packet. */
620c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic SDKCtlPacket*
6217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine_sdkctl_packet_new(SDKCtlSocket* sdkctl, uint32_t size, int type)
622c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
6237136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Allocate packet descriptor large enough to contain packet data. */
6247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlPacket* const packet =
6257136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        _sdkctl_socket_alloc_recycler(sdkctl, sizeof(SDKCtlPacket) + size);
626c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
6277136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->sdkctl              = sdkctl;
6287136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->ref_count           = 1;
6297136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->header.signature    = _sdkctl_packet_sig;
6307136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->header.size         = size;
6317136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->header.type         = type;
632c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
633c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Refence SDKCTlSocket that owns this packet. */
634c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_reference(sdkctl);
635c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
6367136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: Packet %p of type %d is allocated for %d bytes transfer.",
6377136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine          sdkctl->service_name, packet, type, size);
6387136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
639c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return packet;
640c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
641c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
642c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Frees a packet. */
643c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
644c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_packet_free(SDKCtlPacket* packet)
645c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
646c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = packet->sdkctl;
647c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
6487136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Recycle packet. */
649c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_free_recycler(packet->sdkctl, packet);
650c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
6517136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: Packet %p is freed.", sdkctl->service_name, packet);
6527136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
653c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Release SDKCTlSocket that owned this packet. */
654c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_release(sdkctl);
655c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
656c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
6577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* References a packet. */
658c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint
6597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine_sdkctl_packet_reference(SDKCtlPacket* packet)
660c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
661c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(packet->ref_count > 0);
662c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    packet->ref_count++;
663c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return packet->ref_count;
664c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
665c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
6667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Releases a packet. */
667c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint
6687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine_sdkctl_packet_release(SDKCtlPacket* packet)
669c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
670c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(packet->ref_count > 0);
671c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    packet->ref_count--;
672c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (packet->ref_count == 0) {
673c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Last reference has been dropped. Destroy this object. */
674c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_packet_free(packet);
675c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return 0;
676c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
677c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return packet->ref_count;
678c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
679c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
6807136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* An I/O callback invoked on packet transmission.
6817136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * Param:
6827136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  io_opaque SDKCtlPacket instance of the packet that's being sent with this I/O.
6837136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  asio - Write I/O descriptor.
6847136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  status - I/O status.
6857136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
6867136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinestatic AsyncIOAction
6877136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine_on_sdkctl_packet_send_io(void* io_opaque,
6887136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                          AsyncSocketIO* asio,
6897136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                          AsyncIOState status)
6907136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
6917136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlPacket* const packet = (SDKCtlPacket*)io_opaque;
6927136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    AsyncIOAction action = ASIO_ACTION_DONE;
6937136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
6947136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Reference the packet while we're in this callback. */
6957136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    _sdkctl_packet_reference(packet);
6967136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
6977136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Lets see what's going on with query transmission. */
6987136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    switch (status) {
6997136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case ASIO_STATE_SUCCEEDED:
7007136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            /* Packet has been sent to the service. */
7017136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            T("SDKCtl %s: Packet %p transmission has succeeded.",
7027136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine              packet->sdkctl->service_name, packet);
7037136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
7047136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7057136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case ASIO_STATE_CANCELLED:
7067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            T("SDKCtl %s: Packet %p is cancelled.",
7077136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine              packet->sdkctl->service_name, packet);
7087136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
7097136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7107136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case ASIO_STATE_FAILED:
7117136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            T("SDKCtl %s: Packet %p has failed: %d -> %s",
7127136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine              packet->sdkctl->service_name, packet, errno, strerror(errno));
7137136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
7147136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7157136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case ASIO_STATE_FINISHED:
7167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            /* Time to disassociate the packet with the I/O. */
7177136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            _sdkctl_packet_release(packet);
7187136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
7197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        default:
7217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            /* Transitional state. */
7227136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
7237136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
7247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7257136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    _sdkctl_packet_release(packet);
7267136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7277136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return action;
7287136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
7297136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7307136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Transmits a packet to SDK Controller.
7317136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * Param:
7327136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  packet - Packet to transmit.
7337136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
7347136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinestatic void
7357136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine_sdkctl_packet_transmit(SDKCtlPacket* packet)
7367136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
7377136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    assert(packet->header.signature == _sdkctl_packet_sig);
7387136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7397136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Reference to associate with the I/O */
7407136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    _sdkctl_packet_reference(packet);
7417136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7427136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Transmit the packet to SDK controller. */
7437136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    async_socket_write_rel(packet->sdkctl->as, &packet->header, packet->header.size,
7447136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                           _on_sdkctl_packet_send_io, packet, -1);
7457136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7467136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: Packet %p size %d is being sent.",
7477136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine      packet->sdkctl->service_name, packet, packet->header.size);
7487136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
7497136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7507136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/********************************************************************************
7517136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *                        SDKCtlDirectPacket implementation
7527136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine ********************************************************************************/
7537136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7547136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir ChtchetkineSDKCtlDirectPacket*
7557136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_direct_packet_new(SDKCtlSocket* sdkctl)
7567136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
7577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlDirectPacket* const packet =
7587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        _sdkctl_socket_alloc_recycler(sdkctl, sizeof(SDKCtlDirectPacket));
7597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->sdkctl      = sdkctl;
7617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->ref_count   = 1;
7627136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7637136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Refence SDKCTlSocket that owns this packet. */
7647136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl_socket_reference(packet->sdkctl);
7657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: Direct packet %p is allocated.", sdkctl->service_name, packet);
7677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return packet;
7697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
7707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7717136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Frees a direct packet. */
7727136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinestatic void
7737136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine_sdkctl_direct_packet_free(SDKCtlDirectPacket* packet)
7747136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
7757136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlSocket* const sdkctl = packet->sdkctl;
7767136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7777136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Free allocated resources. */
7787136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    _sdkctl_socket_free_recycler(packet->sdkctl, packet);
7797136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7807136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: Direct packet %p is freed.", sdkctl->service_name, packet);
7817136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7827136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Release SDKCTlSocket that owned this packet. */
7837136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl_socket_release(sdkctl);
7847136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
7857136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7867136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* References a packet. */
7877136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineint
7887136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_direct_packet_reference(SDKCtlDirectPacket* packet)
7897136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
7907136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    assert(packet->ref_count > 0);
7917136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->ref_count++;
7927136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return packet->ref_count;
7937136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
7947136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
7957136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Releases a packet. */
7967136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineint
7977136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_direct_packet_release(SDKCtlDirectPacket* packet)
7987136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
7997136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    assert(packet->ref_count > 0);
8007136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->ref_count--;
8017136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (packet->ref_count == 0) {
8027136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Last reference has been dropped. Destroy this object. */
8037136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        _sdkctl_direct_packet_free(packet);
8047136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        return 0;
8057136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
8067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return packet->ref_count;
8077136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
8087136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8097136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* An I/O callback invoked on direct packet transmission.
8107136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * Param:
8117136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  io_opaque SDKCtlDirectPacket instance of the packet that's being sent with
8127136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *      this I/O.
8137136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  asio - Write I/O descriptor.
8147136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *  status - I/O status.
8157136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
8167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinestatic AsyncIOAction
8177136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine_on_sdkctl_direct_packet_send_io(void* io_opaque,
8187136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                 AsyncSocketIO* asio,
8197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                 AsyncIOState status)
8207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
8217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlDirectPacket* const packet = (SDKCtlDirectPacket*)io_opaque;
8227136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    AsyncIOAction action = ASIO_ACTION_DONE;
8237136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Reference the packet while we're in this callback. */
8257136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl_direct_packet_reference(packet);
8267136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8277136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Lets see what's going on with query transmission. */
8287136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    switch (status) {
8297136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case ASIO_STATE_SUCCEEDED:
8307136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            /* Packet has been sent to the service. */
8317136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            T("SDKCtl %s: Direct packet %p transmission has succeeded.",
8327136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine              packet->sdkctl->service_name, packet);
8337136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            packet->on_sent(packet->on_sent_opaque, packet, status);
8347136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
8357136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8367136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case ASIO_STATE_CANCELLED:
8377136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            T("SDKCtl %s: Direct packet %p is cancelled.",
8387136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine              packet->sdkctl->service_name, packet);
8397136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            packet->on_sent(packet->on_sent_opaque, packet, status);
8407136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
8417136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8427136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case ASIO_STATE_FAILED:
8437136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            T("SDKCtl %s: Direct packet %p has failed: %d -> %s",
8447136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine              packet->sdkctl->service_name, packet, errno, strerror(errno));
8457136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            packet->on_sent(packet->on_sent_opaque, packet, status);
8467136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
8477136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8487136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case ASIO_STATE_FINISHED:
8497136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            /* Time to disassociate with the I/O. */
8507136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            sdkctl_direct_packet_release(packet);
8517136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
8527136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8537136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        default:
8547136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            /* Transitional state. */
8557136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
8567136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
8577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl_direct_packet_release(packet);
8597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return action;
8617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
8627136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8637136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinevoid
8647136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_direct_packet_send(SDKCtlDirectPacket* packet,
8657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                          void* data,
8667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                          on_sdkctl_direct_cb cb,
8677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                          void* cb_opaque)
8687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
8697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->packet          = (SDKCtlPacketHeader*)data;
8707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->on_sent         = cb;
8717136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    packet->on_sent_opaque  = cb_opaque;
8727136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    assert(packet->packet->signature == _sdkctl_packet_sig);
8737136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8747136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Reference for I/O */
8757136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl_direct_packet_reference(packet);
8767136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8777136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Transmit the packet to SDK controller. */
8787136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    async_socket_write_rel(packet->sdkctl->as, packet->packet, packet->packet->size,
8797136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                           _on_sdkctl_direct_packet_send_io, packet, -1);
8807136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8817136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: Direct packet %p size %d is being sent",
8827136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine      packet->sdkctl->service_name, packet, packet->packet->size);
8837136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
8847136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8857136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/********************************************************************************
8867136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *                      SDKCtlMessage implementation
8877136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine *******************************************************************************/
8887136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8897136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Alocates a message descriptor. */
8907136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinestatic SDKCtlMessage*
8917136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine_sdkctl_message_new(SDKCtlSocket* sdkctl, uint32_t msg_size, int msg_type)
8927136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
8937136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlMessage* const msg =
8947136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        (SDKCtlMessage*)_sdkctl_packet_new(sdkctl,
8957136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                           sizeof(SDKCtlMessageHeader) + msg_size,
8967136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                           SDKCTL_PACKET_MESSAGE);
8977136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    msg->msg_type = msg_type;
8987136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
8997136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return msg;
9007136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
9017136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
9027136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineint
9037136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_message_reference(SDKCtlMessage* msg)
9047136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
9057136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return _sdkctl_packet_reference(&msg->packet);
9067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
9077136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
9087136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineint
9097136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_message_release(SDKCtlMessage* msg)
9107136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
9117136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return _sdkctl_packet_release(&msg->packet);
9127136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
9137136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
9147136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir ChtchetkineSDKCtlMessage*
9157136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_message_send(SDKCtlSocket* sdkctl,
9167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                    int msg_type,
9177136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                    const void* data,
9187136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                    uint32_t size)
9197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
9207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlMessage* const msg = _sdkctl_message_new(sdkctl, size, msg_type);
9217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (size != 0 && data != NULL) {
9227136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        memcpy(msg + 1, data, size);
9237136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
9247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    _sdkctl_packet_transmit(&msg->packet);
9257136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
9267136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return msg;
9277136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
9287136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
9297136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineint
9307136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_message_get_header_size(void)
9317136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
9327136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return sizeof(SDKCtlMessageHeader);
9337136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
9347136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
9357136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinevoid
9367136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_init_message_header(void* msg, int msg_type, int msg_size)
9377136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
9387136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlMessageHeader* const msg_header = (SDKCtlMessageHeader*)msg;
9397136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
9407136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    msg_header->packet.signature    = _sdkctl_packet_sig;
9417136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    msg_header->packet.size         = sizeof(SDKCtlMessageHeader) + msg_size;
9427136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    msg_header->packet.type         = SDKCTL_PACKET_MESSAGE;
9437136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    msg_header->msg_type            = msg_type;
9447136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
9457136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
946c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
947c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                    SDKCtlQuery implementation
948c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
949c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
950c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Frees query descriptor. */
951c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
952c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_query_free(SDKCtlQuery* query)
953c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
954c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query != NULL) {
955c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlSocket* const sdkctl = query->sdkctl;
956c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (query->internal_resp_buffer != NULL &&
957c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            (query->response_buffer == NULL ||
958c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine             query->response_buffer == &query->internal_resp_buffer)) {
9597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            /* This query used its internal buffer to receive the response.
9607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine             * Free it. */
961c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            free(query->internal_resp_buffer);
962c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
963c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
964c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        loopTimer_done(query->timer);
9657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
9667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Recyle the descriptor. */
967c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_free_recycler(sdkctl, query);
968c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
9697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        T("SDKCtl %s: Query %p is freed.", sdkctl->service_name, query);
9707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
971c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Release socket that owned this query. */
972c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_socket_release(sdkctl);
973c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
974c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
975c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
976c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Cancels timeout for the query.
977c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *
978c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * For the simplicity of implementation, the dispatcher will cancel query timer
979c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * when query response data begins to flow in. If we let the timer to expire at
980c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * that stage, we will end up with data flowing in without real place to
981c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * accomodate it.
982c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
983c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
984c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_query_cancel_timeout(SDKCtlQuery* query)
985c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
986c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    loopTimer_stop(query->timer);
987c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
9887136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: Query %p ID %d deadline %lld is cancelled.",
9897136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine      query->sdkctl->service_name, query, query->header.query_id, query->deadline);
990c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
991c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
992c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/*
993c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Query I/O callbacks.
994c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
995c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
996c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Callback that is invoked by the I/O dispatcher when query is successfuly
997c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * completed (i.e. response to the query is received).
998c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
999c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1000c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_query_completed(SDKCtlQuery* query)
1001c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1002c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Query %p ID %d is completed.",
1003c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query, query->header.query_id);
1004c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1005c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Cancel deadline, and inform the client about query completion. */
1006c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_query_cancel_timeout(query);
1007c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->query_cb(query->query_opaque, query, ASIO_STATE_SUCCEEDED);
1008c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1009c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1010c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A callback that is invoked on query cancellation. */
1011c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1012c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_query_cancelled(SDKCtlQuery* query)
1013c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1014c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /*
1015c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * Query cancellation means that SDK controller is disconnected. In turn,
1016c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * this means that SDK controller socket will handle disconnection in its
1017c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * connection callback. So, at this point all we need to do here is to inform
10187136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine     * the client about query cancellation.
1019c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     */
1020c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1021c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Cancel deadline, and inform the client about query cancellation. */
1022c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_query_cancel_timeout(query);
1023c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->query_cb(query->query_opaque, query, ASIO_STATE_CANCELLED);
1024c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1025c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1026c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A timer callback that is invoked on query timeout.
1027c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
1028c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  opaque - SDKCtlQuery instance.
1029c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1030c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1031c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_skdctl_query_timeout(void* opaque)
1032c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1033c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = (SDKCtlQuery*)opaque;
1034c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1035c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("SDKCtl %s: Query %p ID %d with deadline %lld has timed out at %lld",
1036c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query, query->header.query_id,
1037c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->deadline, async_socket_deadline(query->sdkctl->as, 0));
1038c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1039c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference the query while we're in this callback. */
1040c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_reference(query);
1041c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1042c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Inform the client about deadline expiration. Note that client may
1043c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * extend the deadline, and retry the query. */
1044c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    const AsyncIOAction action =
1045c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->query_cb(query->query_opaque, query, ASIO_STATE_TIMED_OUT);
1046c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1047c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* For actions other than retry we will destroy the query. */
1048c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (action != ASIO_ACTION_RETRY) {
1049c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_remove_query(query);
1050c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1051c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1052c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_release(query);
1053c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1054c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
10557136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* A callback that is invoked when query has been sent to the SDK controller. */
1056c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1057c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_query_sent(SDKCtlQuery* query)
1058c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
10597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: Sent %d bytes of query %p ID %d of type %d",
1060c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query->header.packet.size, query,
1061c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->header.query_id, query->header.query_type);
1062c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1063c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Inform the client about the event. */
1064c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->query_cb(query->query_opaque, query, ASIO_STATE_CONTINUES);
1065c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1066c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Set a timer to expire at query's deadline, and let the response to come
1067c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * through the dispatcher loop. */
1068c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    loopTimer_startAbsolute(query->timer, query->deadline);
1069c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1070c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1071c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* An I/O callback invoked on query transmission.
1072c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
1073c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  io_opaque SDKCtlQuery instance of the query that's being sent with this I/O.
1074c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  asio - Write I/O descriptor.
1075c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  status - I/O status.
1076c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1077c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1078c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_query_send_io(void* io_opaque,
1079c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                         AsyncSocketIO* asio,
1080c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                         AsyncIOState status)
1081c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1082c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = (SDKCtlQuery*)io_opaque;
1083c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    AsyncIOAction action = ASIO_ACTION_DONE;
1084c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1085c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference the query while we're in this callback. */
1086c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_reference(query);
1087c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1088c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Lets see what's going on with query transmission. */
1089c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    switch (status) {
10907136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case ASIO_STATE_SUCCEEDED:
10917136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            /* Query has been sent to the service. */
10927136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            _on_sdkctl_query_sent(query);
10937136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            break;
10947136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
1095c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_CANCELLED:
10967136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            T("SDKCtl %s: Query %p ID %d is cancelled in transmission.",
10977136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine              query->sdkctl->service_name, query, query->header.query_id);
1098c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Remove the query from the list of active queries. */
1099c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _sdkctl_socket_remove_query(query);
1100c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _on_sdkctl_query_cancelled(query);
1101c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1102c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1103c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_TIMED_OUT:
11047136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            D("SDKCtl %s: Query %p ID %d with deadline %lld has timed out in transmission at %lld",
1105c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              query->sdkctl->service_name, query, query->header.query_id,
11067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine              query->deadline,  async_socket_deadline(query->sdkctl->as, 0));
1107c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Invoke query's callback. */
1108c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = query->query_cb(query->query_opaque, query, status);
1109c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* For actions other than retry we need to stop the query. */
1110c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            if (action != ASIO_ACTION_RETRY) {
1111c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _sdkctl_socket_remove_query(query);
1112c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            }
1113c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1114c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1115c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_FAILED:
11167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            T("SDKCtl %s: Query %p ID %d failed in transmission: %d -> %s",
1117c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              query->sdkctl->service_name, query, query->header.query_id,
1118c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              errno, strerror(errno));
1119c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Invoke query's callback. Note that we will let the client to
1120c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine             * decide what to do on I/O failure. */
1121c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = query->query_cb(query->query_opaque, query, status);
1122c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* For actions other than retry we need to stop the query. */
1123c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            if (action != ASIO_ACTION_RETRY) {
1124c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _sdkctl_socket_remove_query(query);
1125c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            }
1126c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1127c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1128c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_FINISHED:
1129c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Time to disassociate with the I/O. */
1130c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl_query_release(query);
1131c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1132c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1133c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        default:
1134c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Transitional state. */
1135c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1136c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1137c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1138c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_release(query);
1139c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1140c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return action;
1141c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1142c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1143c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1144c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                    SDKCtlQuery public API implementation
1145c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine ********************************************************************************/
1146c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1147c8aa2c570d30098da59f1967d5158024ed28570dVladimir ChtchetkineSDKCtlQuery*
1148c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_new(SDKCtlSocket* sdkctl, int query_type, uint32_t in_data_size)
1149c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
11507136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlQuery* const query =
11517136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        _sdkctl_socket_alloc_recycler(sdkctl, sizeof(SDKCtlQuery) + in_data_size);
11527136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->next                     = NULL;
11537136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->sdkctl                   = sdkctl;
11547136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->response_buffer          = NULL;
11557136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->response_size            = NULL;
11567136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->internal_resp_buffer     = NULL;
11577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->internal_resp_size       = 0;
11587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->query_cb                 = NULL;
11597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->query_opaque             = NULL;
11607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->deadline                 = DURATION_INFINITE;
11617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->ref_count                = 1;
11627136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->header.packet.signature  = _sdkctl_packet_sig;
11637136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->header.packet.size       = sizeof(SDKCtlQueryHeader) + in_data_size;
11647136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->header.packet.type       = SDKCTL_PACKET_QUERY;
11657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->header.query_id          = _sdkctl_socket_next_query_id(sdkctl);
11667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->header.query_type        = query_type;
1167c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1168c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Initialize timer to fire up on query deadline expiration. */
1169c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    loopTimer_init(query->timer, sdkctl->looper, _on_skdctl_query_timeout, query);
1170c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1171c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference socket that owns this query. */
1172c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_reference(sdkctl);
1173c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1174c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Query %p ID %d type %d is created for %d bytes of data.",
1175c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query, query->header.query_id,
1176c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query_type, in_data_size);
1177c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1178c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query;
1179c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1180c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1181c8aa2c570d30098da59f1967d5158024ed28570dVladimir ChtchetkineSDKCtlQuery*
1182c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_new_ex(SDKCtlSocket* sdkctl,
1183c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    int query_type,
1184c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    uint32_t in_data_size,
1185c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    const void* in_data,
1186c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    void** response_buffer,
1187c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    uint32_t* response_size,
1188c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    on_sdkctl_query_cb query_cb,
1189c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    void* query_opaque)
1190c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1191c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = sdkctl_query_new(sdkctl, query_type, in_data_size);
1192c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
11937136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->response_buffer = response_buffer;
1194c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query->response_buffer == NULL) {
1195c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Creator didn't supply a buffer. Use internal one instead. */
1196c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->response_buffer = &query->internal_resp_buffer;
1197c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
11987136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->response_size = response_size;
1199c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query->response_size == NULL) {
1200c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Creator didn't supply a buffer for response size. Use internal one
1201c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * instead. */
1202c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->response_size = &query->internal_resp_size;
1203c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
12047136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->query_cb = query_cb;
12057136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    query->query_opaque = query_opaque;
1206c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Init query's input buffer. */
1207c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (in_data_size != 0 && in_data != NULL) {
1208c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        memcpy(query + 1, in_data, in_data_size);
1209c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1210c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1211c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query;
1212c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1213c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1214c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinevoid
1215c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_send(SDKCtlQuery* query, int to)
1216c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1217c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = query->sdkctl;
1218c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1219c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Initialize the deadline. */
1220c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->deadline = async_socket_deadline(query->sdkctl->as, to);
1221c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1222c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* List the query in the list of active queries. */
1223c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_add_query(query);
1224c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1225c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference query associated with write I/O. */
1226c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_reference(query);
1227c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
12287136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    assert(query->header.packet.signature == _sdkctl_packet_sig);
1229c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Transmit the query to SDK controller. */
1230c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    async_socket_write_abs(sdkctl->as, &query->header, query->header.packet.size,
1231c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                           _on_sdkctl_query_send_io, query, query->deadline);
1232c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
12337136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: Query %p ID %d type %d is being sent with deadline at %lld",
1234c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->sdkctl->service_name, query, query->header.query_id,
1235c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      query->header.query_type, query->deadline);
1236c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1237c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1238c8aa2c570d30098da59f1967d5158024ed28570dVladimir ChtchetkineSDKCtlQuery*
1239c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_build_and_send(SDKCtlSocket* sdkctl,
1240c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            int query_type,
1241c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            uint32_t in_data_size,
1242c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            const void* in_data,
1243c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            void** response_buffer,
1244c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            uint32_t* response_size,
1245c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            on_sdkctl_query_cb query_cb,
1246c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            void* query_opaque,
1247c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            int to)
1248c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1249c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query =
1250c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_new_ex(sdkctl, query_type, in_data_size, in_data,
1251c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            response_buffer, response_size, query_cb,
1252c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            query_opaque);
1253c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_query_send(query, to);
1254c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query;
1255c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1256c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1257c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint
1258c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_reference(SDKCtlQuery* query)
1259c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1260c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(query->ref_count > 0);
1261c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->ref_count++;
1262c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query->ref_count;
1263c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1264c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1265c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint
1266c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_query_release(SDKCtlQuery* query)
1267c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1268c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(query->ref_count > 0);
1269c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query->ref_count--;
1270c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query->ref_count == 0) {
1271c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Last reference has been dropped. Destroy this object. */
1272c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_query_free(query);
1273c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return 0;
1274c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1275c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return query->ref_count;
1276c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1277c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
12787136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinevoid*
12797136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_query_get_buffer_in(SDKCtlQuery* query)
12807136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
12817136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Query buffer starts right after the header. */
12827136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return query + 1;
12837136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
12847136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
12857136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinevoid*
12867136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_query_get_buffer_out(SDKCtlQuery* query)
12877136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
12887136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return query->response_buffer != NULL ? *query->response_buffer :
12897136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                            query->internal_resp_buffer;
12907136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
12917136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
1292c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1293c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlPacket implementation
1294c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
1295c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
12967136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* A packet has been received from SDK controller.
12977136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * Note that we expect the packet to be a message, since queries, and query
12987136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * replies are handled separately. */
1299c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1300c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_packet_received(SDKCtlSocket* sdkctl, SDKCtlPacket* packet)
1301c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1302c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Received packet size: %d, type: %d",
1303c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      sdkctl->service_name, packet->header.size, packet->header.type);
1304c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
13057136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    assert(packet->header.signature == _sdkctl_packet_sig);
13067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (packet->header.type == SDKCTL_PACKET_MESSAGE) {
13077136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        SDKCtlMessage* const msg = (SDKCtlMessage*)packet;
13087136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Lets see if this is an internal protocol message. */
13097136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        switch (msg->msg_type) {
13107136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            case SDKCTL_MSG_PORT_CONNECTED:
13117136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                sdkctl->port_status = SDKCTL_PORT_CONNECTED;
13127136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                sdkctl->on_port_connection(sdkctl->opaque, sdkctl,
13137136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                           SDKCTL_PORT_CONNECTED);
13147136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                break;
13157136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
13167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            case SDKCTL_MSG_PORT_DISCONNECTED:
13177136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                sdkctl->port_status = SDKCTL_PORT_DISCONNECTED;
13187136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                sdkctl->on_port_connection(sdkctl->opaque, sdkctl,
13197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                           SDKCTL_PORT_DISCONNECTED);
13207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                break;
13217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
13227136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            case SDKCTL_MSG_PORT_ENABLED:
13237136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                sdkctl->port_status = SDKCTL_PORT_ENABLED;
13247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                sdkctl->on_port_connection(sdkctl->opaque, sdkctl,
13257136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                           SDKCTL_PORT_ENABLED);
13267136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                break;
13277136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
13287136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            case SDKCTL_MSG_PORT_DISABLED:
13297136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                sdkctl->port_status = SDKCTL_PORT_DISABLED;
13307136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                sdkctl->on_port_connection(sdkctl->opaque, sdkctl,
13317136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                           SDKCTL_PORT_DISABLED);
13327136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                break;
13337136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
13347136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            default:
13357136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                /* This is a higher-level message. Dispatch the message to the
13367136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                 * client. */
13377136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                sdkctl->on_message(sdkctl->opaque, sdkctl, msg, msg->msg_type, msg + 1,
13387136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                   packet->header.size - sizeof(SDKCtlMessageHeader));
13397136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                break;
13407136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        }
13417136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    } else {
13427136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        E("SDKCtl %s: Received unknown packet type %d size %d",
13437136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine          sdkctl->service_name, packet->header.type, packet->header.size);
13447136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
1345c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1346c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1347c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1348c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDKCtlIODispatcher implementation
1349c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
1350c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1351c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* An I/O callback invoked when data gets received from the socket.
1352c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
1353c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  io_opaque SDKCtlIODispatcher instance associated with the reader.
1354c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  asio - Read I/O descriptor.
1355c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  status - I/O status.
1356c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1357c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction _on_sdkctl_io_dispatcher_io(void* io_opaque,
1358c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                                 AsyncSocketIO* asio,
1359c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                                 AsyncIOState status);
1360c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1361c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Starts I/O dispatcher for SDK controller socket. */
1362c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1363c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_io_dispatcher_start(SDKCtlSocket* sdkctl) {
1364c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
1365c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1366c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->state           = SDKCTL_IODISP_EXPECT_HEADER;
1367c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->sdkctl          = sdkctl;
1368c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->packet          = NULL;
1369c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->current_query   = NULL;
1370c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1371c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Register a packet header reader with the socket. */
13727136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    async_socket_read_rel(dispatcher->sdkctl->as, &dispatcher->packet_header,
1373c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                          sizeof(SDKCtlPacketHeader), _on_sdkctl_io_dispatcher_io,
1374c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                          dispatcher, -1);
1375c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1376c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1377c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Resets I/O dispatcher for SDK controller socket. */
1378c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1379c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_io_dispatcher_reset(SDKCtlSocket* sdkctl) {
1380c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
1381c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1382c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Cancel current query. */
1383c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (dispatcher->current_query != NULL) {
1384c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQuery* const query = dispatcher->current_query;
1385c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->current_query = NULL;
1386c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _on_sdkctl_query_cancelled(query);
1387c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
1388c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1389c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1390c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Free packet data buffer. */
1391c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (dispatcher->packet != NULL) {
13927136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        _sdkctl_packet_release(dispatcher->packet);
1393c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->packet = NULL;
1394c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1395c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1396c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reset dispatcher state. */
1397c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
13987136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
13997136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: I/O Dispatcher is reset", sdkctl->service_name);
1400c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1401c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1402c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/*
1403c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * I/O dispatcher callbacks.
1404c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1405c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1406c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A callback that is invoked when a failure occurred while dispatcher was
1407c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * reading data from the socket.
1408c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1409c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1410c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_io_failure(SDKCtlIODispatcher* dispatcher,
1411c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                             AsyncSocketIO* asio)
1412c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1413c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1414c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1415c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("SDKCtl %s: Dispatcher I/O failure: %d -> %s",
1416c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      sdkctl->service_name, errno, strerror(errno));
1417c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1418c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* We treat all I/O failures same way we treat disconnection. Just cancel
1419c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * everything, disconnect, and let the client to decide what to do next. */
1420c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_disconnect(sdkctl);
1421c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1422c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Report disconnection to the client, and let it restore connection in this
1423c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * callback. */
14247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED);
1425c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1426c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1427c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A callback that is invoked when dispatcher's reader has been cancelled. */
1428c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1429c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_io_cancelled(SDKCtlIODispatcher* dispatcher,
1430c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                               AsyncSocketIO* asio)
1431c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1432c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Dispatcher I/O cancelled.", dispatcher->sdkctl->service_name);
1433c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1434c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* If we're in the middle of receiving query reply we need to cancel the
1435c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * query. */
1436c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (dispatcher->current_query != NULL) {
1437c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQuery* const query = dispatcher->current_query;
1438c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->current_query = NULL;
1439c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _on_sdkctl_query_cancelled(query);
1440c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
1441c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1442c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1443c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Discard packet data we've received so far. */
1444c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (dispatcher->packet != NULL) {
14457136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        _sdkctl_packet_release(dispatcher->packet);
1446c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->packet = NULL;
1447c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1448c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1449c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1450c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A generic packet header has been received by I/O dispatcher. */
1451c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1452c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_packet_header(SDKCtlIODispatcher* dispatcher,
1453c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                AsyncSocketIO* asio)
1454c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1455c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1456c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1457c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Packet header type %d, size %d is received.",
14587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine      dispatcher->sdkctl->service_name, dispatcher->packet_header.type,
14597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine      dispatcher->packet_header.size);
14607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
14617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    /* Make sure we have a valid packet header. */
14627136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (dispatcher->packet_header.signature != _sdkctl_packet_sig) {
14637136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        E("SDKCtl %s: Invalid packet signature %x for packet type %d, size %d",
14647136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine          sdkctl->service_name, dispatcher->packet_header.signature,
14657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine          dispatcher->packet_header.type, dispatcher->packet_header.size);
14667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* This is a protocol failure. Treat it as I/O failure: disconnect, and
14677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine         * let the client to decide what to do next. */
14687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        errno = EINVAL;
14697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        _on_io_dispatcher_io_failure(dispatcher, asio);
14707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        return ASIO_ACTION_DONE;
14717136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
1472c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1473c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Here we have three choices for the packet, that define the rest of
1474c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * the data that follow it:
1475c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * - Regular packet,
1476c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * - Response to a query that has been sent to SDK controller,
1477c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * - A query from SDK controller.
1478c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * Update the state accordingly, and initiate reading of the
1479c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * remaining of the packet.
1480c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     */
14817136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine     if (dispatcher->packet_header.type == SDKCTL_PACKET_QUERY_RESPONSE) {
1482c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* This is a response to the query. Before receiving response data we
1483c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * need to locate the relevant query, and use its response buffer to read
1484c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * the data. For that we need to obtain query ID firts. So, initiate
1485c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * reading of the remaining part of SDKCtlQueryReplyHeader. */
1486c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER;
1487c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_read_rel(sdkctl->as, &dispatcher->query_reply_header.query_id,
1488c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                              sizeof(SDKCtlQueryReplyHeader) - sizeof(SDKCtlPacketHeader),
1489c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                             _on_sdkctl_io_dispatcher_io, dispatcher, -1);
1490c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1491c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* For regular packets, as well as queries, we simply allocate buffer,
1492c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * that fits the entire packet, and read the remainder of the data in
1493c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * there. */
1494c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->state = SDKCTL_IODISP_EXPECT_DATA;
1495c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->packet =
14967136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            _sdkctl_packet_new(sdkctl, dispatcher->packet_header.size,
14977136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                               dispatcher->packet_header.type);
1498c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Initiate reading of the packet data. */
1499c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_read_rel(sdkctl->as, dispatcher->packet + 1,
15007136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                              dispatcher->packet_header.size - sizeof(SDKCtlPacketHeader),
1501c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                              _on_sdkctl_io_dispatcher_io, dispatcher, -1);
1502c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1503c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1504c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
1505c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1506c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1507c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A generic packet has been received by I/O dispatcher. */
1508c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1509c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_packet(SDKCtlIODispatcher* dispatcher, AsyncSocketIO* asio)
1510c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1511c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
15127136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    SDKCtlPacket* const packet = dispatcher->packet;
15137136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    dispatcher->packet = NULL;
1514c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1515c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Packet type %d, size %d is received.",
15167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine      dispatcher->sdkctl->service_name, dispatcher->packet_header.type,
15177136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine      dispatcher->packet_header.size);
1518c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
15197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    _on_sdkctl_packet_received(sdkctl, packet);
15207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    _sdkctl_packet_release(packet);
1521c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1522c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Get ready for the next I/O cycle. */
1523c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
15247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    async_socket_read_rel(sdkctl->as, &dispatcher->packet_header, sizeof(SDKCtlPacketHeader),
1525c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                          _on_sdkctl_io_dispatcher_io, dispatcher, -1);
1526c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
1527c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1528c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1529c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A query reply header has been received by I/O dispatcher. */
1530c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1531c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_query_reply_header(SDKCtlIODispatcher* dispatcher,
1532c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                     AsyncSocketIO* asio)
1533c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1534c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1535c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* query;
1536c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1537c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Query reply header is received for query ID %d",
1538c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      dispatcher->sdkctl->service_name, dispatcher->query_reply_header.query_id);
1539c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1540c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Pull the query out of the list of active queries. It's the dispatcher that
1541c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * owns this query now. */
1542c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->current_query =
1543c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_remove_query_id(sdkctl, dispatcher->query_reply_header.query_id);
1544c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query = dispatcher->current_query;
15457136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    const uint32_t query_data_size =
15467136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        dispatcher->packet_header.size - sizeof(SDKCtlQueryReplyHeader);
15477136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA;
1548c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1549c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query == NULL) {
1550c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("%s: Query #%d is not found by dispatcher",
1551c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          dispatcher->sdkctl->service_name, dispatcher->query_reply_header.query_id);
1552c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1553c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Query is not found. Just read the remainder of reply up in the air,
1554c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * and then discard when it's over. */
1555c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->state = SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA;
1556c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->packet =
15577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            _sdkctl_packet_new(sdkctl, dispatcher->packet_header.size,
15587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                               dispatcher->packet_header.type);
1559c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Copy query reply info to the packet. */
1560c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        memcpy(&dispatcher->packet->header, &dispatcher->query_reply_header,
1561c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine               sizeof(SDKCtlQueryReplyHeader));
15627136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        async_socket_read_rel(sdkctl->as, dispatcher->packet + 1, query_data_size,
1563c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                             _on_sdkctl_io_dispatcher_io, dispatcher, -1);
1564c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1565c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Prepare to receive query reply. For the simplicity sake, cancel query
1566c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * time out, so it doesn't expire on us while we're in the middle of
1567c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * receiving query's reply. */
1568c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_query_cancel_timeout(query);
1569c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1570c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (*query->response_size < query_data_size) {
1571c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            *query->response_buffer = malloc(query_data_size);
1572c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            if (*query->response_buffer == NULL) {
1573c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                APANIC("%s: Unable to allocate %d bytes for query response",
1574c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                       sdkctl->service_name, query_data_size);
1575c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            }
1576c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1577c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Save the actual query response size. */
1578c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        *query->response_size = query_data_size;
1579c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1580c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Start reading query response. */
1581c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_read_rel(sdkctl->as, *query->response_buffer,
1582c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                              *query->response_size, _on_sdkctl_io_dispatcher_io,
1583c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                              dispatcher, -1);
1584c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1585c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1586c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
1587c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1588c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1589c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A query reply header has been received by I/O dispatcher. */
1590c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1591c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_io_dispatcher_query_reply(SDKCtlIODispatcher* dispatcher, AsyncSocketIO* asio)
1592c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1593c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1594c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* const query = dispatcher->current_query;
1595c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->current_query = NULL;
1596c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1597c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (query != NULL) {
1598c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _ANDROID_ASSERT(query->header.query_id == dispatcher->query_reply_header.query_id,
1599c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                        "SDKCtl %s: Query ID mismatch in I/O dispatcher",
1600c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                        sdkctl->service_name);
1601c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        T("SDKCtl %s: Query reply is received for query %p ID %d. Reply size is %d",
1602c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          dispatcher->sdkctl->service_name, query, query->header.query_id,
1603c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          *query->response_size);
1604c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1605c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Complete the query, and release it from the dispatcher. */
1606c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _on_sdkctl_query_completed(query);
1607c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
1608c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1609c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* This was "read up in the air" for a cancelled query. Just discard the
1610c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine         * read data. */
1611c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (dispatcher->packet != NULL) {
16127136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            _sdkctl_packet_release(dispatcher->packet);
1613c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            dispatcher->packet = NULL;
1614c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1615c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1616c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1617c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Get ready for the next I/O cycle. */
1618c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    dispatcher->state = SDKCTL_IODISP_EXPECT_HEADER;
16197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    async_socket_read_rel(sdkctl->as, &dispatcher->packet_header, sizeof(SDKCtlPacketHeader),
1620c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                          _on_sdkctl_io_dispatcher_io, dispatcher, -1);
1621c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
1622c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1623c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1624c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* An I/O callback invoked when data gets received from the socket.
1625c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * This is main I/O dispatcher loop.
1626c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
1627c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  io_opaque SDKCtlIODispatcher instance associated with the reader.
1628c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  asio - Read I/O descriptor.
1629c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  status - I/O status.
1630c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1631c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1632c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_io_dispatcher_io(void* io_opaque,
1633c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            AsyncSocketIO* asio,
1634c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            AsyncIOState status)
1635c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1636c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    AsyncIOAction action = ASIO_ACTION_DONE;
1637c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcher* const dispatcher = (SDKCtlIODispatcher*)io_opaque;
1638c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = dispatcher->sdkctl;
1639c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1640c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference SDKCtlSocket while we're in this callback. */
1641c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_reference(sdkctl);
1642c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1643c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (status != ASIO_STATE_SUCCEEDED) {
1644c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Something going on with I/O other than receiving data.. */
1645c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        switch (status) {
1646c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_STARTED:
1647c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* Data has started flowing in. Cancel timeout on I/O that has
1648c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 * started, so we can complete the current state of the
1649c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 * dispatcher without interruptions other than I/O failures. */
1650c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                async_socket_io_cancel_time_out(asio);
1651c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1652c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1653c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_FAILED:
1654c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* I/O failure has occurred. Handle the failure. */
1655c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _on_io_dispatcher_io_failure(dispatcher, asio);
1656c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1657c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1658c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_TIMED_OUT:
1659c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 /* The way I/O dispatcher is implemented, this should never
1660c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  * happen, because dispatcher doesn't set I/O expiration time
1661c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  * when registering its readers. */
1662c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _ANDROID_ASSERT(0,
1663c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    "SDKCtl %s: We should never receive ASIO_STATE_TIMED_OUT in SDKCtl I/O dispatcher.",
1664c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    sdkctl->service_name);
1665c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1666c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1667c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_CANCELLED:
1668c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* Cancellation means that we're in the middle of handling
1669c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 * disconnection. Sooner or later, this dispatcher will be reset,
1670c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 * so we don't really care about keeping its state at this point.
1671c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 */
1672c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _on_io_dispatcher_io_cancelled(dispatcher, asio);
1673c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1674c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1675c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_FINISHED:
1676c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1677c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1678c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            default:
1679c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _ANDROID_ASSERT(0, "SDKCtl %s: Unexpected I/O status %d in the dispatcher",
1680c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                sdkctl->service_name, status);
1681c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* Handle this as protocol failure. */
1682c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                errno = EINVAL;
1683c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                _on_io_dispatcher_io_failure(dispatcher, asio);
1684c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                action = ASIO_ACTION_ABORT;
1685c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
1686c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1687c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1688c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_socket_release(sdkctl);
1689c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1690c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return action;
1691c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1692c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1693c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Requested data has been read. Handle the chunk depending on dispatcher's
1694c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * state. */
1695c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    switch (dispatcher->state) {
1696c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case SDKCTL_IODISP_EXPECT_HEADER:
1697c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* A generic packet header is received. */
1698c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = _on_io_dispatcher_packet_header(dispatcher, asio);
1699c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1700c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1701c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case SDKCTL_IODISP_EXPECT_QUERY_REPLY_HEADER:
1702c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Query reply header is received. */
1703c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = _on_io_dispatcher_query_reply_header(dispatcher, asio);
1704c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1705c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1706c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case SDKCTL_IODISP_EXPECT_QUERY_REPLY_DATA:
1707c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* Query reply is received. Complete the query. */
1708c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = _on_io_dispatcher_query_reply(dispatcher, asio);
1709c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1710c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1711c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case SDKCTL_IODISP_EXPECT_DATA:
1712c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            /* A generic packet is received. */
1713c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = _on_io_dispatcher_packet(dispatcher, asio);
1714c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1715c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1716c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        default:
1717c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _ANDROID_ASSERT(0, "SDKCtl %s: Unexpected I/O dispacher state %d",
1718c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            sdkctl->service_name, dispatcher->state);
1719c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1720c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1721c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1722c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_release(sdkctl);
1723c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1724c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return action;
1725c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1726c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1727c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1728c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                       SDKCtlSocket internals.
1729c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
1730c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1731c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Cancels all queries that is active on this socket. */
1732c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1733c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_cancel_all_queries(SDKCtlSocket* sdkctl)
1734c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1735c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlIODispatcher* const dispatcher = &sdkctl->io_dispatcher;
1736c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlQuery* query;
1737c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1738c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Cancel query that is being completed in dispatcher. */
1739c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (dispatcher->current_query != NULL) {
1740c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQuery* const query = dispatcher->current_query;
1741c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        dispatcher->current_query = NULL;
1742c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _on_sdkctl_query_cancelled(query);
1743c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
1744c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1745c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1746c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* One by one empty query list cancelling pulled queries. */
1747c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    query = _sdkctl_socket_pull_first_query(sdkctl);
1748c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    while (query != NULL) {
1749c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_query_cancel_timeout(query);
1750c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query->query_cb(query->query_opaque, query, ASIO_STATE_CANCELLED);
1751c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
1752c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        query = _sdkctl_socket_pull_first_query(sdkctl);
1753c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1754c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1755c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1756c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Cancels all packets that is active on this socket. */
1757c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1758c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_cancel_all_packets(SDKCtlSocket* sdkctl)
1759c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1760c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1761c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1762c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Cancels all I/O that is active on this socket. */
1763c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1764c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_cancel_all_io(SDKCtlSocket* sdkctl)
1765c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1766c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Cancel all queries, and packets that are active for this I/O. */
1767c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_cancel_all_queries(sdkctl);
1768c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_cancel_all_packets(sdkctl);
1769c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1770c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1771c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Disconnects AsyncSocket for SDKCtlSocket. */
1772c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1773c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_disconnect_socket(SDKCtlSocket* sdkctl)
1774c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1775c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->as != NULL) {
1776c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Disconnect the socket. This will trigger I/O cancellation callbacks. */
1777c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_disconnect(sdkctl->as);
1778c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1779c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Cancel all I/O that is active on this socket. */
1780c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_cancel_all_io(sdkctl);
1781c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1782c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Reset I/O dispatcher. */
1783c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_io_dispatcher_reset(sdkctl);
1784c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1785c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1786c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->state = SDKCTL_SOCKET_DISCONNECTED;
17877136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->port_status = SDKCTL_PORT_DISCONNECTED;
1788c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1789c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1790c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Frees SDKCtlSocket instance. */
1791c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
1792c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_socket_free(SDKCtlSocket* sdkctl)
1793c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1794c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl != NULL) {
17957136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        T("SDKCtl %s: descriptor is destroing.", sdkctl->service_name);
17967136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
1797c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Disconnect, and release the socket. */
1798c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (sdkctl->as != NULL) {
1799c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            async_socket_disconnect(sdkctl->as);
1800c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            async_socket_release(sdkctl->as);
1801c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1802c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1803c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Free allocated resources. */
1804c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (sdkctl->looper != NULL) {
1805c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            looper_free(sdkctl->looper);
1806c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1807c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (sdkctl->service_name != NULL) {
1808c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            free(sdkctl->service_name);
1809c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1810c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_empty_recycler(sdkctl);
1811c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1812c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        AFREE(sdkctl);
1813c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1814c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1815c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1816c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1817c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                    SDK Control Socket connection callbacks.
1818c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
1819c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1820c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Initiates handshake query when SDK controller socket is connected. */
1821c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void _sdkctl_do_handshake(SDKCtlSocket* sdkctl);
1822c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1823c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A socket connection is established.
1824c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Here we will start I/O dispatcher, and will initiate a handshake with
1825c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * the SdkController service for this socket. */
1826c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1827c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_async_socket_connected(SDKCtlSocket* sdkctl)
1828c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1829c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("SDKCtl %s: Socket is connected.", sdkctl->service_name);
1830c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1831c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Notify the client that connection is established. */
1832c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    const AsyncIOAction action =
18337136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_SUCCEEDED);
1834c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1835c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (action == ASIO_ACTION_DONE) {
1836c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Initialize, and start main I/O dispatcher. */
1837c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_io_dispatcher_start(sdkctl);
1838c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1839c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Initiate handshake. */
1840c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_do_handshake(sdkctl);
1841c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1842c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return action;
1843c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1844c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Client didn't like something about this connection. */
1845c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return action;
1846c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1847c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1848c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1849c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* Handles lost connection with SdkController service. */
1850c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1851c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_async_socket_disconnected(SDKCtlSocket* sdkctl)
1852c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1853c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("SDKCtl %s: Socket has been disconnected.", sdkctl->service_name);
1854c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1855c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_disconnect_socket(sdkctl);
1856c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
18577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    AsyncIOAction action = sdkctl->on_socket_connection(sdkctl->opaque, sdkctl,
18587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                                        ASIO_STATE_FAILED);
1859c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (action == ASIO_ACTION_DONE) {
1860c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Default action for disconnect is to reestablish the connection. */
1861c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        action = ASIO_ACTION_RETRY;
1862c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1863c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (action == ASIO_ACTION_RETRY) {
1864c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->state = SDKCTL_SOCKET_CONNECTING;
1865c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1866c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return action;
1867c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1868c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1869c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* An entry point for all socket connection events.
1870c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Here we will dispatch connection events to appropriate handlers.
1871c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine * Param:
1872c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *  client_opaque - SDKCtlSocket isntance.
1873c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine */
1874c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
1875c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_async_socket_connection(void* client_opaque,
1876c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            AsyncSocket* as,
1877c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                            AsyncIOState status)
1878c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1879c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    AsyncIOAction action = ASIO_ACTION_DONE;
1880c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = (SDKCtlSocket*)client_opaque;
1881c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1882c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Reference the socket while in this callback. */
1883c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_reference(sdkctl);
1884c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1885c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    switch (status) {
1886c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_SUCCEEDED:
1887c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl->state = SDKCTL_SOCKET_CONNECTED;
1888c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _on_async_socket_connected(sdkctl);
1889c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1890c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1891c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_FAILED:
1892c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            if (sdkctl->state == SDKCTL_SOCKET_CONNECTED) {
1893c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* This is disconnection condition. */
1894c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                action = _on_async_socket_disconnected(sdkctl);
1895c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            } else {
1896c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                /* An error has occurred while attempting to connect to socket.
1897c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 * Lets try again... */
1898c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                action = ASIO_ACTION_RETRY;
1899c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            }
1900c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1901c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1902c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        case ASIO_STATE_RETRYING:
1903c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        default:
1904c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            action = ASIO_ACTION_RETRY;
1905c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            break;
1906c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1907c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1908c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl_socket_release(sdkctl);
1909c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1910c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return action;
1911c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1912c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1913c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
1914c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                      SDK Control Socket public API
1915c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
1916c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1917c8aa2c570d30098da59f1967d5158024ed28570dVladimir ChtchetkineSDKCtlSocket*
1918c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_socket_new(int reconnect_to,
1919c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  const char* service_name,
19207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                  on_sdkctl_socket_connection_cb on_socket_connection,
19217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                  on_sdkctl_port_connection_cb on_port_connection,
1922c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  on_sdkctl_message_cb on_message,
1923c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  void* opaque)
1924c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1925c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* sdkctl;
1926c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    ANEW0(sdkctl);
1927c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
19287136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->state                   = SDKCTL_SOCKET_DISCONNECTED;
19297136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->port_status             = SDKCTL_PORT_DISCONNECTED;
19307136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->opaque                  = opaque;
19317136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->service_name            = ASTRDUP(service_name);
19327136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->on_socket_connection    = on_socket_connection;
19337136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->on_port_connection      = on_port_connection;
19347136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->on_message              = on_message;
19357136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->reconnect_to            = reconnect_to;
19367136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->as                      = NULL;
19377136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->next_query_id           = 0;
19387136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->query_head              = sdkctl->query_tail = NULL;
19397136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->ref_count               = 1;
19407136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->recycler                = NULL;
19417136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->recycler_block_size     = 0;
19427136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->recycler_max            = 0;
19437136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    sdkctl->recycler_count          = 0;
19447136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
19457136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    T("SDKCtl %s: descriptor is created.", sdkctl->service_name);
1946c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1947c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->looper = looper_newCore();
1948c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->looper == NULL) {
1949c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        E("Unable to create I/O looper for SDKCtl socket '%s'",
1950c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          service_name);
19517136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        on_socket_connection(opaque, sdkctl, ASIO_STATE_FAILED);
1952c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_free(sdkctl);
1953c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return NULL;
1954c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1955c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1956c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return sdkctl;
1957c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1958c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1959c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint sdkctl_socket_reference(SDKCtlSocket* sdkctl)
1960c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1961c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(sdkctl->ref_count > 0);
1962c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->ref_count++;
1963c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return sdkctl->ref_count;
1964c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1965c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1966c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkineint
1967c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_socket_release(SDKCtlSocket* sdkctl)
1968c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1969c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    assert(sdkctl->ref_count > 0);
1970c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->ref_count--;
1971c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->ref_count == 0) {
1972c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Last reference has been dropped. Destroy this object. */
1973c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _sdkctl_socket_free(sdkctl);
1974c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return 0;
1975c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1976c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return sdkctl->ref_count;
1977c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1978c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1979c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinevoid
1980c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_init_recycler(SDKCtlSocket* sdkctl,
1981c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                     uint32_t data_size,
1982c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                     int max_recycled_num)
1983c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
1984c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->recycler != NULL) {
1985c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("SDKCtl %s: Recycler is already initialized. Ignoring recycler init.",
1986c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          sdkctl->service_name);
1987c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return;
1988c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
1989c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1990c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* SDKCtlQuery is max descriptor sizeof. */
1991c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    data_size += sizeof(SDKCtlQuery);
1992c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1993c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_block_size = data_size;
1994c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_max        = max_recycled_num;
1995c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->recycler_count      = 0;
1996c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
1997c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1998c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinevoid
1999c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_socket_connect(SDKCtlSocket* sdkctl, int port, int retry_to)
2000c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
2001c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Handling connect request to port %d, retrying in %dms...",
2002c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      sdkctl->service_name, port, retry_to);
2003c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2004c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->state = SDKCTL_SOCKET_CONNECTING;
2005c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    sdkctl->as = async_socket_new(port, sdkctl->reconnect_to,
2006c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                  _on_async_socket_connection, sdkctl,
2007c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                  sdkctl->looper);
2008c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->as == NULL) {
2009c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        E("Unable to allocate AsyncSocket for SDKCtl socket '%s'",
2010c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine           sdkctl->service_name);
20117136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED);
2012c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
2013c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_connect(sdkctl->as, retry_to);
2014c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
2015c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
2016c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2017c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinevoid
2018c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_socket_reconnect(SDKCtlSocket* sdkctl, int port, int retry_to)
2019c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
2020c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Handling reconnection request to port %d, retrying in %dms...",
2021c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      sdkctl->service_name, port, retry_to);
2022c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2023c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_disconnect_socket(sdkctl);
2024c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2025c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (sdkctl->as == NULL) {
2026c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_socket_connect(sdkctl, port, retry_to);
2027c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
2028c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl->state = SDKCTL_SOCKET_CONNECTING;
2029c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_reconnect(sdkctl->as, retry_to);
2030c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
2031c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
2032c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2033c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinevoid
2034c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinesdkctl_socket_disconnect(SDKCtlSocket* sdkctl)
2035c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
2036c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("SDKCtl %s: Handling disconnect request.", sdkctl->service_name);
2037c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2038c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _sdkctl_socket_disconnect_socket(sdkctl);
2039c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
2040c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
20417136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineint
20427136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_socket_is_connected(SDKCtlSocket* sdkctl)
20437136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
20447136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return (sdkctl->state == SDKCTL_SOCKET_CONNECTED) ? 1 : 0;
20457136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
20467136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
20477136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineint
20487136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_socket_is_port_ready(SDKCtlSocket* sdkctl)
20497136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
20507136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return (sdkctl->port_status == SDKCTL_PORT_ENABLED) ? 1 : 0;
20517136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
20527136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
20537136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir ChtchetkineSdkCtlPortStatus
20547136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_socket_get_port_status(SDKCtlSocket* sdkctl)
20557136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
20567136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return sdkctl->port_status;
20577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
20587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
20597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineint
20607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkinesdkctl_socket_is_handshake_ok(SDKCtlSocket* sdkctl)
20617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
20627136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    switch (sdkctl->port_status) {
20637136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case SDKCTL_HANDSHAKE_DUP:
20647136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case SDKCTL_HANDSHAKE_UNKNOWN_QUERY:
20657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        case SDKCTL_HANDSHAKE_UNKNOWN_RESPONSE:
20667136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            return 0;
20677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        default:
20687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        return 1;
20697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    }
20707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
2071c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2072c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/********************************************************************************
2073c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *                       Handshake query
2074c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine *******************************************************************************/
2075c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
20767136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/*
20777136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine * Handshake result values.
20787136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine */
20797136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
20807136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Handshake has succeeded completed, and service-side port is connected. */
20817136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine#define SDKCTL_HANDSHAKE_RESP_CONNECTED         0
20827136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Handshake has succeeded completed, but service-side port is not connected. */
20837136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine#define SDKCTL_HANDSHAKE_RESP_NOPORT            1
20847136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Handshake has failed due to duplicate connection request. */
20857136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine#define SDKCTL_HANDSHAKE_RESP_DUP               -1
20867136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine/* Handshake has failed due to unknown query. */
20877136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine#define SDKCTL_HANDSHAKE_RESP_QUERY_UNKNOWN     -2
20887136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
2089c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* A callback that is ivoked on handshake I/O events. */
2090c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
2091c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_handshake_io(void* query_opaque,
2092c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 SDKCtlQuery* query,
2093c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 AsyncIOState status)
2094c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
2095c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = (SDKCtlSocket*)query_opaque;
2096c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2097c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (status == ASIO_STATE_SUCCEEDED) {
20987136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        const int* res = (const int*)(*query->response_buffer);
20997136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        SdkCtlPortStatus handshake_status;
21007136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        switch (*res) {
21017136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            case SDKCTL_HANDSHAKE_RESP_CONNECTED:
21027136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                D("SDKCtl %s: Handshake succeeded. Port is connected",
21037136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                  sdkctl->service_name);
21047136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                handshake_status = SDKCTL_HANDSHAKE_CONNECTED;
21057136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                break;
21067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
21077136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            case SDKCTL_HANDSHAKE_RESP_NOPORT:
21087136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                D("SDKCtl %s: Handshake succeeded. Port is not connected",
21097136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                  sdkctl->service_name);
21107136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                handshake_status = SDKCTL_HANDSHAKE_NO_PORT;
21117136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                break;
21127136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
21137136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            case SDKCTL_HANDSHAKE_RESP_DUP:
21147136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                D("SDKCtl %s: Handshake failed: duplicate connection.",
21157136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                  sdkctl->service_name);
21167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                handshake_status = SDKCTL_HANDSHAKE_DUP;
21177136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                break;
2118c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
21197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            case SDKCTL_HANDSHAKE_RESP_QUERY_UNKNOWN:
21207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                D("SDKCtl %s: Handshake failed: unknown query.",
21217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                  sdkctl->service_name);
21227136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                handshake_status = SDKCTL_HANDSHAKE_UNKNOWN_QUERY;
21237136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                break;
21247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
21257136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            default:
21267136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                E("SDKCtl %s: Unknown handshake response: %d",
21277136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                  sdkctl->service_name, *res);
21287136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                handshake_status = SDKCTL_HANDSHAKE_UNKNOWN_RESPONSE;
21297136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                break;
21307136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        }
21317136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->port_status = handshake_status;
21327136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        sdkctl->on_port_connection(sdkctl->opaque, sdkctl, handshake_status);
2133c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
2134c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Something is going on with the handshake... */
2135c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        switch (status) {
2136c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_FAILED:
2137c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_TIMED_OUT:
2138c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            case ASIO_STATE_CANCELLED:
2139c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              D("SDKCtl %s: Handshake failed: I/O state %d. Error: %d -> %s",
2140c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                sdkctl->service_name, status, errno, strerror(errno));
21417136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                sdkctl->on_socket_connection(sdkctl->opaque, sdkctl,
21427136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                                             ASIO_STATE_FAILED);
2143c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
2144c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2145c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            default:
2146c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                break;
2147c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
2148c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
2149c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
2150c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
2151c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2152c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic AsyncIOAction
2153c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_on_sdkctl_endianness_io(void* io_opaque,
2154c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                         AsyncSocketIO* asio,
2155c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                         AsyncIOState status) {
2156c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    SDKCtlSocket* const sdkctl = (SDKCtlSocket*)io_opaque;
2157c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2158c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (status == ASIO_STATE_SUCCEEDED) {
2159c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Now it's time to initiate handshake message. */
2160c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("SDKCtl %s: Sending handshake query...", sdkctl->service_name);
2161c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        SDKCtlQuery* query =
2162c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            sdkctl_query_build_and_send(sdkctl, SDKCTL_QUERY_HANDSHAKE,
2163c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                        strlen(sdkctl->service_name),
2164c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                        sdkctl->service_name, NULL, NULL,
2165c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                        _on_handshake_io, sdkctl, 3000);
2166c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        sdkctl_query_release(query);
2167c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        return ASIO_ACTION_DONE;
2168c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
2169c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Something is going on with the endianness... */
2170c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        switch (status) {
2171c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                case ASIO_STATE_FAILED:
2172c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                case ASIO_STATE_TIMED_OUT:
2173c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                case ASIO_STATE_CANCELLED:
2174c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                  D("SDKCtl %s: endianness failed: I/O state %d. Error: %d -> %s",
2175c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    sdkctl->service_name, status, errno, strerror(errno));
21767136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine                    sdkctl->on_socket_connection(sdkctl->opaque, sdkctl, ASIO_STATE_FAILED);
2177c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    break;
2178c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2179c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                default:
2180c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                    break;
2181c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
2182c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    }
2183c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    return ASIO_ACTION_DONE;
2184c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
2185c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2186c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
2187c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_sdkctl_do_handshake(SDKCtlSocket* sdkctl)
2188c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
2189c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#ifndef HOST_WORDS_BIGENDIAN
2190c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic const char _host_end = 0;
2191c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#else
2192c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic const char _host_end = 1;
2193c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#endif
2194c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
21957136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    D("SDKCtl %s: Sending endianness: %d", sdkctl->service_name, _host_end);
2196c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
2197c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Before we can send any structured data to the SDK controller we need to
2198c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine     * report endianness of the host. */
2199c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    async_socket_write_rel(sdkctl->as, &_host_end, 1,
2200c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                           _on_sdkctl_endianness_io, sdkctl, 3000);
2201c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
2202