1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Encapsulates exchange protocol between the emulator, and an Android device
19 * that is connected to the host via USB. The communication is established over
20 * a TCP port forwarding, enabled by ADB.
21 */
22
23#include "android/utils/debug.h"
24#include "android/async-socket-connector.h"
25#include "utils/panic.h"
26#include "iolooper.h"
27
28#define  E(...)    derror(__VA_ARGS__)
29#define  W(...)    dwarning(__VA_ARGS__)
30#define  D(...)    VERBOSE_PRINT(asconnector,__VA_ARGS__)
31#define  D_ACTIVE  VERBOSE_CHECK(asconnector)
32
33#define TRACE_ON    0
34
35#if TRACE_ON
36#define  T(...)    VERBOSE_PRINT(asconnector,__VA_ARGS__)
37#else
38#define  T(...)
39#endif
40
41/********************************************************************************
42 *                             Internals
43 *******************************************************************************/
44
45struct AsyncSocketConnector {
46    /* TCP address for the connection. */
47    SockAddress     address;
48    /* I/O looper for asynchronous I/O. */
49    Looper*         looper;
50    /* I/O port for asynchronous connection. */
51    LoopIo          connector_io[1];
52    /* Timer that is used to retry asynchronous connections. */
53    LoopTimer       connector_timer[1];
54    /* Asynchronous connector to the socket. */
55    AsyncConnector  connector[1];
56    /* Callback to invoke on connection events. */
57    asc_event_cb    on_connected_cb;
58    /* An opaque parameter to pass to the connection callback. */
59    void*           on_connected_cb_opaque;
60    /* Retry timeout in milliseconds. */
61    int             retry_to;
62    /* Socket descriptor for the connection. */
63    int             fd;
64    /* Number of outstanding references to the connector. */
65    int             ref_count;
66    /* Flags whether (1) or not (0) connector owns the looper. */
67    int             owns_looper;
68};
69
70/* Asynchronous I/O looper callback invoked by the connector.
71 * Param:
72 *  opaque - AsyncSocketConnector instance.
73 *  fd, events - Standard I/O callback parameters.
74 */
75static void _on_async_socket_connector_io(void* opaque, int fd, unsigned events);
76
77/* Gets socket's address string. */
78AINLINED const char*
79_asc_socket_string(AsyncSocketConnector* connector)
80{
81    return sock_address_to_string(&connector->address);
82}
83
84/* Destroys AsyncSocketConnector instance.
85 * Param:
86 *  connector - Initialized AsyncSocketConnector instance.
87 */
88static void
89_async_socket_connector_free(AsyncSocketConnector* connector)
90{
91    if (connector != NULL) {
92        T("ASC %s: Connector is destroying...", _asc_socket_string(connector));
93
94        /* Stop all activities. */
95        if (asyncConnector_stop(connector->connector) == 0) {
96            /* Connection was in progress. We need to destroy I/O descriptor for
97             * that connection. */
98            D("ASC %s: Stopped async connection in progress.",
99              _asc_socket_string(connector));
100            loopIo_done(connector->connector_io);
101        }
102
103        /* Free allocated resources. */
104        if (connector->looper != NULL) {
105            loopTimer_done(connector->connector_timer);
106            if (connector->owns_looper) {
107                looper_free(connector->looper);
108            }
109        }
110
111        if (connector->fd >= 0) {
112            socket_close(connector->fd);
113        }
114
115        T("ASC %s: Connector is destroyed", _asc_socket_string(connector));
116
117        sock_address_done(&connector->address);
118
119        AFREE(connector);
120    }
121}
122
123/* Opens connection socket.
124 * Param:
125 *  connector - Initialized AsyncSocketConnector instance.
126 * Return:
127 *  0 on success, or -1 on failure.
128 */
129static int
130_async_socket_connector_open_socket(AsyncSocketConnector* connector)
131{
132    /* Open socket. */
133    connector->fd = socket_create_inet(SOCKET_STREAM);
134    if (connector->fd < 0) {
135        D("ASC %s: Unable to create socket: %d -> %s",
136          _asc_socket_string(connector), errno, strerror(errno));
137        return -1;
138    }
139
140    /* Prepare for async I/O on the connector. */
141    socket_set_nonblock(connector->fd);
142
143    T("ASC %s: Connector socket is opened with FD = %d",
144      _asc_socket_string(connector), connector->fd);
145
146    return 0;
147}
148
149/* Closes connection socket.
150 * Param:
151 *  connector - Initialized AsyncSocketConnector instance.
152 * Return:
153 *  0 on success, or -1 on failure.
154 */
155static void
156_async_socket_connector_close_socket(AsyncSocketConnector* connector)
157{
158    if (connector->fd >= 0) {
159        socket_close(connector->fd);
160        T("ASC %s: Connector socket FD = %d is closed.",
161          _asc_socket_string(connector), connector->fd);
162        connector->fd = -1;
163    }
164}
165
166/* Asynchronous connector (AsyncConnector instance) has completed connection
167 *  attempt.
168 * Param:
169 *  connector - Initialized AsyncSocketConnector instance. Note: When this
170 *      callback is called, the caller has referenced passed connector object,
171 *      So, it's guaranteed that this connector is not going to be destroyed
172 *      while this routine executes.
173 *  status - Status of the connection attempt.
174 */
175static void
176_on_async_socket_connector_connecting(AsyncSocketConnector* connector,
177                                      AsyncStatus status)
178{
179    AsyncIOAction action = ASIO_ACTION_DONE;
180
181    switch (status) {
182        case ASYNC_COMPLETE:
183            loopIo_done(connector->connector_io);
184            D("Socket '%s' is connected", _asc_socket_string(connector));
185            /* Invoke "on connected" callback */
186            action = connector->on_connected_cb(connector->on_connected_cb_opaque,
187                                                connector, ASIO_STATE_SUCCEEDED);
188            break;
189
190        case ASYNC_ERROR:
191            loopIo_done(connector->connector_io);
192            D("Error while connecting to socket '%s': %d -> %s",
193              _asc_socket_string(connector), errno, strerror(errno));
194            /* Invoke "on connected" callback */
195            action = connector->on_connected_cb(connector->on_connected_cb_opaque,
196                                                connector, ASIO_STATE_FAILED);
197            break;
198
199        case ASYNC_NEED_MORE:
200            T("ASC %s: Waiting on connection to complete. Connector FD = %d",
201              _asc_socket_string(connector), connector->fd);
202            return;
203    }
204
205    if (action == ASIO_ACTION_RETRY) {
206        D("ASC %s: Retrying connection. Connector FD = %d",
207          _asc_socket_string(connector), connector->fd);
208        loopTimer_startRelative(connector->connector_timer, connector->retry_to);
209    } else if (action == ASIO_ACTION_ABORT) {
210        D("ASC %s: Client has aborted connection. Connector FD = %d",
211          _asc_socket_string(connector), connector->fd);
212    }
213}
214
215static void
216_on_async_socket_connector_io(void* opaque, int fd, unsigned events)
217{
218    AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
219
220    /* Reference the connector while we're handing I/O. */
221    async_socket_connector_reference(connector);
222
223    /* Notify the client that another connection attempt is about to start. */
224    const AsyncIOAction action =
225        connector->on_connected_cb(connector->on_connected_cb_opaque,
226                                   connector, ASIO_STATE_CONTINUES);
227    if (action != ASIO_ACTION_ABORT) {
228        /* Complete socket connection. */
229        const AsyncStatus status = asyncConnector_run(connector->connector);
230        _on_async_socket_connector_connecting(connector, status);
231    } else {
232        D("ASC %s: Client has aborted connection. Connector FD = %d",
233          _asc_socket_string(connector), connector->fd);
234    }
235
236    /* Release the connector after we're done with handing I/O. */
237    async_socket_connector_release(connector);
238}
239
240/* Retry connection timer callback.
241 * Param:
242 *  opaque - AsyncSocketConnector instance.
243 */
244static void
245_on_async_socket_connector_retry(void* opaque)
246{
247    AsyncStatus status;
248    AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
249
250    T("ASC %s: Reconnect timer expired. Connector FD = %d",
251              _asc_socket_string(connector), connector->fd);
252
253    /* Reference the connector while we're in callback. */
254    async_socket_connector_reference(connector);
255
256    /* Invoke the callback to notify about a connection retry attempt. */
257    AsyncIOAction action =
258        connector->on_connected_cb(connector->on_connected_cb_opaque,
259                                   connector, ASIO_STATE_RETRYING);
260
261    if (action != ASIO_ACTION_ABORT) {
262        /* Close handle opened for the previous (failed) attempt. */
263        _async_socket_connector_close_socket(connector);
264
265        /* Retry connection attempt. */
266        if (_async_socket_connector_open_socket(connector) == 0) {
267            loopIo_init(connector->connector_io, connector->looper,
268                        connector->fd, _on_async_socket_connector_io, connector);
269            status = asyncConnector_init(connector->connector,
270                                         &connector->address,
271                                         connector->connector_io);
272        } else {
273            status = ASYNC_ERROR;
274        }
275
276        _on_async_socket_connector_connecting(connector, status);
277    } else {
278        D("ASC %s: Client has aborted connection. Connector FD = %d",
279          _asc_socket_string(connector), connector->fd);
280    }
281
282    /* Release the connector after we're done with the callback. */
283    async_socket_connector_release(connector);
284}
285
286/********************************************************************************
287 *                       Async connector implementation
288 *******************************************************************************/
289
290AsyncSocketConnector*
291async_socket_connector_new(const SockAddress* address,
292                           int retry_to,
293                           asc_event_cb cb,
294                           void* cb_opaque,
295                           Looper* looper)
296{
297    AsyncSocketConnector* connector;
298
299    if (cb == NULL) {
300        W("No callback for AsyncSocketConnector for socket '%s'",
301          sock_address_to_string(address));
302        errno = EINVAL;
303        return NULL;
304    }
305
306    ANEW0(connector);
307
308    connector->fd = -1;
309    connector->retry_to = retry_to;
310    connector->on_connected_cb = cb;
311    connector->on_connected_cb_opaque = cb_opaque;
312    connector->ref_count = 1;
313
314    /* Copy socket address. */
315#ifdef _WIN32
316    connector->address = *address;
317#else
318    if (sock_address_get_family(address) == SOCKET_UNIX) {
319        sock_address_init_unix(&connector->address, sock_address_get_path(address));
320    } else {
321        connector->address = *address;
322    }
323#endif
324
325    /* Create a looper for asynchronous I/O. */
326    if (looper == NULL) {
327        connector->looper = looper_newCore();
328        if (connector->looper == NULL) {
329            E("Unable to create I/O looper for AsyncSocketConnector for socket '%s'",
330              _asc_socket_string(connector));
331            cb(cb_opaque, connector, ASIO_STATE_FAILED);
332            _async_socket_connector_free(connector);
333            return NULL;
334        }
335        connector->owns_looper = 1;
336    } else {
337        connector->looper = looper;
338        connector->owns_looper = 0;
339    }
340
341    /* Create a timer that will be used for connection retries. */
342    loopTimer_init(connector->connector_timer, connector->looper,
343                   _on_async_socket_connector_retry, connector);
344
345    T("ASC %s: New connector object", _asc_socket_string(connector));
346
347    return connector;
348}
349
350int
351async_socket_connector_reference(AsyncSocketConnector* connector)
352{
353    assert(connector->ref_count > 0);
354    connector->ref_count++;
355    return connector->ref_count;
356}
357
358int
359async_socket_connector_release(AsyncSocketConnector* connector)
360{
361    assert(connector->ref_count > 0);
362    connector->ref_count--;
363    if (connector->ref_count == 0) {
364        /* Last reference has been dropped. Destroy this object. */
365        _async_socket_connector_free(connector);
366        return 0;
367    }
368    return connector->ref_count;
369}
370
371void
372async_socket_connector_connect(AsyncSocketConnector* connector)
373{
374    AsyncStatus status;
375
376    T("ASC %s: Handling connect request. Connector FD = %d",
377      _asc_socket_string(connector), connector->fd);
378
379    if (_async_socket_connector_open_socket(connector) == 0) {
380        const AsyncIOAction action =
381            connector->on_connected_cb(connector->on_connected_cb_opaque,
382                                       connector, ASIO_STATE_STARTED);
383        if (action == ASIO_ACTION_ABORT) {
384            D("ASC %s: Client has aborted connection. Connector FD = %d",
385              _asc_socket_string(connector), connector->fd);
386            return;
387        } else {
388            loopIo_init(connector->connector_io, connector->looper,
389                        connector->fd, _on_async_socket_connector_io, connector);
390            status = asyncConnector_init(connector->connector,
391                                         &connector->address,
392                                         connector->connector_io);
393        }
394    } else {
395        status = ASYNC_ERROR;
396    }
397
398    _on_async_socket_connector_connecting(connector, status);
399}
400
401int
402async_socket_connector_pull_fd(AsyncSocketConnector* connector)
403{
404    const int fd = connector->fd;
405    if (fd >= 0) {
406        connector->fd = -1;
407    }
408
409    T("ASC %s: Client has pulled connector FD %d", _asc_socket_string(connector), fd);
410
411    return fd;
412}
413