19d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/*
29d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Copyright (C) 2011 The Android Open Source Project
39d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *
49d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Licensed under the Apache License, Version 2.0 (the "License");
59d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * you may not use this file except in compliance with the License.
69d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * You may obtain a copy of the License at
79d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *
89d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *      http://www.apache.org/licenses/LICENSE-2.0
99d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *
109d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Unless required by applicable law or agreed to in writing, software
119d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * distributed under the License is distributed on an "AS IS" BASIS,
129d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * See the License for the specific language governing permissions and
149d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * limitations under the License.
159d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine */
169d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
179d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/*
189d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Encapsulates exchange protocol between the emulator, and an Android device
199d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * that is connected to the host via USB. The communication is established over
209d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * a TCP port forwarding, enabled by ADB.
219d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine */
229d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
239d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine#include "android/utils/debug.h"
249d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine#include "android/async-socket-connector.h"
259d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine#include "utils/panic.h"
269d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine#include "iolooper.h"
279d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
289d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine#define  E(...)    derror(__VA_ARGS__)
299d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine#define  W(...)    dwarning(__VA_ARGS__)
309d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine#define  D(...)    VERBOSE_PRINT(asconnector,__VA_ARGS__)
319d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine#define  D_ACTIVE  VERBOSE_CHECK(asconnector)
329d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
33c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define TRACE_ON    0
34c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
35c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#if TRACE_ON
36c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  T(...)    VERBOSE_PRINT(asconnector,__VA_ARGS__)
37c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#else
38c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#define  T(...)
39c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine#endif
40c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
419d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/********************************************************************************
429d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *                             Internals
439d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *******************************************************************************/
449d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
459d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkinestruct AsyncSocketConnector {
469d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* TCP address for the connection. */
479d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    SockAddress     address;
489d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* I/O looper for asynchronous I/O. */
499d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    Looper*         looper;
509d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* I/O port for asynchronous connection. */
519d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    LoopIo          connector_io[1];
529d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* Timer that is used to retry asynchronous connections. */
539d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    LoopTimer       connector_timer[1];
549d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* Asynchronous connector to the socket. */
559d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    AsyncConnector  connector[1];
566dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    /* Callback to invoke on connection events. */
579d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    asc_event_cb    on_connected_cb;
589d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* An opaque parameter to pass to the connection callback. */
599d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    void*           on_connected_cb_opaque;
609d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* Retry timeout in milliseconds. */
619d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    int             retry_to;
629d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* Socket descriptor for the connection. */
639d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    int             fd;
64ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Number of outstanding references to the connector. */
65ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    int             ref_count;
66c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    /* Flags whether (1) or not (0) connector owns the looper. */
67c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    int             owns_looper;
689d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine};
699d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
709d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/* Asynchronous I/O looper callback invoked by the connector.
719d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Param:
729d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *  opaque - AsyncSocketConnector instance.
739d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *  fd, events - Standard I/O callback parameters.
749d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine */
759d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkinestatic void _on_async_socket_connector_io(void* opaque, int fd, unsigned events);
769d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
779d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/* Gets socket's address string. */
789d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir ChtchetkineAINLINED const char*
799d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine_asc_socket_string(AsyncSocketConnector* connector)
809d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine{
819d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    return sock_address_to_string(&connector->address);
829d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine}
839d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
849d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/* Destroys AsyncSocketConnector instance.
859d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Param:
869d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *  connector - Initialized AsyncSocketConnector instance.
879d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine */
889d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkinestatic void
899d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine_async_socket_connector_free(AsyncSocketConnector* connector)
909d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine{
919d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    if (connector != NULL) {
92c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        T("ASC %s: Connector is destroying...", _asc_socket_string(connector));
93c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
94c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Stop all activities. */
95ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        if (asyncConnector_stop(connector->connector) == 0) {
96ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            /* Connection was in progress. We need to destroy I/O descriptor for
97ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine             * that connection. */
98c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            D("ASC %s: Stopped async connection in progress.",
99ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine              _asc_socket_string(connector));
100ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            loopIo_done(connector->connector_io);
101ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        }
1029d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
103c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        /* Free allocated resources. */
1049d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        if (connector->looper != NULL) {
1059d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine            loopTimer_done(connector->connector_timer);
106c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            if (connector->owns_looper) {
107c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                looper_free(connector->looper);
108c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            }
1099d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        }
1109d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
111c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (connector->fd >= 0) {
112c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            socket_close(connector->fd);
113c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
114c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
115c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        T("ASC %s: Connector is destroyed", _asc_socket_string(connector));
116c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1179d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        sock_address_done(&connector->address);
1189d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
1199d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        AFREE(connector);
1209d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
1219d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine}
1229d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
1239d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/* Opens connection socket.
1249d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Param:
1259d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *  connector - Initialized AsyncSocketConnector instance.
1269d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Return:
1279d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *  0 on success, or -1 on failure.
1289d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine */
1299d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkinestatic int
1309d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine_async_socket_connector_open_socket(AsyncSocketConnector* connector)
1319d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine{
1329d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* Open socket. */
1339d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    connector->fd = socket_create_inet(SOCKET_STREAM);
1349d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    if (connector->fd < 0) {
135c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("ASC %s: Unable to create socket: %d -> %s",
1366dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine          _asc_socket_string(connector), errno, strerror(errno));
1379d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        return -1;
1389d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
1399d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
1409d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* Prepare for async I/O on the connector. */
1419d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    socket_set_nonblock(connector->fd);
1429d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
143c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASC %s: Connector socket is opened with FD = %d",
144c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _asc_socket_string(connector), connector->fd);
145c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
1469d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    return 0;
1479d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine}
1489d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
1499d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/* Closes connection socket.
1509d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Param:
1519d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *  connector - Initialized AsyncSocketConnector instance.
1529d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Return:
1539d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *  0 on success, or -1 on failure.
1549d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine */
1559d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkinestatic void
1569d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine_async_socket_connector_close_socket(AsyncSocketConnector* connector)
1579d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine{
1589d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    if (connector->fd >= 0) {
1599d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        socket_close(connector->fd);
160c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        T("ASC %s: Connector socket FD = %d is closed.",
161c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          _asc_socket_string(connector), connector->fd);
1629d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        connector->fd = -1;
1639d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
1649d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine}
1659d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
1669d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/* Asynchronous connector (AsyncConnector instance) has completed connection
1679d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *  attempt.
1689d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Param:
169ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine *  connector - Initialized AsyncSocketConnector instance. Note: When this
170ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine *      callback is called, the caller has referenced passed connector object,
171ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine *      So, it's guaranteed that this connector is not going to be destroyed
172ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine *      while this routine executes.
1739d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *  status - Status of the connection attempt.
1749d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine */
1759d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkinestatic void
1769d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine_on_async_socket_connector_connecting(AsyncSocketConnector* connector,
1779d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine                                      AsyncStatus status)
1789d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine{
1796dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    AsyncIOAction action = ASIO_ACTION_DONE;
1809d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
1819d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    switch (status) {
1829d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        case ASYNC_COMPLETE:
1839d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine            loopIo_done(connector->connector_io);
1846dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            D("Socket '%s' is connected", _asc_socket_string(connector));
1859d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine            /* Invoke "on connected" callback */
1869d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine            action = connector->on_connected_cb(connector->on_connected_cb_opaque,
1876dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                                connector, ASIO_STATE_SUCCEEDED);
1889d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine            break;
1899d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
1909d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        case ASYNC_ERROR:
1919d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine            loopIo_done(connector->connector_io);
1926dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            D("Error while connecting to socket '%s': %d -> %s",
1936dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine              _asc_socket_string(connector), errno, strerror(errno));
1949d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine            /* Invoke "on connected" callback */
1959d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine            action = connector->on_connected_cb(connector->on_connected_cb_opaque,
1966dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                                connector, ASIO_STATE_FAILED);
1979d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine            break;
1989d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
1999d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        case ASYNC_NEED_MORE:
200c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            T("ASC %s: Waiting on connection to complete. Connector FD = %d",
201c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              _asc_socket_string(connector), connector->fd);
2029d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine            return;
2039d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
2049d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
2056dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (action == ASIO_ACTION_RETRY) {
206c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("ASC %s: Retrying connection. Connector FD = %d",
207c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          _asc_socket_string(connector), connector->fd);
2089d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        loopTimer_startRelative(connector->connector_timer, connector->retry_to);
209ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    } else if (action == ASIO_ACTION_ABORT) {
210c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("ASC %s: Client has aborted connection. Connector FD = %d",
211c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          _asc_socket_string(connector), connector->fd);
2129d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
2139d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine}
2149d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
2159d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkinestatic void
2169d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine_on_async_socket_connector_io(void* opaque, int fd, unsigned events)
2179d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine{
2189d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
2199d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
220ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Reference the connector while we're handing I/O. */
221ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_connector_reference(connector);
222ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
2236dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    /* Notify the client that another connection attempt is about to start. */
2246dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    const AsyncIOAction action =
2256dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        connector->on_connected_cb(connector->on_connected_cb_opaque,
2266dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                   connector, ASIO_STATE_CONTINUES);
2276dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    if (action != ASIO_ACTION_ABORT) {
2286dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        /* Complete socket connection. */
2296dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        const AsyncStatus status = asyncConnector_run(connector->connector);
2306dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        _on_async_socket_connector_connecting(connector, status);
2316dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    } else {
232c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("ASC %s: Client has aborted connection. Connector FD = %d",
233c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          _asc_socket_string(connector), connector->fd);
2346dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    }
235ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
236ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Release the connector after we're done with handing I/O. */
237ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_connector_release(connector);
2389d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine}
2399d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
2409d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/* Retry connection timer callback.
2419d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine * Param:
2429d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *  opaque - AsyncSocketConnector instance.
2439d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine */
2449d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkinestatic void
2459d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine_on_async_socket_connector_retry(void* opaque)
2469d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine{
2476dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    AsyncStatus status;
2489d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
2499d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
250c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASC %s: Reconnect timer expired. Connector FD = %d",
251c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              _asc_socket_string(connector), connector->fd);
252c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
253ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Reference the connector while we're in callback. */
254ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_connector_reference(connector);
255ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
2569d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* Invoke the callback to notify about a connection retry attempt. */
2576dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine    AsyncIOAction action =
2589d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        connector->on_connected_cb(connector->on_connected_cb_opaque,
2596dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                   connector, ASIO_STATE_RETRYING);
2609d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
261ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    if (action != ASIO_ACTION_ABORT) {
262ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        /* Close handle opened for the previous (failed) attempt. */
263ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        _async_socket_connector_close_socket(connector);
2649d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
265ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        /* Retry connection attempt. */
266ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        if (_async_socket_connector_open_socket(connector) == 0) {
267ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            loopIo_init(connector->connector_io, connector->looper,
268ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine                        connector->fd, _on_async_socket_connector_io, connector);
269ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            status = asyncConnector_init(connector->connector,
270ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine                                         &connector->address,
271ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine                                         connector->connector_io);
272ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        } else {
273ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            status = ASYNC_ERROR;
274ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        }
2759d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
276ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        _on_async_socket_connector_connecting(connector, status);
2779d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    } else {
278c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        D("ASC %s: Client has aborted connection. Connector FD = %d",
279c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine          _asc_socket_string(connector), connector->fd);
2809d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
2816dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine
282ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Release the connector after we're done with the callback. */
283ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    async_socket_connector_release(connector);
2849d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine}
2859d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
2869d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine/********************************************************************************
2879d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *                       Async connector implementation
2889d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine *******************************************************************************/
2899d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
2909d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir ChtchetkineAsyncSocketConnector*
2919d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkineasync_socket_connector_new(const SockAddress* address,
2929d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine                           int retry_to,
2939d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine                           asc_event_cb cb,
294c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                           void* cb_opaque,
295c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine                           Looper* looper)
2969d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine{
2979d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    AsyncSocketConnector* connector;
2989d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
2999d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    if (cb == NULL) {
3006dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        W("No callback for AsyncSocketConnector for socket '%s'",
3019d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine          sock_address_to_string(address));
3029d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        errno = EINVAL;
3039d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        return NULL;
3049d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
3059d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
3069d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    ANEW0(connector);
3079d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
3089d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    connector->fd = -1;
3099d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    connector->retry_to = retry_to;
3109d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    connector->on_connected_cb = cb;
3119d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    connector->on_connected_cb_opaque = cb_opaque;
312ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    connector->ref_count = 1;
3139d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
3149d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* Copy socket address. */
3154732aee0622005bc612f75d0319e6e3a057301b4Vladimir Chtchetkine#ifdef _WIN32
3164732aee0622005bc612f75d0319e6e3a057301b4Vladimir Chtchetkine    connector->address = *address;
3174732aee0622005bc612f75d0319e6e3a057301b4Vladimir Chtchetkine#else
3189d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    if (sock_address_get_family(address) == SOCKET_UNIX) {
3199d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        sock_address_init_unix(&connector->address, sock_address_get_path(address));
3209d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    } else {
3219d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        connector->address = *address;
3229d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
3234732aee0622005bc612f75d0319e6e3a057301b4Vladimir Chtchetkine#endif
3249d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
3259d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    /* Create a looper for asynchronous I/O. */
326c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    if (looper == NULL) {
327c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        connector->looper = looper_newCore();
328c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        if (connector->looper == NULL) {
329c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            E("Unable to create I/O looper for AsyncSocketConnector for socket '%s'",
330c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              _asc_socket_string(connector));
331c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            cb(cb_opaque, connector, ASIO_STATE_FAILED);
332c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            _async_socket_connector_free(connector);
333c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            return NULL;
334c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        }
335c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        connector->owns_looper = 1;
336c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    } else {
337c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        connector->looper = looper;
338c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine        connector->owns_looper = 0;
3399d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
3409d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
341ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    /* Create a timer that will be used for connection retries. */
342ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    loopTimer_init(connector->connector_timer, connector->looper,
343ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine                   _on_async_socket_connector_retry, connector);
344ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
345c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASC %s: New connector object", _asc_socket_string(connector));
346c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
3479d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    return connector;
3489d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine}
3499d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
350ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint
351ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_connector_reference(AsyncSocketConnector* connector)
352ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{
353ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    assert(connector->ref_count > 0);
354ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    connector->ref_count++;
355ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    return connector->ref_count;
356ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine}
357ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
358ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineint
359ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkineasync_socket_connector_release(AsyncSocketConnector* connector)
360ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine{
361ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    assert(connector->ref_count > 0);
362ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    connector->ref_count--;
363ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    if (connector->ref_count == 0) {
364ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        /* Last reference has been dropped. Destroy this object. */
365ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        _async_socket_connector_free(connector);
366ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine        return 0;
367ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    }
368ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine    return connector->ref_count;
369ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine}
370ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine
3716dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkinevoid
3729d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkineasync_socket_connector_connect(AsyncSocketConnector* connector)
3739d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine{
3749d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    AsyncStatus status;
3759d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
376c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASC %s: Handling connect request. Connector FD = %d",
377c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine      _asc_socket_string(connector), connector->fd);
378c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
3799d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    if (_async_socket_connector_open_socket(connector) == 0) {
3806dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        const AsyncIOAction action =
3816dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            connector->on_connected_cb(connector->on_connected_cb_opaque,
3826dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                       connector, ASIO_STATE_STARTED);
3836dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        if (action == ASIO_ACTION_ABORT) {
384c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine            D("ASC %s: Client has aborted connection. Connector FD = %d",
385c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine              _asc_socket_string(connector), connector->fd);
3866dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            return;
3876dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        } else {
388ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine            loopIo_init(connector->connector_io, connector->looper,
389ef4ccd385650612a830a098f4b1eac48482b65b3Vladimir Chtchetkine                        connector->fd, _on_async_socket_connector_io, connector);
3906dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine            status = asyncConnector_init(connector->connector,
3916dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                         &connector->address,
3926dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine                                         connector->connector_io);
3936dc5c2cef91004488f04fc6e9c0946f6d3a29705Vladimir Chtchetkine        }
3949d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    } else {
3959d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        status = ASYNC_ERROR;
3969d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
3979d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
3989d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    _on_async_socket_connector_connecting(connector, status);
3999d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine}
4009d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine
4019d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkineint
4029d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkineasync_socket_connector_pull_fd(AsyncSocketConnector* connector)
4039d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine{
4049d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    const int fd = connector->fd;
4059d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    if (fd >= 0) {
4069d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine        connector->fd = -1;
4079d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    }
408c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
409c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine    T("ASC %s: Client has pulled connector FD %d", _asc_socket_string(connector), fd);
410c8aa2c570d30098da59f1967d5158024ed28570dVladimir Chtchetkine
4119d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine    return fd;
4129d36fe7e6f0c5ece4de1b29ec78a15c37c158b1dVladimir Chtchetkine}
413