1a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/*
2a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Copyright (C) 2012 The Android Open Source Project
3a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *
4a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Licensed under the Apache License, Version 2.0 (the "License");
5a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * you may not use this file except in compliance with the License.
6a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * You may obtain a copy of the License at
7a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *
8a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *      http://www.apache.org/licenses/LICENSE-2.0
9a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *
10a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Unless required by applicable law or agreed to in writing, software
11a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * distributed under the License is distributed on an "AS IS" BASIS,
12a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * See the License for the specific language governing permissions and
14a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * limitations under the License.
15a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
16a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
17a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/*
18a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Encapsulates exchange protocol between the emulator, and an Android device
19a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * that is connected to the host via USB. The communication is established over
20a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * a TCP port forwarding, enabled by ADB.
21a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
22a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
23a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#include "android/async-socket-connector.h"
24a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#include "android/async-socket.h"
25af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include "android/utils/debug.h"
26af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include "android/utils/eintr_wrapper.h"
27af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include "android/utils/panic.h"
28d413fa5f2916a2a46494edb320340486b262644cDavid 'Digit' Turner#include "android/iolooper.h"
29a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
30a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#define  E(...)    derror(__VA_ARGS__)
31a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#define  W(...)    dwarning(__VA_ARGS__)
32a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#define  D(...)    VERBOSE_PRINT(asyncsocket,__VA_ARGS__)
33a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine#define  D_ACTIVE  VERBOSE_CHECK(asyncsocket)
34a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
35c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define TRACE_ON    0
36c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
37c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#if TRACE_ON
38c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  T(...)    VERBOSE_PRINT(asyncsocket,__VA_ARGS__)
39c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#else
40c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  T(...)
41c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#endif
42c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
43a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/********************************************************************************
44a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *                  Asynchronous Socket internal API declarations
45a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *******************************************************************************/
46a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
47a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Gets socket's address string. */
48a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic const char* _async_socket_string(AsyncSocket* as);
49a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
50a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Gets socket's looper. */
51a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic Looper* _async_socket_get_looper(AsyncSocket* as);
52a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
53a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Handler for the I/O time out.
54a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
556dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *  as - Asynchronous socket for the I/O.
56a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  asio - Desciptor for the timed out I/O.
57a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
586dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction _async_socket_io_timed_out(AsyncSocket* as,
596dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                                AsyncSocketIO* asio);
60a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
61a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/********************************************************************************
62a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *                  Asynchronous Socket Reader / Writer
63a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *******************************************************************************/
64a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
65a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestruct AsyncSocketIO {
66a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Next I/O in the reader, or writer list. */
67a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO*      next;
68a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Asynchronous socket for this I/O. */
69a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocket*        as;
70a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Timer used for time outs on this I/O. */
71a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    LoopTimer           timer[1];
72a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* An opaque pointer associated with this I/O. */
73a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    void*               io_opaque;
74a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Buffer where to read / write data. */
75a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    uint8_t*            buffer;
76a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Bytes to transfer through the socket for this I/O. */
77a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    uint32_t            to_transfer;
78a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Bytes thransferred through the socket in this I/O. */
79a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    uint32_t            transferred;
806dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    /* I/O callback for this I/O. */
816dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    on_as_io_cb         on_io;
82a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* I/O type selector: 1 - read, 0 - write. */
83a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    int                 is_io_read;
846dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    /* State of the I/O. */
856dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    AsyncIOState        state;
86ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Number of outstanding references to the I/O. */
87ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    int                 ref_count;
88ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Deadline for this I/O */
89ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    Duration            deadline;
90a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine};
91a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
92a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/*
93a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Recycling I/O instances.
94a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Since AsyncSocketIO instances are not that large, it makes sence to recycle
95a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * them for faster allocation, rather than allocating and freeing them for each
96a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * I/O on the socket.
97a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
98a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
99a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* List of recycled I/O descriptors. */
100a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO* _asio_recycled    = NULL;
101a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Number of I/O descriptors that are recycled in the _asio_recycled list. */
102a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic int _recycled_asio_count         = 0;
103a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Maximum number of I/O descriptors that can be recycled. */
104a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic const int _max_recycled_asio_num = 32;
105a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
106a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Handler for an I/O time-out timer event.
107a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * When this routine is invoked, it indicates that a time out has occurred on an
108a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * I/O.
109a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
110a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  opaque - AsyncSocketIO instance representing the timed out I/O.
111a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
112a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void _on_async_socket_io_timed_out(void* opaque);
113a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
114a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Creates new I/O descriptor.
115a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
116a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Asynchronous socket for the I/O.
117a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  is_io_read - I/O type selector: 1 - read, 0 - write.
118a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  buffer, len - Reader / writer buffer address.
1196dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *  io_cb - Callback for this reader / writer.
120a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  io_opaque - An opaque pointer associated with the I/O.
121a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  deadline - Deadline to complete the I/O.
122a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return:
123a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  Initialized AsyncSocketIO instance.
124a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
125a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO*
126a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_rw_new(AsyncSocket* as,
127a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                     int is_io_read,
128a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                     void* buffer,
129a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                     uint32_t len,
1306dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                     on_as_io_cb io_cb,
131a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                     void* io_opaque,
132a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                     Duration deadline)
133a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
134a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Lookup in the recycler first. */
135a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* asio = _asio_recycled;
136a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (asio != NULL) {
137a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* Pull the descriptor from recycler. */
138a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _asio_recycled = asio->next;
139a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _recycled_asio_count--;
140a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    } else {
141a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* No recycled descriptors. Allocate new one. */
142a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        ANEW0(asio);
143a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
144a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
145a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    asio->next          = NULL;
146a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    asio->as            = as;
147a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    asio->is_io_read    = is_io_read;
148a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    asio->buffer        = (uint8_t*)buffer;
149a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    asio->to_transfer   = len;
150a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    asio->transferred   = 0;
1516dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    asio->on_io         = io_cb;
152a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    asio->io_opaque     = io_opaque;
1536dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    asio->state         = ASIO_STATE_QUEUED;
154ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    asio->ref_count     = 1;
155ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    asio->deadline      = deadline;
156a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    loopTimer_init(asio->timer, _async_socket_get_looper(as),
157a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                   _on_async_socket_io_timed_out, asio);
158a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    loopTimer_startAbsolute(asio->timer, deadline);
159a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
160ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Reference socket that is holding this I/O. */
161ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_reference(as);
162ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
163c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: %s I/O descriptor %p is created for %d bytes of data",
164c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _async_socket_string(as), is_io_read ? "READ" : "WRITE", asio, len);
165c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
166a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return asio;
167a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
168a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
169a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Destroys and frees I/O descriptor. */
170a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void
171ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine_async_socket_io_free(AsyncSocketIO* asio)
172a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
173ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    AsyncSocket* const as = asio->as;
174ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
175c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: %s I/O descriptor %p is destroyed.",
176c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", asio);
177c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
178a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    loopTimer_done(asio->timer);
179a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
180a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Try to recycle it first, and free the memory if recycler is full. */
181a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (_recycled_asio_count < _max_recycled_asio_num) {
182a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        asio->next = _asio_recycled;
183a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _asio_recycled = asio;
184a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _recycled_asio_count++;
185a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    } else {
186a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        AFREE(asio);
187a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
188ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
189ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Release socket that is holding this I/O. */
190ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_release(as);
191ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine}
192ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
193c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine/* An I/O has been finished and its descriptor is about to be discarded. */
194c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkinestatic void
195c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine_async_socket_io_finished(AsyncSocketIO* asio)
196c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine{
197c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Notify the client of the I/O that I/O is finished. */
198c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    asio->on_io(asio->io_opaque, asio, ASIO_STATE_FINISHED);
199c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine}
200c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
201ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint
202ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_io_reference(AsyncSocketIO* asio)
203ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{
204ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    assert(asio->ref_count > 0);
205ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    asio->ref_count++;
206ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    return asio->ref_count;
207ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine}
208ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
209ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint
210ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_io_release(AsyncSocketIO* asio)
211ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{
212ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    assert(asio->ref_count > 0);
213ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    asio->ref_count--;
214ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    if (asio->ref_count == 0) {
215c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        _async_socket_io_finished(asio);
216ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        /* Last reference has been dropped. Destroy this object. */
217ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        _async_socket_io_free(asio);
218ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        return 0;
219ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    }
220ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    return asio->ref_count;
221a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
222a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
223a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Creates new asynchronous socket reader.
224a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
225a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Asynchronous socket for the reader.
226a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  buffer, len - Reader's buffer.
2276dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *  io_cb - Reader's callback.
228a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  reader_opaque - An opaque pointer associated with the reader.
229a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  deadline - Deadline to complete the operation.
230a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return:
231a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  An initialized AsyncSocketIO intance.
232a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
233a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO*
234a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_reader_new(AsyncSocket* as,
235a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                         void* buffer,
236a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                         uint32_t len,
2376dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                         on_as_io_cb io_cb,
238a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                         void* reader_opaque,
239a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                         Duration deadline)
240a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
241a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* const asio = _async_socket_rw_new(as, 1, buffer, len, io_cb,
242a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                                                     reader_opaque, deadline);
243a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return asio;
244a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
245a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
246a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Creates new asynchronous socket writer.
247a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
248a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Asynchronous socket for the writer.
249a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  buffer, len - Writer's buffer.
2506dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *  io_cb - Writer's callback.
251a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  writer_opaque - An opaque pointer associated with the writer.
252a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  deadline - Deadline to complete the operation.
253a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return:
254a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  An initialized AsyncSocketIO intance.
255a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
256a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO*
257a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_writer_new(AsyncSocket* as,
258a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                         const void* buffer,
259a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                         uint32_t len,
2606dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                         on_as_io_cb io_cb,
261a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                         void* writer_opaque,
262a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                         Duration deadline)
263a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
264a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* const asio = _async_socket_rw_new(as, 0, (void*)buffer, len,
265a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                                                     io_cb, writer_opaque,
266a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                                                     deadline);
267a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return asio;
268a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
269a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
270a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* I/O timed out. */
271a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void
272a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_io_timed_out(void* opaque)
273a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
274a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* const asio = (AsyncSocketIO*)opaque;
275ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    AsyncSocket* const as = asio->as;
276ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
277c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("ASocket %s: %s I/O with deadline %lld has timed out at %lld",
278ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine      _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE",
279ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine      asio->deadline, async_socket_deadline(as, 0));
280ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
281ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Reference while in callback. */
282ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_io_reference(asio);
283ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    _async_socket_io_timed_out(asio->as, asio);
284ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_io_release(asio);
2856dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
2866dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
2876dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine/********************************************************************************
2886dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *                 Public Asynchronous Socket I/O API
2896dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *******************************************************************************/
2906dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
2916dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir ChtchetkineAsyncSocket*
2926dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_socket(const AsyncSocketIO* asio)
2936dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
294ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_reference(asio->as);
2956dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return asio->as;
2966dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
2976dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
2986dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid
2996dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_cancel_time_out(AsyncSocketIO* asio)
3006dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
3016dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    loopTimer_stop(asio->timer);
3026dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
3036dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
3046dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid*
3056dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_io_opaque(const AsyncSocketIO* asio)
3066dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
3076dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return asio->io_opaque;
3086dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
3096dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
3106dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid*
3116dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_client_opaque(const AsyncSocketIO* asio)
3126dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
3136dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return async_socket_get_client_opaque(asio->as);
3146dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
3156dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
3166dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid*
3176dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_buffer_info(const AsyncSocketIO* asio,
3186dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                uint32_t* transferred,
3196dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                uint32_t* to_transfer)
3206dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
3216dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (transferred != NULL) {
3226dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        *transferred = asio->transferred;
3236dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    }
3246dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (to_transfer != NULL) {
3256dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        *to_transfer = asio->to_transfer;
3266dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    }
3276dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return asio->buffer;
3286dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
3296dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
3306dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid*
3316dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_buffer(const AsyncSocketIO* asio)
3326dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
3336dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return asio->buffer;
3346dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
3356dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
3366dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineuint32_t
3376dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_transferred(const AsyncSocketIO* asio)
3386dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
3396dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return asio->transferred;
3406dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
3416dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
3426dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineuint32_t
3436dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_get_to_transfer(const AsyncSocketIO* asio)
3446dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
3456dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return asio->to_transfer;
3466dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
3476dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
3486dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineint
3496dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_io_is_read(const AsyncSocketIO* asio)
3506dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
3516dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return asio->is_io_read;
352a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
353a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
354a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/********************************************************************************
355a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *                      Asynchronous Socket internals
356a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *******************************************************************************/
357a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
358a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestruct AsyncSocket {
359a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* TCP address for the socket. */
360a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    SockAddress         address;
3616dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    /* Connection callback for this socket. */
3626dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    on_as_connection_cb on_connection;
363a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* An opaque pointer associated with this socket by the client. */
364a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    void*               client_opaque;
365a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* I/O looper for asynchronous I/O on the socket. */
366a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    Looper*             looper;
367a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* I/O descriptor for asynchronous I/O on the socket. */
368a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    LoopIo              io[1];
369a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Timer to use for reconnection attempts. */
370a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    LoopTimer           reconnect_timer[1];
371a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Head of the list of the active readers. */
372a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO*      readers_head;
373a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Tail of the list of the active readers. */
374a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO*      readers_tail;
375a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Head of the list of the active writers. */
376a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO*      writers_head;
377a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Tail of the list of the active writers. */
378a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO*      writers_tail;
379a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Socket's file descriptor. */
380a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    int                 fd;
381a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Timeout to use for reconnection attempts. */
382a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    int                 reconnect_to;
383ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Number of outstanding references to the socket. */
384ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    int                 ref_count;
385c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Flags whether (1) or not (0) socket owns the looper. */
386c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int                 owns_looper;
387a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine};
388a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
389a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic const char*
390a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_string(AsyncSocket* as)
391a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
392a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return sock_address_to_string(&as->address);
393a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
394a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
395a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic Looper*
396a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_get_looper(AsyncSocket* as)
397a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
398a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return as->looper;
399a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
400a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
401a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Pulls first reader out of the list.
402a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
403a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
404a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return:
405a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  First I/O pulled out of the list, or NULL if there are no I/O in the list.
406ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine *  Note that the caller is responsible for releasing the I/O object returned
407ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine *  from this routine.
408a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
409a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO*
410a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_pull_first_io(AsyncSocket* as,
411a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                            AsyncSocketIO** list_head,
412a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                            AsyncSocketIO** list_tail)
413a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
414a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* const ret = *list_head;
415a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (ret != NULL) {
416a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        *list_head = ret->next;
417a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        ret->next = NULL;
418a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        if (*list_head == NULL) {
419a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine            *list_tail = NULL;
420a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        }
421a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
422a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return ret;
423a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
424a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
425a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Pulls first reader out of the list.
426a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
427a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
428a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return:
429a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  First reader pulled out of the list, or NULL if there are no readers in the
430a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  list.
431ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine *  Note that the caller is responsible for releasing the I/O object returned
432ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine *  from this routine.
433a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
434a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO*
435a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_pull_first_reader(AsyncSocket* as)
436a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
437a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return _async_socket_pull_first_io(as, &as->readers_head, &as->readers_tail);
438a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
439a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
440a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Pulls first writer out of the list.
441a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
442a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
443a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return:
444a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  First writer pulled out of the list, or NULL if there are no writers in the
445a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  list.
446ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine *  Note that the caller is responsible for releasing the I/O object returned
447ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine *  from this routine.
448a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
449a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic AsyncSocketIO*
450a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_pull_first_writer(AsyncSocket* as)
451a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
452a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return _async_socket_pull_first_io(as, &as->writers_head, &as->writers_tail);
453a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
454a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
455a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Removes an I/O descriptor from a list of active I/O.
456a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
457a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
458a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  list_head, list_tail - Pointers to the list head and tail.
459a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  io - I/O to remove.
460a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return:
461a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  Boolean: 1 if I/O has been removed, or 0 if I/O has not been found in the list.
462a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
463a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic int
464a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_remove_io(AsyncSocket* as,
465a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                        AsyncSocketIO** list_head,
466a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                        AsyncSocketIO** list_tail,
467a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                        AsyncSocketIO* io)
468a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
469a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* prev = NULL;
470a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
471a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    while (*list_head != NULL && io != *list_head) {
472a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        prev = *list_head;
473a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        list_head = &((*list_head)->next);
474a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
475a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (*list_head == NULL) {
476a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        D("%s: I/O %p is not found in the list for socket '%s'",
477a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine          __FUNCTION__, io, _async_socket_string(as));
478a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        return 0;
479a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
480a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
481a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    *list_head = io->next;
482a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (prev != NULL) {
483a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        prev->next = io->next;
484a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
485a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (*list_tail == io) {
486a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        *list_tail = prev;
487a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
488a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
489ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Release I/O adjusting reference added when I/O has been saved in the list. */
490ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_io_release(io);
491ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
492a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return 1;
493a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
494a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
495a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Advances to the next I/O in the list.
496a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
497a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
498a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  list_head, list_tail - Pointers to the list head and tail.
499a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
500ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkinestatic void
501a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_advance_io(AsyncSocket* as,
502a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                         AsyncSocketIO** list_head,
503a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                         AsyncSocketIO** list_tail)
504a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
505a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* first_io = *list_head;
506a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (first_io != NULL) {
507a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        *list_head = first_io->next;
508a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        first_io->next = NULL;
509a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
510a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (*list_head == NULL) {
511a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        *list_tail = NULL;
512a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
513ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    if (first_io != NULL) {
514ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        /* Release I/O removed from the head of the list. */
515ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        async_socket_io_release(first_io);
516ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    }
517a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
518a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
519a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Advances to the next reader in the list.
520a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
521a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
522a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
523ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkinestatic void
524a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_advance_reader(AsyncSocket* as)
525a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
526ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    _async_socket_advance_io(as, &as->readers_head, &as->readers_tail);
527a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
528a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
529a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Advances to the next writer in the list.
530a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
531a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
532a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
533ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkinestatic void
534a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_advance_writer(AsyncSocket* as)
535a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
536ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    _async_socket_advance_io(as, &as->writers_head, &as->writers_tail);
537a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
538a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
539a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Completes an I/O.
540a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
541a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
542a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  asio - I/O to complete.
5436dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * Return:
5446dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *  One of AsyncIOAction values.
545a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
5466dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction
547a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_complete_io(AsyncSocket* as, AsyncSocketIO* asio)
548a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
549c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: %s I/O %p is completed.",
550c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", asio);
551c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
552a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Stop the timer. */
553c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    async_socket_io_cancel_time_out(asio);
554a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
5556dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return asio->on_io(asio->io_opaque, asio, ASIO_STATE_SUCCEEDED);
556a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
557a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
558a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Timeouts an I/O.
559a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
560a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
561a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  asio - An I/O that has timed out.
5626dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * Return:
5636dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *  One of AsyncIOAction values.
564a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
5656dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction
566a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_io_timed_out(AsyncSocket* as, AsyncSocketIO* asio)
567a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
568c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: %s I/O %p with deadline %lld has timed out at %lld",
569c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", asio,
570c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      asio->deadline, async_socket_deadline(as, 0));
571c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
5726dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    /* Report to the client. */
5736dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    const AsyncIOAction action = asio->on_io(asio->io_opaque, asio,
5746dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                             ASIO_STATE_TIMED_OUT);
5756dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
5766dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    /* Remove the I/O from a list of active I/O for actions other than retry. */
5776dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (action != ASIO_ACTION_RETRY) {
5786dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        if (asio->is_io_read) {
5796dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            _async_socket_remove_io(as, &as->readers_head, &as->readers_tail, asio);
5806dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        } else {
5816dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            _async_socket_remove_io(as, &as->writers_head, &as->writers_tail, asio);
5826dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        }
583a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
584a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
5856dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return action;
586a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
587a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
588a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Cancels an I/O.
589a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
590a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
591a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  asio - An I/O to cancel.
5926dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * Return:
5936dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *  One of AsyncIOAction values.
594a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
5956dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction
596a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_cancel_io(AsyncSocket* as, AsyncSocketIO* asio)
597a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
598c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: %s I/O %p is cancelled.",
599c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", asio);
600c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
601a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Stop the timer. */
602c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    async_socket_io_cancel_time_out(asio);
603a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
6046dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return asio->on_io(asio->io_opaque, asio, ASIO_STATE_CANCELLED);
605a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
606a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
607a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Reports an I/O failure.
608a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
609a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
610a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  asio - An I/O that has failed. Can be NULL for general failures.
611a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  failure - Failure (errno) that has occurred.
6126dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine * Return:
6136dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *  One of AsyncIOAction values.
614a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
6156dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction
616a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_io_failure(AsyncSocket* as, AsyncSocketIO* asio, int failure)
617a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
618c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: %s I/O %p has failed: %d -> %s",
619c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE", asio,
620c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      failure, strerror(failure));
621c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
622a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Stop the timer. */
623c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    async_socket_io_cancel_time_out(asio);
624a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
6256dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    errno = failure;
6266dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return asio->on_io(asio->io_opaque, asio, ASIO_STATE_FAILED);
627a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
628a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
629a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Cancels all the active socket readers.
630a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
631a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
632a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
633a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void
634a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_cancel_readers(AsyncSocket* as)
635a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
636a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    while (as->readers_head != NULL) {
637a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        AsyncSocketIO* const to_cancel = _async_socket_pull_first_reader(as);
6386dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        /* We ignore action returned from the cancellation callback, since we're
6396dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine         * in a disconnected state here. */
640a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_cancel_io(as, to_cancel);
641ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        async_socket_io_release(to_cancel);
642a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
643a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
644a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
645a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Cancels all the active socket writers.
646a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
647a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
648a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
649a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void
650a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_cancel_writers(AsyncSocket* as)
651a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
652a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    while (as->writers_head != NULL) {
653a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        AsyncSocketIO* const to_cancel = _async_socket_pull_first_writer(as);
6546dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        /* We ignore action returned from the cancellation callback, since we're
6556dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine         * in a disconnected state here. */
656a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_cancel_io(as, to_cancel);
657ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        async_socket_io_release(to_cancel);
658a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
659a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
660a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
661a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Cancels all the I/O on the socket. */
662a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void
663a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_cancel_all_io(AsyncSocket* as)
664a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
665a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Stop the reconnection timer. */
666a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    loopTimer_stop(as->reconnect_timer);
667a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
668a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Stop read / write on the socket. */
669a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    loopIo_dontWantWrite(as->io);
670a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    loopIo_dontWantRead(as->io);
671a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
672a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Cancel active readers and writers. */
673a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    _async_socket_cancel_readers(as);
674a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    _async_socket_cancel_writers(as);
675a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
676a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
677a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Closes socket handle used by the async socket.
678a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
679a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
680a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
681a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void
682a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_close_socket(AsyncSocket* as)
683a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
684a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (as->fd >= 0) {
685c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        T("ASocket %s: Socket handle %d is closed.",
686c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          _async_socket_string(as), as->fd);
6877136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        loopIo_done(as->io);
6887136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        socket_close(as->fd);
689a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        as->fd = -1;
690a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
691a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
692a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
693a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Destroys AsyncSocket instance.
694a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
695a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
696a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
697a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void
698ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine_async_socket_free(AsyncSocket* as)
699a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
700a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (as != NULL) {
701c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        T("ASocket %s: Socket descriptor is destroyed.", _async_socket_string(as));
702a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
703a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* Close socket. */
704a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_close_socket(as);
705a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
706a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* Free allocated resources. */
707a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        if (as->looper != NULL) {
708a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine            loopTimer_done(as->reconnect_timer);
709c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            if (as->owns_looper) {
710c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                looper_free(as->looper);
711c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            }
712a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        }
713a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        sock_address_done(&as->address);
714a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        AFREE(as);
715a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
716a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
717a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
718a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Starts reconnection attempts after connection has been lost.
719a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
720a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
721a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  to - Milliseconds to wait before reconnection attempt.
722a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
723a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void
724a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_async_socket_reconnect(AsyncSocket* as, int to)
725a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
726c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: reconnecting in %dms...", _async_socket_string(as), to);
727c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
728a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Make sure that no I/O is active, and socket is closed before we
729a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine     * reconnect. */
730a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    _async_socket_cancel_all_io(as);
731a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
732a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Set the timer for reconnection attempt. */
733a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    loopTimer_startRelative(as->reconnect_timer, to);
734a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
735a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
736a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/********************************************************************************
737a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *                      Asynchronous Socket callbacks
738a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *******************************************************************************/
739a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
740a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked when socket gets disconnected.
741a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
742a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
743a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
744a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void
745a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_disconnected(AsyncSocket* as)
746a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
747a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Save error to restore it for the client's callback. */
748a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    const int save_errno = errno;
7496dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    AsyncIOAction action = ASIO_ACTION_ABORT;
750a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
751c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("ASocket %s: Disconnected.", _async_socket_string(as));
752a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
753a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Cancel all the I/O on this socket. */
754a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    _async_socket_cancel_all_io(as);
755a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
756a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Close the socket. */
757a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    _async_socket_close_socket(as);
758a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
759a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Restore errno, and invoke client's callback. */
760a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    errno = save_errno;
7616dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    action = as->on_connection(as->client_opaque, as, ASIO_STATE_FAILED);
762a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
7636dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (action == ASIO_ACTION_RETRY) {
764a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* Client requested reconnection. */
7656dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        _async_socket_reconnect(as, as->reconnect_to);
766a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
767a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
768a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
769a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked on socket's I/O failure.
770a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
771a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
772a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  asio - Descriptor for the failed I/O. Can be NULL for general failures.
773a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
7746dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction
775a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_failure(AsyncSocket* as, AsyncSocketIO* asio)
776a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
777c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    D("ASocket %s: %s I/O failure: %d -> %s",
778ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine      _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE",
779ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine      errno, strerror(errno));
780a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
781a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Report the failure. */
7826dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return _async_socket_io_failure(as, asio, errno);
783a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
784a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
785a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked when there is data available to read.
786a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
787a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
788a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return:
789a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  0 on success, or -1 on failure. Failure returned from this routine will
790a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  skip writes (if awailable) behind this read.
791a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
792a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic int
793a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_recv(AsyncSocket* as)
794a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
7956dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    AsyncIOAction action;
7966dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
797a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Get current reader. */
798a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* const asr = as->readers_head;
799a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (asr == NULL) {
800c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("ASocket %s: No reader is available.", _async_socket_string(as));
801a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        loopIo_dontWantRead(as->io);
802a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        return 0;
803a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
804a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
805ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Reference the reader while we're working with it in this callback. */
806ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_io_reference(asr);
807ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
8086dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    /* Bump I/O state, and inform the client that I/O is in progress. */
8096dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (asr->state == ASIO_STATE_QUEUED) {
8106dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        asr->state = ASIO_STATE_STARTED;
8116dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    } else {
8126dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        asr->state = ASIO_STATE_CONTINUES;
8136dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    }
8146dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    action = asr->on_io(asr->io_opaque, asr, asr->state);
8156dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (action == ASIO_ACTION_ABORT) {
816c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("ASocket %s: Read is aborted by the client.", _async_socket_string(as));
8176dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        /* Move on to the next reader. */
8186dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        _async_socket_advance_reader(as);
8196dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        /* Lets see if there are still active readers, and enable, or disable
8206dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine         * read I/O callback accordingly. */
8216dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        if (as->readers_head != NULL) {
8226dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            loopIo_wantRead(as->io);
8236dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        } else {
8246dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            loopIo_dontWantRead(as->io);
8256dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        }
826ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        async_socket_io_release(asr);
8276dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        return 0;
8286dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    }
8296dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
830a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Read next chunk of data. */
831af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    int res = HANDLE_EINTR(
832af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner            socket_recv(as->fd,
833af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner                        asr->buffer + asr->transferred,
834af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner                        asr->to_transfer - asr->transferred));
835a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (res == 0) {
836a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* Socket has been disconnected. */
837a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        errno = ECONNRESET;
838a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _on_async_socket_disconnected(as);
839ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        async_socket_io_release(asr);
840a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        return -1;
841a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
842a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
843a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (res < 0) {
844a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        if (errno == EWOULDBLOCK || errno == EAGAIN) {
845a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine            /* Yield to writes behind this read. */
846a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine            loopIo_wantRead(as->io);
847ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            async_socket_io_release(asr);
848a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine            return 0;
849a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        }
850a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
851a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* An I/O error. */
8526dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        action = _on_async_socket_failure(as, asr);
853c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (action != ASIO_ACTION_RETRY) {
854c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            D("ASocket %s: Read is aborted on failure.", _async_socket_string(as));
8556dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            /* Move on to the next reader. */
8566dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            _async_socket_advance_reader(as);
8576dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            /* Lets see if there are still active readers, and enable, or disable
8586dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine             * read I/O callback accordingly. */
8596dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            if (as->readers_head != NULL) {
8606dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                loopIo_wantRead(as->io);
8616dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            } else {
8626dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                loopIo_dontWantRead(as->io);
8636dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            }
8646dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        }
865ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        async_socket_io_release(asr);
866a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        return -1;
867a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
868a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
869a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Update the reader's descriptor. */
870a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    asr->transferred += res;
871a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (asr->transferred == asr->to_transfer) {
872a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* This read is completed. Move on to the next reader. */
873a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_advance_reader(as);
874a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
875a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* Notify reader completion. */
876a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_complete_io(as, asr);
877a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
878a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
879a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Lets see if there are still active readers, and enable, or disable read
880a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine     * I/O callback accordingly. */
881a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (as->readers_head != NULL) {
882a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        loopIo_wantRead(as->io);
883a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    } else {
884a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        loopIo_dontWantRead(as->io);
885a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
886a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
887ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_io_release(asr);
888ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
889a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return 0;
890a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
891a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
892a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked when there is data available to write.
893a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
894a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
895a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return:
896a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  0 on success, or -1 on failure. Failure returned from this routine will
897a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  skip reads (if awailable) behind this write.
898a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
899a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic int
900a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_send(AsyncSocket* as)
901a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
9026dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    AsyncIOAction action;
9036dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
904a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Get current writer. */
905a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* const asw = as->writers_head;
906a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (asw == NULL) {
907c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("ASocket %s: No writer is available.", _async_socket_string(as));
908a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        loopIo_dontWantWrite(as->io);
909a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        return 0;
910a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
911a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
912ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Reference the writer while we're working with it in this callback. */
913ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_io_reference(asw);
914ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
9156dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    /* Bump I/O state, and inform the client that I/O is in progress. */
9166dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (asw->state == ASIO_STATE_QUEUED) {
9176dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        asw->state = ASIO_STATE_STARTED;
9186dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    } else {
9196dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        asw->state = ASIO_STATE_CONTINUES;
9206dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    }
9216dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    action = asw->on_io(asw->io_opaque, asw, asw->state);
9226dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (action == ASIO_ACTION_ABORT) {
923c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("ASocket %s: Write is aborted by the client.", _async_socket_string(as));
924ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        /* Move on to the next writer. */
925ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        _async_socket_advance_writer(as);
9266dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        /* Lets see if there are still active writers, and enable, or disable
9276dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine         * write I/O callback accordingly. */
9286dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        if (as->writers_head != NULL) {
9296dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            loopIo_wantWrite(as->io);
9306dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        } else {
9316dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            loopIo_dontWantWrite(as->io);
9326dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        }
933ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        async_socket_io_release(asw);
9346dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        return 0;
9356dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    }
9366dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
937a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Write next chunk of data. */
938af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    int res = HANDLE_EINTR(
939af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner            socket_send(as->fd,
940af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner                        asw->buffer + asw->transferred,
941af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner                        asw->to_transfer - asw->transferred));
942a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (res == 0) {
943a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* Socket has been disconnected. */
944a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        errno = ECONNRESET;
945a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _on_async_socket_disconnected(as);
946ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        async_socket_io_release(asw);
947a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        return -1;
948a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
949a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
950a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (res < 0) {
951a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        if (errno == EWOULDBLOCK || errno == EAGAIN) {
952a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine            /* Yield to reads behind this write. */
953a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine            loopIo_wantWrite(as->io);
954ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            async_socket_io_release(asw);
955a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine            return 0;
956a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        }
957a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
958a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* An I/O error. */
9596dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        action = _on_async_socket_failure(as, asw);
960c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (action != ASIO_ACTION_RETRY) {
961c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            D("ASocket %s: Write is aborted on failure.", _async_socket_string(as));
962ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            /* Move on to the next writer. */
963ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            _async_socket_advance_writer(as);
9646dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            /* Lets see if there are still active writers, and enable, or disable
9656dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine             * write I/O callback accordingly. */
9666dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            if (as->writers_head != NULL) {
9676dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                loopIo_wantWrite(as->io);
9686dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            } else {
9696dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                loopIo_dontWantWrite(as->io);
9706dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            }
9716dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        }
972ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        async_socket_io_release(asw);
973a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        return -1;
974a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
975a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
976ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Update the writer descriptor. */
977a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    asw->transferred += res;
978a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (asw->transferred == asw->to_transfer) {
979a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* This write is completed. Move on to the next writer. */
980a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_advance_writer(as);
981a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
982a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* Notify writer completion. */
983a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_complete_io(as, asw);
984a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
985a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
986a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Lets see if there are still active writers, and enable, or disable write
987a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine     * I/O callback accordingly. */
988a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (as->writers_head != NULL) {
989a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        loopIo_wantWrite(as->io);
990a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    } else {
991a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        loopIo_dontWantWrite(as->io);
992a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
993a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
994ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_io_release(asw);
995ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
996a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return 0;
997a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
998a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
999a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked when an I/O is available on socket.
1000a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
1001a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
1002a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  fd - Socket's file descriptor.
1003a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  events - LOOP_IO_READ | LOOP_IO_WRITE bitmask.
1004a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
1005a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinestatic void
1006a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_io(void* opaque, int fd, unsigned events)
1007a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
1008a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocket* const as = (AsyncSocket*)opaque;
1009a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1010ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Reference the socket while we're working with it in this callback. */
1011ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_reference(as);
1012ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
1013a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if ((events & LOOP_IO_READ) != 0) {
1014a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        if (_on_async_socket_recv(as) != 0) {
1015ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            async_socket_release(as);
1016a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine            return;
1017a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        }
1018a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
1019a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1020a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if ((events & LOOP_IO_WRITE) != 0) {
1021a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        if (_on_async_socket_send(as) != 0) {
1022ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            async_socket_release(as);
1023a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine            return;
1024a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        }
1025a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
1026ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
1027ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_release(as);
1028a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1029a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1030a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* A callback that is invoked by asynchronous socket connector on connection
1031a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  events.
1032a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
1033a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  opaque - Initialized AsyncSocket instance.
1034a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  connector - Connector that is used to connect this socket.
1035a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  event - Connection event.
1036a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Return:
10376dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine *  One of AsyncIOAction values.
1038a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
10396dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinestatic AsyncIOAction
1040a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_connector_events(void* opaque,
1041a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                     AsyncSocketConnector* connector,
10426dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                     AsyncIOState event)
1043a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
10446dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    AsyncIOAction action;
1045a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocket* const as = (AsyncSocket*)opaque;
1046a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1047ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Reference the socket while we're working with it in this callback. */
1048ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_reference(as);
1049ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
10506dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (event == ASIO_STATE_SUCCEEDED) {
10516dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        /* Accept the connection. */
10526dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        as->fd = async_socket_connector_pull_fd(connector);
10536dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        loopIo_init(as->io, as->looper, as->fd, _on_async_socket_io, as);
1054a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
1055a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1056a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    /* Invoke client's callback. */
10576dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    action = as->on_connection(as->client_opaque, as, event);
10586dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (event == ASIO_STATE_SUCCEEDED && action != ASIO_ACTION_DONE) {
1059a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        /* For whatever reason the client didn't want to keep this connection.
1060a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine         * Close it. */
1061c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("ASocket %s: Connection is discarded by the client.",
1062c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          _async_socket_string(as));
1063a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_close_socket(as);
1064a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
1065a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1066ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    if (action != ASIO_ACTION_RETRY) {
1067ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        async_socket_connector_release(connector);
1068ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    }
1069ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
1070ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_release(as);
1071ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
10726dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return action;
1073a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1074a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1075a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/* Timer callback invoked to reconnect the lost connection.
1076a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine * Param:
1077a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *  as - Initialized AsyncSocket instance.
1078a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine */
1079a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinevoid
1080a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine_on_async_socket_reconnect(void* opaque)
1081a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
1082a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocket* as = (AsyncSocket*)opaque;
1083ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
1084ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Reference the socket while we're working with it in this callback. */
1085ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_reference(as);
1086a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    async_socket_connect(as, as->reconnect_to);
1087ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_release(as);
1088a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1089a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1090a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1091a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine/********************************************************************************
1092a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *                  Android Device Socket public API
1093a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine *******************************************************************************/
1094a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1095a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir ChtchetkineAsyncSocket*
1096a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_new(int port,
1097a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                 int reconnect_to,
10986dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                 on_as_connection_cb client_cb,
1099c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 void* client_opaque,
1100c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                 Looper* looper)
1101a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
1102a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocket* as;
1103a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
11046dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (client_cb == NULL) {
1105a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        E("Invalid client_cb parameter");
1106a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        return NULL;
1107a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
1108a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1109a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    ANEW0(as);
1110a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1111a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    as->fd = -1;
1112a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    as->client_opaque = client_opaque;
11136dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    as->on_connection = client_cb;
1114a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    as->readers_head = as->readers_tail = NULL;
1115a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    as->reconnect_to = reconnect_to;
1116ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    as->ref_count = 1;
1117a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    sock_address_init_inet(&as->address, SOCK_ADDRESS_INET_LOOPBACK, port);
1118c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (looper == NULL) {
1119c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        as->looper = looper_newCore();
1120c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (as->looper == NULL) {
1121c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            E("Unable to create I/O looper for async socket '%s'",
1122c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              _async_socket_string(as));
1123c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            client_cb(client_opaque, as, ASIO_STATE_FAILED);
1124c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _async_socket_free(as);
1125c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            return NULL;
1126c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
1127c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        as->owns_looper = 1;
1128c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
1129c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        as->looper = looper;
1130c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        as->owns_looper = 0;
1131a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
1132c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1133a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    loopTimer_init(as->reconnect_timer, as->looper, _on_async_socket_reconnect, as);
1134a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1135c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: Descriptor is created.", _async_socket_string(as));
1136c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1137a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    return as;
1138a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1139a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1140ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint
1141ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_reference(AsyncSocket* as)
1142ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{
1143ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    assert(as->ref_count > 0);
1144ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    as->ref_count++;
1145ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    return as->ref_count;
1146ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine}
1147ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
1148ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint
1149ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_release(AsyncSocket* as)
1150ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{
1151ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    assert(as->ref_count > 0);
1152ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    as->ref_count--;
1153ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    if (as->ref_count == 0) {
1154ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        /* Last reference has been dropped. Destroy this object. */
1155ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        _async_socket_cancel_all_io(as);
1156ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        _async_socket_free(as);
1157ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        return 0;
1158ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    }
1159ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    return as->ref_count;
1160ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine}
1161ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
11626dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid
1163a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_connect(AsyncSocket* as, int retry_to)
1164a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
1165c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: Handling connection request for %dms...",
1166c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _async_socket_string(as), retry_to);
1167c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1168a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketConnector* const connector =
1169c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        async_socket_connector_new(&as->address, retry_to, _on_connector_events,
1170c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                                   as, as->looper);
11716dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (connector != NULL) {
11726dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        async_socket_connector_connect(connector);
11736dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    } else {
11746dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        as->on_connection(as->client_opaque, as, ASIO_STATE_FAILED);
1175a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
1176a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1177a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
1178a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkinevoid
1179a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_disconnect(AsyncSocket* as)
1180a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
1181c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: Handling disconnection request...", _async_socket_string(as));
1182c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1183a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    if (as != NULL) {
1184a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_cancel_all_io(as);
1185a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_close_socket(as);
1186a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
1187a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1188a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
11896dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid
1190a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_reconnect(AsyncSocket* as, int retry_to)
1191a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
1192c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: Handling reconnection request for %dms...",
1193c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _async_socket_string(as), retry_to);
1194c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1195a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    _async_socket_cancel_all_io(as);
1196a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    _async_socket_close_socket(as);
1197c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    _async_socket_reconnect(as, retry_to);
1198a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1199a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
12006dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid
1201a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_read_abs(AsyncSocket* as,
1202a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                      void* buffer, uint32_t len,
12036dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                      on_as_io_cb reader_cb,
1204a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                      void* reader_opaque,
1205a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                      Duration deadline)
1206a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
1207c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: Handling read for %d bytes with deadline %lld...",
1208c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _async_socket_string(as), len, deadline);
1209c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1210a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* const asr =
1211a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_reader_new(as, buffer, len, reader_cb, reader_opaque,
1212a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                                 deadline);
12137136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (async_socket_is_connected(as)) {
12147136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Add new reader to the list. Note that we use initial reference from I/O
12157136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine         * 'new' routine as "in the list" reference counter. */
12167136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        if (as->readers_head == NULL) {
12177136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            as->readers_head = as->readers_tail = asr;
12187136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        } else {
12197136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            as->readers_tail->next = asr;
12207136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            as->readers_tail = asr;
12217136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        }
12227136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        loopIo_wantRead(as->io);
1223a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    } else {
12247136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        D("ASocket %s: Read on a disconnected socket.", _async_socket_string(as));
12257136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        errno = ECONNRESET;
12267136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        reader_cb(reader_opaque, asr, ASIO_STATE_FAILED);
12277136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        async_socket_io_release(asr);
1228a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
1229a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1230a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
12316dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid
1232a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_read_rel(AsyncSocket* as,
1233a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                      void* buffer, uint32_t len,
12346dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                      on_as_io_cb reader_cb,
1235a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                      void* reader_opaque,
1236a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                      int to)
1237a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
1238a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    const Duration dl = (to >= 0) ? looper_now(_async_socket_get_looper(as)) + to :
1239a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                                    DURATION_INFINITE;
12406dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    async_socket_read_abs(as, buffer, len, reader_cb, reader_opaque, dl);
1241a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1242a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
12436dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid
1244a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkineasync_socket_write_abs(AsyncSocket* as,
1245a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                       const void* buffer, uint32_t len,
12466dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                       on_as_io_cb writer_cb,
1247a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                       void* writer_opaque,
1248a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                       Duration deadline)
1249a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
1250c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASocket %s: Handling write for %d bytes with deadline %lld...",
1251c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _async_socket_string(as), len, deadline);
1252c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1253a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    AsyncSocketIO* const asw =
1254a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine        _async_socket_writer_new(as, buffer, len, writer_cb, writer_opaque,
1255a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                                 deadline);
12567136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    if (async_socket_is_connected(as)) {
12577136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        /* Add new writer to the list. Note that we use initial reference from I/O
12587136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine         * 'new' routine as "in the list" reference counter. */
12597136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        if (as->writers_head == NULL) {
12607136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            as->writers_head = as->writers_tail = asw;
12617136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        } else {
12627136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            as->writers_tail->next = asw;
12637136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine            as->writers_tail = asw;
12647136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        }
12657136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        loopIo_wantWrite(as->io);
1266a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    } else {
12677136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        D("ASocket %s: Write on a disconnected socket.", _async_socket_string(as));
12687136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        errno = ECONNRESET;
12697136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        writer_cb(writer_opaque, asw, ASIO_STATE_FAILED);
12707136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine        async_socket_io_release(asw);
1271a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    }
1272a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1273a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine
12746dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid
12756dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_write_rel(AsyncSocket* as,
12766dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                       const void* buffer, uint32_t len,
12776dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                       on_as_io_cb writer_cb,
12786dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                       void* writer_opaque,
12796dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                       int to)
1280a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine{
1281a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine    const Duration dl = (to >= 0) ? looper_now(_async_socket_get_looper(as)) + to :
1282a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine                                    DURATION_INFINITE;
12836dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    async_socket_write_abs(as, buffer, len, writer_cb, writer_opaque, dl);
12846dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
12856dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
12866dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid*
12876dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_get_client_opaque(const AsyncSocket* as)
12886dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
12896dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return as->client_opaque;
12906dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine}
12916dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
12926dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir ChtchetkineDuration
12936dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkineasync_socket_deadline(AsyncSocket* as, int rel)
12946dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine{
12956dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    return (rel >= 0) ? looper_now(_async_socket_get_looper(as)) + rel :
12966dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                        DURATION_INFINITE;
1297a7383ef4eb8d3863c8d582ea0d6b2ddb42125cbaVladimir Chtchetkine}
1298ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
1299ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint
1300ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_get_port(const AsyncSocket* as)
1301ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{
1302ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    return sock_address_get_port(&as->address);
1303ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine}
13047136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine
13057136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineint
13067136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkineasync_socket_is_connected(const AsyncSocket* as)
13077136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine{
13087136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine    return as->fd >= 0;
13097136b053b7fc7840ec64e01d1d19ab822e1f949aVladimir Chtchetkine}
1310