blob: 71740e48ad1deedc01d2a958d2860d2053cccd63 [file] [log] [blame]
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -07001/*
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
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070023#include "android/utils/debug.h"
24#include "android/async-socket-connector.h"
25#include "utils/panic.h"
David 'Digit' Turnerd413fa52013-12-14 23:35:20 +010026#include "android/iolooper.h"
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070027
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
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070033#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
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070041/********************************************************************************
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];
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -070056 /* Callback to invoke on connection events. */
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070057 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;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -070064 /* Number of outstanding references to the connector. */
65 int ref_count;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070066 /* Flags whether (1) or not (0) connector owns the looper. */
67 int owns_looper;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070068};
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) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070092 T("ASC %s: Connector is destroying...", _asc_socket_string(connector));
93
94 /* Stop all activities. */
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -070095 if (asyncConnector_stop(connector->connector) == 0) {
96 /* Connection was in progress. We need to destroy I/O descriptor for
97 * that connection. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070098 D("ASC %s: Stopped async connection in progress.",
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -070099 _asc_socket_string(connector));
100 loopIo_done(connector->connector_io);
101 }
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700102
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
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700111 if (connector->fd >= 0) {
112 socket_close(connector->fd);
113 }
114
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700115 T("ASC %s: Connector is destroyed", _asc_socket_string(connector));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700116
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) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700135 D("ASC %s: Unable to create socket: %d -> %s",
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700136 _asc_socket_string(connector), errno, strerror(errno));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700137 return -1;
138 }
139
140 /* Prepare for async I/O on the connector. */
141 socket_set_nonblock(connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700142
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700143 T("ASC %s: Connector socket is opened with FD = %d",
144 _asc_socket_string(connector), connector->fd);
145
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700146 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);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700160 T("ASC %s: Connector socket FD = %d is closed.",
161 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700162 connector->fd = -1;
163 }
164}
165
166/* Asynchronous connector (AsyncConnector instance) has completed connection
167 * attempt.
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700168 * Param:
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700169 * 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.
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700173 * status - Status of the connection attempt.
174 */
175static void
176_on_async_socket_connector_connecting(AsyncSocketConnector* connector,
177 AsyncStatus status)
178{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700179 AsyncIOAction action = ASIO_ACTION_DONE;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700180
181 switch (status) {
182 case ASYNC_COMPLETE:
183 loopIo_done(connector->connector_io);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700184 D("Socket '%s' is connected", _asc_socket_string(connector));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700185 /* Invoke "on connected" callback */
186 action = connector->on_connected_cb(connector->on_connected_cb_opaque,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700187 connector, ASIO_STATE_SUCCEEDED);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700188 break;
189
190 case ASYNC_ERROR:
191 loopIo_done(connector->connector_io);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700192 D("Error while connecting to socket '%s': %d -> %s",
193 _asc_socket_string(connector), errno, strerror(errno));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700194 /* Invoke "on connected" callback */
195 action = connector->on_connected_cb(connector->on_connected_cb_opaque,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700196 connector, ASIO_STATE_FAILED);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700197 break;
198
199 case ASYNC_NEED_MORE:
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700200 T("ASC %s: Waiting on connection to complete. Connector FD = %d",
201 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700202 return;
203 }
204
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700205 if (action == ASIO_ACTION_RETRY) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700206 D("ASC %s: Retrying connection. Connector FD = %d",
207 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700208 loopTimer_startRelative(connector->connector_timer, connector->retry_to);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700209 } else if (action == ASIO_ACTION_ABORT) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700210 D("ASC %s: Client has aborted connection. Connector FD = %d",
211 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700212 }
213}
214
215static void
216_on_async_socket_connector_io(void* opaque, int fd, unsigned events)
217{
218 AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
219
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700220 /* Reference the connector while we're handing I/O. */
221 async_socket_connector_reference(connector);
222
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700223 /* 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 {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700232 D("ASC %s: Client has aborted connection. Connector FD = %d",
233 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700234 }
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700235
236 /* Release the connector after we're done with handing I/O. */
237 async_socket_connector_release(connector);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700238}
239
240/* Retry connection timer callback.
241 * Param:
242 * opaque - AsyncSocketConnector instance.
243 */
244static void
245_on_async_socket_connector_retry(void* opaque)
246{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700247 AsyncStatus status;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700248 AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
249
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700250 T("ASC %s: Reconnect timer expired. Connector FD = %d",
251 _asc_socket_string(connector), connector->fd);
252
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700253 /* Reference the connector while we're in callback. */
254 async_socket_connector_reference(connector);
255
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700256 /* Invoke the callback to notify about a connection retry attempt. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700257 AsyncIOAction action =
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700258 connector->on_connected_cb(connector->on_connected_cb_opaque,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700259 connector, ASIO_STATE_RETRYING);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700260
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700261 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 {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700278 D("ASC %s: Client has aborted connection. Connector FD = %d",
279 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700280 }
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700281
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700282 /* Release the connector after we're done with the callback. */
283 async_socket_connector_release(connector);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700284}
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,
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700294 void* cb_opaque,
295 Looper* looper)
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700296{
297 AsyncSocketConnector* connector;
298
299 if (cb == NULL) {
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700300 W("No callback for AsyncSocketConnector for socket '%s'",
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700301 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;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700312 connector->ref_count = 1;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700313
314 /* Copy socket address. */
Vladimir Chtchetkine4732aee2012-04-30 12:38:06 -0700315#ifdef _WIN32
316 connector->address = *address;
317#else
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700318 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 }
Vladimir Chtchetkine4732aee2012-04-30 12:38:06 -0700323#endif
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700324
325 /* Create a looper for asynchronous I/O. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700326 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;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700339 }
340
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700341 /* 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
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700345 T("ASC %s: New connector object", _asc_socket_string(connector));
346
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700347 return connector;
348}
349
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700350int
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
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700371void
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700372async_socket_connector_connect(AsyncSocketConnector* connector)
373{
374 AsyncStatus status;
375
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700376 T("ASC %s: Handling connect request. Connector FD = %d",
377 _asc_socket_string(connector), connector->fd);
378
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700379 if (_async_socket_connector_open_socket(connector) == 0) {
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700380 const AsyncIOAction action =
381 connector->on_connected_cb(connector->on_connected_cb_opaque,
382 connector, ASIO_STATE_STARTED);
383 if (action == ASIO_ACTION_ABORT) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700384 D("ASC %s: Client has aborted connection. Connector FD = %d",
385 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700386 return;
387 } else {
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700388 loopIo_init(connector->connector_io, connector->looper,
389 connector->fd, _on_async_socket_connector_io, connector);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700390 status = asyncConnector_init(connector->connector,
391 &connector->address,
392 connector->connector_io);
393 }
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700394 } else {
395 status = ASYNC_ERROR;
396 }
397
398 _on_async_socket_connector_connecting(connector, status);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700399}
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 }
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700408
409 T("ASC %s: Client has pulled connector FD %d", _asc_socket_string(connector), fd);
410
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700411 return fd;
412}