blob: 836016ce30219cd2ebf97150cc7d7e85191dd222 [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
23#include "qemu-common.h"
24#include "android/async-utils.h"
25#include "android/utils/debug.h"
26#include "android/async-socket-connector.h"
27#include "utils/panic.h"
28#include "iolooper.h"
29
30#define E(...) derror(__VA_ARGS__)
31#define W(...) dwarning(__VA_ARGS__)
32#define D(...) VERBOSE_PRINT(asconnector,__VA_ARGS__)
33#define D_ACTIVE VERBOSE_CHECK(asconnector)
34
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070035#define TRACE_ON 0
36
37#if TRACE_ON
38#define T(...) VERBOSE_PRINT(asconnector,__VA_ARGS__)
39#else
40#define T(...)
41#endif
42
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070043/********************************************************************************
44 * Internals
45 *******************************************************************************/
46
47struct AsyncSocketConnector {
48 /* TCP address for the connection. */
49 SockAddress address;
50 /* I/O looper for asynchronous I/O. */
51 Looper* looper;
52 /* I/O port for asynchronous connection. */
53 LoopIo connector_io[1];
54 /* Timer that is used to retry asynchronous connections. */
55 LoopTimer connector_timer[1];
56 /* Asynchronous connector to the socket. */
57 AsyncConnector connector[1];
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -070058 /* Callback to invoke on connection events. */
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070059 asc_event_cb on_connected_cb;
60 /* An opaque parameter to pass to the connection callback. */
61 void* on_connected_cb_opaque;
62 /* Retry timeout in milliseconds. */
63 int retry_to;
64 /* Socket descriptor for the connection. */
65 int fd;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -070066 /* Number of outstanding references to the connector. */
67 int ref_count;
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070068 /* Flags whether (1) or not (0) connector owns the looper. */
69 int owns_looper;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070070};
71
72/* Asynchronous I/O looper callback invoked by the connector.
73 * Param:
74 * opaque - AsyncSocketConnector instance.
75 * fd, events - Standard I/O callback parameters.
76 */
77static void _on_async_socket_connector_io(void* opaque, int fd, unsigned events);
78
79/* Gets socket's address string. */
80AINLINED const char*
81_asc_socket_string(AsyncSocketConnector* connector)
82{
83 return sock_address_to_string(&connector->address);
84}
85
86/* Destroys AsyncSocketConnector instance.
87 * Param:
88 * connector - Initialized AsyncSocketConnector instance.
89 */
90static void
91_async_socket_connector_free(AsyncSocketConnector* connector)
92{
93 if (connector != NULL) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -070094 T("ASC %s: Connector is destroying...", _asc_socket_string(connector));
95
96 /* Stop all activities. */
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -070097 if (asyncConnector_stop(connector->connector) == 0) {
98 /* Connection was in progress. We need to destroy I/O descriptor for
99 * that connection. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700100 D("ASC %s: Stopped async connection in progress.",
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700101 _asc_socket_string(connector));
102 loopIo_done(connector->connector_io);
103 }
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700104
105 /* Free allocated resources. */
106 if (connector->looper != NULL) {
107 loopTimer_done(connector->connector_timer);
108 if (connector->owns_looper) {
109 looper_free(connector->looper);
110 }
111 }
112
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700113 if (connector->fd >= 0) {
114 socket_close(connector->fd);
115 }
116
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700117 T("ASC %s: Connector is destroyed", _asc_socket_string(connector));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700118
119 sock_address_done(&connector->address);
120
121 AFREE(connector);
122 }
123}
124
125/* Opens connection socket.
126 * Param:
127 * connector - Initialized AsyncSocketConnector instance.
128 * Return:
129 * 0 on success, or -1 on failure.
130 */
131static int
132_async_socket_connector_open_socket(AsyncSocketConnector* connector)
133{
134 /* Open socket. */
135 connector->fd = socket_create_inet(SOCKET_STREAM);
136 if (connector->fd < 0) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700137 D("ASC %s: Unable to create socket: %d -> %s",
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700138 _asc_socket_string(connector), errno, strerror(errno));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700139 return -1;
140 }
141
142 /* Prepare for async I/O on the connector. */
143 socket_set_nonblock(connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700144
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700145 T("ASC %s: Connector socket is opened with FD = %d",
146 _asc_socket_string(connector), connector->fd);
147
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700148 return 0;
149}
150
151/* Closes connection socket.
152 * Param:
153 * connector - Initialized AsyncSocketConnector instance.
154 * Return:
155 * 0 on success, or -1 on failure.
156 */
157static void
158_async_socket_connector_close_socket(AsyncSocketConnector* connector)
159{
160 if (connector->fd >= 0) {
161 socket_close(connector->fd);
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700162 T("ASC %s: Connector socket FD = %d is closed.",
163 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700164 connector->fd = -1;
165 }
166}
167
168/* Asynchronous connector (AsyncConnector instance) has completed connection
169 * attempt.
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700170 * Param:
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700171 * connector - Initialized AsyncSocketConnector instance. Note: When this
172 * callback is called, the caller has referenced passed connector object,
173 * So, it's guaranteed that this connector is not going to be destroyed
174 * while this routine executes.
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700175 * status - Status of the connection attempt.
176 */
177static void
178_on_async_socket_connector_connecting(AsyncSocketConnector* connector,
179 AsyncStatus status)
180{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700181 AsyncIOAction action = ASIO_ACTION_DONE;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700182
183 switch (status) {
184 case ASYNC_COMPLETE:
185 loopIo_done(connector->connector_io);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700186 D("Socket '%s' is connected", _asc_socket_string(connector));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700187 /* Invoke "on connected" callback */
188 action = connector->on_connected_cb(connector->on_connected_cb_opaque,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700189 connector, ASIO_STATE_SUCCEEDED);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700190 break;
191
192 case ASYNC_ERROR:
193 loopIo_done(connector->connector_io);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700194 D("Error while connecting to socket '%s': %d -> %s",
195 _asc_socket_string(connector), errno, strerror(errno));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700196 /* Invoke "on connected" callback */
197 action = connector->on_connected_cb(connector->on_connected_cb_opaque,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700198 connector, ASIO_STATE_FAILED);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700199 break;
200
201 case ASYNC_NEED_MORE:
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700202 T("ASC %s: Waiting on connection to complete. Connector FD = %d",
203 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700204 return;
205 }
206
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700207 if (action == ASIO_ACTION_RETRY) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700208 D("ASC %s: Retrying connection. Connector FD = %d",
209 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700210 loopTimer_startRelative(connector->connector_timer, connector->retry_to);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700211 } else if (action == ASIO_ACTION_ABORT) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700212 D("ASC %s: Client has aborted connection. Connector FD = %d",
213 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700214 }
215}
216
217static void
218_on_async_socket_connector_io(void* opaque, int fd, unsigned events)
219{
220 AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
221
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700222 /* Reference the connector while we're handing I/O. */
223 async_socket_connector_reference(connector);
224
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700225 /* Notify the client that another connection attempt is about to start. */
226 const AsyncIOAction action =
227 connector->on_connected_cb(connector->on_connected_cb_opaque,
228 connector, ASIO_STATE_CONTINUES);
229 if (action != ASIO_ACTION_ABORT) {
230 /* Complete socket connection. */
231 const AsyncStatus status = asyncConnector_run(connector->connector);
232 _on_async_socket_connector_connecting(connector, status);
233 } else {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700234 D("ASC %s: Client has aborted connection. Connector FD = %d",
235 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700236 }
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700237
238 /* Release the connector after we're done with handing I/O. */
239 async_socket_connector_release(connector);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700240}
241
242/* Retry connection timer callback.
243 * Param:
244 * opaque - AsyncSocketConnector instance.
245 */
246static void
247_on_async_socket_connector_retry(void* opaque)
248{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700249 AsyncStatus status;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700250 AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
251
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700252 T("ASC %s: Reconnect timer expired. Connector FD = %d",
253 _asc_socket_string(connector), connector->fd);
254
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700255 /* Reference the connector while we're in callback. */
256 async_socket_connector_reference(connector);
257
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700258 /* Invoke the callback to notify about a connection retry attempt. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700259 AsyncIOAction action =
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700260 connector->on_connected_cb(connector->on_connected_cb_opaque,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700261 connector, ASIO_STATE_RETRYING);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700262
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700263 if (action != ASIO_ACTION_ABORT) {
264 /* Close handle opened for the previous (failed) attempt. */
265 _async_socket_connector_close_socket(connector);
266
267 /* Retry connection attempt. */
268 if (_async_socket_connector_open_socket(connector) == 0) {
269 loopIo_init(connector->connector_io, connector->looper,
270 connector->fd, _on_async_socket_connector_io, connector);
271 status = asyncConnector_init(connector->connector,
272 &connector->address,
273 connector->connector_io);
274 } else {
275 status = ASYNC_ERROR;
276 }
277
278 _on_async_socket_connector_connecting(connector, status);
279 } else {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700280 D("ASC %s: Client has aborted connection. Connector FD = %d",
281 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700282 }
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700283
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700284 /* Release the connector after we're done with the callback. */
285 async_socket_connector_release(connector);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700286}
287
288/********************************************************************************
289 * Async connector implementation
290 *******************************************************************************/
291
292AsyncSocketConnector*
293async_socket_connector_new(const SockAddress* address,
294 int retry_to,
295 asc_event_cb cb,
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700296 void* cb_opaque,
297 Looper* looper)
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700298{
299 AsyncSocketConnector* connector;
300
301 if (cb == NULL) {
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700302 W("No callback for AsyncSocketConnector for socket '%s'",
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700303 sock_address_to_string(address));
304 errno = EINVAL;
305 return NULL;
306 }
307
308 ANEW0(connector);
309
310 connector->fd = -1;
311 connector->retry_to = retry_to;
312 connector->on_connected_cb = cb;
313 connector->on_connected_cb_opaque = cb_opaque;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700314 connector->ref_count = 1;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700315
316 /* Copy socket address. */
317 if (sock_address_get_family(address) == SOCKET_UNIX) {
318 sock_address_init_unix(&connector->address, sock_address_get_path(address));
319 } else {
320 connector->address = *address;
321 }
322
323 /* Create a looper for asynchronous I/O. */
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700324 if (looper == NULL) {
325 connector->looper = looper_newCore();
326 if (connector->looper == NULL) {
327 E("Unable to create I/O looper for AsyncSocketConnector for socket '%s'",
328 _asc_socket_string(connector));
329 cb(cb_opaque, connector, ASIO_STATE_FAILED);
330 _async_socket_connector_free(connector);
331 return NULL;
332 }
333 connector->owns_looper = 1;
334 } else {
335 connector->looper = looper;
336 connector->owns_looper = 0;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700337 }
338
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700339 /* Create a timer that will be used for connection retries. */
340 loopTimer_init(connector->connector_timer, connector->looper,
341 _on_async_socket_connector_retry, connector);
342
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700343 T("ASC %s: New connector object", _asc_socket_string(connector));
344
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700345 return connector;
346}
347
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700348int
349async_socket_connector_reference(AsyncSocketConnector* connector)
350{
351 assert(connector->ref_count > 0);
352 connector->ref_count++;
353 return connector->ref_count;
354}
355
356int
357async_socket_connector_release(AsyncSocketConnector* connector)
358{
359 assert(connector->ref_count > 0);
360 connector->ref_count--;
361 if (connector->ref_count == 0) {
362 /* Last reference has been dropped. Destroy this object. */
363 _async_socket_connector_free(connector);
364 return 0;
365 }
366 return connector->ref_count;
367}
368
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700369void
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700370async_socket_connector_connect(AsyncSocketConnector* connector)
371{
372 AsyncStatus status;
373
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700374 T("ASC %s: Handling connect request. Connector FD = %d",
375 _asc_socket_string(connector), connector->fd);
376
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700377 if (_async_socket_connector_open_socket(connector) == 0) {
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700378 const AsyncIOAction action =
379 connector->on_connected_cb(connector->on_connected_cb_opaque,
380 connector, ASIO_STATE_STARTED);
381 if (action == ASIO_ACTION_ABORT) {
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700382 D("ASC %s: Client has aborted connection. Connector FD = %d",
383 _asc_socket_string(connector), connector->fd);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700384 return;
385 } else {
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700386 loopIo_init(connector->connector_io, connector->looper,
387 connector->fd, _on_async_socket_connector_io, connector);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700388 status = asyncConnector_init(connector->connector,
389 &connector->address,
390 connector->connector_io);
391 }
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700392 } else {
393 status = ASYNC_ERROR;
394 }
395
396 _on_async_socket_connector_connecting(connector, status);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700397}
398
399int
400async_socket_connector_pull_fd(AsyncSocketConnector* connector)
401{
402 const int fd = connector->fd;
403 if (fd >= 0) {
404 connector->fd = -1;
405 }
Vladimir Chtchetkinec8aa2c52012-04-05 16:22:55 -0700406
407 T("ASC %s: Client has pulled connector FD %d", _asc_socket_string(connector), fd);
408
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700409 return fd;
410}