blob: 80ec5bbce8e0c541ad64ea03e030b67172a256de [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
35/********************************************************************************
36 * Internals
37 *******************************************************************************/
38
39struct AsyncSocketConnector {
40 /* TCP address for the connection. */
41 SockAddress address;
42 /* I/O looper for asynchronous I/O. */
43 Looper* looper;
44 /* I/O port for asynchronous connection. */
45 LoopIo connector_io[1];
46 /* Timer that is used to retry asynchronous connections. */
47 LoopTimer connector_timer[1];
48 /* Asynchronous connector to the socket. */
49 AsyncConnector connector[1];
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -070050 /* Callback to invoke on connection events. */
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070051 asc_event_cb on_connected_cb;
52 /* An opaque parameter to pass to the connection callback. */
53 void* on_connected_cb_opaque;
54 /* Retry timeout in milliseconds. */
55 int retry_to;
56 /* Socket descriptor for the connection. */
57 int fd;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -070058 /* Number of outstanding references to the connector. */
59 int ref_count;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070060};
61
62/* Asynchronous I/O looper callback invoked by the connector.
63 * Param:
64 * opaque - AsyncSocketConnector instance.
65 * fd, events - Standard I/O callback parameters.
66 */
67static void _on_async_socket_connector_io(void* opaque, int fd, unsigned events);
68
69/* Gets socket's address string. */
70AINLINED const char*
71_asc_socket_string(AsyncSocketConnector* connector)
72{
73 return sock_address_to_string(&connector->address);
74}
75
76/* Destroys AsyncSocketConnector instance.
77 * Param:
78 * connector - Initialized AsyncSocketConnector instance.
79 */
80static void
81_async_socket_connector_free(AsyncSocketConnector* connector)
82{
83 if (connector != NULL) {
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -070084 D("%s: Connector is destroyed.", _asc_socket_string(connector));
85 if (asyncConnector_stop(connector->connector) == 0) {
86 /* Connection was in progress. We need to destroy I/O descriptor for
87 * that connection. */
88 D("%s: Stopped async connection in progress.",
89 _asc_socket_string(connector));
90 loopIo_done(connector->connector_io);
91 }
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070092 if (connector->fd >= 0) {
93 socket_close(connector->fd);
94 }
95
96 if (connector->looper != NULL) {
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -070097 loopTimer_stop(connector->connector_timer);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -070098 loopTimer_done(connector->connector_timer);
99 looper_free(connector->looper);
100 }
101
102 sock_address_done(&connector->address);
103
104 AFREE(connector);
105 }
106}
107
108/* Opens connection socket.
109 * Param:
110 * connector - Initialized AsyncSocketConnector instance.
111 * Return:
112 * 0 on success, or -1 on failure.
113 */
114static int
115_async_socket_connector_open_socket(AsyncSocketConnector* connector)
116{
117 /* Open socket. */
118 connector->fd = socket_create_inet(SOCKET_STREAM);
119 if (connector->fd < 0) {
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700120 D("%s: Unable to create socket: %d -> %s",
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700121 _asc_socket_string(connector), errno, strerror(errno));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700122 return -1;
123 }
124
125 /* Prepare for async I/O on the connector. */
126 socket_set_nonblock(connector->fd);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700127
128 return 0;
129}
130
131/* Closes connection socket.
132 * Param:
133 * connector - Initialized AsyncSocketConnector instance.
134 * Return:
135 * 0 on success, or -1 on failure.
136 */
137static void
138_async_socket_connector_close_socket(AsyncSocketConnector* connector)
139{
140 if (connector->fd >= 0) {
141 socket_close(connector->fd);
142 connector->fd = -1;
143 }
144}
145
146/* Asynchronous connector (AsyncConnector instance) has completed connection
147 * attempt.
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700148 * Param:
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700149 * connector - Initialized AsyncSocketConnector instance. Note: When this
150 * callback is called, the caller has referenced passed connector object,
151 * So, it's guaranteed that this connector is not going to be destroyed
152 * while this routine executes.
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700153 * status - Status of the connection attempt.
154 */
155static void
156_on_async_socket_connector_connecting(AsyncSocketConnector* connector,
157 AsyncStatus status)
158{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700159 AsyncIOAction action = ASIO_ACTION_DONE;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700160
161 switch (status) {
162 case ASYNC_COMPLETE:
163 loopIo_done(connector->connector_io);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700164 D("Socket '%s' is connected", _asc_socket_string(connector));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700165 /* Invoke "on connected" callback */
166 action = connector->on_connected_cb(connector->on_connected_cb_opaque,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700167 connector, ASIO_STATE_SUCCEEDED);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700168 break;
169
170 case ASYNC_ERROR:
171 loopIo_done(connector->connector_io);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700172 D("Error while connecting to socket '%s': %d -> %s",
173 _asc_socket_string(connector), errno, strerror(errno));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700174 /* Invoke "on connected" callback */
175 action = connector->on_connected_cb(connector->on_connected_cb_opaque,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700176 connector, ASIO_STATE_FAILED);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700177 break;
178
179 case ASYNC_NEED_MORE:
180 return;
181 }
182
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700183 if (action == ASIO_ACTION_RETRY) {
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700184 D("%s: Retrying connection", _asc_socket_string(connector));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700185 loopTimer_startRelative(connector->connector_timer, connector->retry_to);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700186 } else if (action == ASIO_ACTION_ABORT) {
187 D("%s: AsyncSocketConnector client for socket '%s' has aborted connection",
188 __FUNCTION__, _asc_socket_string(connector));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700189 }
190}
191
192static void
193_on_async_socket_connector_io(void* opaque, int fd, unsigned events)
194{
195 AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
196
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700197 /* Reference the connector while we're handing I/O. */
198 async_socket_connector_reference(connector);
199
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700200 /* Notify the client that another connection attempt is about to start. */
201 const AsyncIOAction action =
202 connector->on_connected_cb(connector->on_connected_cb_opaque,
203 connector, ASIO_STATE_CONTINUES);
204 if (action != ASIO_ACTION_ABORT) {
205 /* Complete socket connection. */
206 const AsyncStatus status = asyncConnector_run(connector->connector);
207 _on_async_socket_connector_connecting(connector, status);
208 } else {
209 D("%s: AsyncSocketConnector client for socket '%s' has aborted connection",
210 __FUNCTION__, _asc_socket_string(connector));
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700211 }
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700212
213 /* Release the connector after we're done with handing I/O. */
214 async_socket_connector_release(connector);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700215}
216
217/* Retry connection timer callback.
218 * Param:
219 * opaque - AsyncSocketConnector instance.
220 */
221static void
222_on_async_socket_connector_retry(void* opaque)
223{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700224 AsyncStatus status;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700225 AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
226
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700227 /* Reference the connector while we're in callback. */
228 async_socket_connector_reference(connector);
229
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700230 /* Invoke the callback to notify about a connection retry attempt. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700231 AsyncIOAction action =
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700232 connector->on_connected_cb(connector->on_connected_cb_opaque,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700233 connector, ASIO_STATE_RETRYING);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700234
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700235 if (action != ASIO_ACTION_ABORT) {
236 /* Close handle opened for the previous (failed) attempt. */
237 _async_socket_connector_close_socket(connector);
238
239 /* Retry connection attempt. */
240 if (_async_socket_connector_open_socket(connector) == 0) {
241 loopIo_init(connector->connector_io, connector->looper,
242 connector->fd, _on_async_socket_connector_io, connector);
243 status = asyncConnector_init(connector->connector,
244 &connector->address,
245 connector->connector_io);
246 } else {
247 status = ASYNC_ERROR;
248 }
249
250 _on_async_socket_connector_connecting(connector, status);
251 } else {
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700252 D("%s: AsyncSocketConnector client for socket '%s' has aborted connection",
253 __FUNCTION__, _asc_socket_string(connector));
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700254 }
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700255
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700256 /* Release the connector after we're done with the callback. */
257 async_socket_connector_release(connector);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700258}
259
260/********************************************************************************
261 * Async connector implementation
262 *******************************************************************************/
263
264AsyncSocketConnector*
265async_socket_connector_new(const SockAddress* address,
266 int retry_to,
267 asc_event_cb cb,
268 void* cb_opaque)
269{
270 AsyncSocketConnector* connector;
271
272 if (cb == NULL) {
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700273 W("No callback for AsyncSocketConnector for socket '%s'",
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700274 sock_address_to_string(address));
275 errno = EINVAL;
276 return NULL;
277 }
278
279 ANEW0(connector);
280
281 connector->fd = -1;
282 connector->retry_to = retry_to;
283 connector->on_connected_cb = cb;
284 connector->on_connected_cb_opaque = cb_opaque;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700285 connector->ref_count = 1;
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700286
287 /* Copy socket address. */
288 if (sock_address_get_family(address) == SOCKET_UNIX) {
289 sock_address_init_unix(&connector->address, sock_address_get_path(address));
290 } else {
291 connector->address = *address;
292 }
293
294 /* Create a looper for asynchronous I/O. */
295 connector->looper = looper_newCore();
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700296 if (connector->looper == NULL) {
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700297 E("Unable to create I/O looper for AsyncSocketConnector for socket '%s'",
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700298 _asc_socket_string(connector));
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700299 cb(cb_opaque, connector, ASIO_STATE_FAILED);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700300 _async_socket_connector_free(connector);
301 return NULL;
302 }
303
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700304 /* Create a timer that will be used for connection retries. */
305 loopTimer_init(connector->connector_timer, connector->looper,
306 _on_async_socket_connector_retry, connector);
307
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700308 return connector;
309}
310
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700311int
312async_socket_connector_reference(AsyncSocketConnector* connector)
313{
314 assert(connector->ref_count > 0);
315 connector->ref_count++;
316 return connector->ref_count;
317}
318
319int
320async_socket_connector_release(AsyncSocketConnector* connector)
321{
322 assert(connector->ref_count > 0);
323 connector->ref_count--;
324 if (connector->ref_count == 0) {
325 /* Last reference has been dropped. Destroy this object. */
326 _async_socket_connector_free(connector);
327 return 0;
328 }
329 return connector->ref_count;
330}
331
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700332void
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700333async_socket_connector_connect(AsyncSocketConnector* connector)
334{
335 AsyncStatus status;
336
337 if (_async_socket_connector_open_socket(connector) == 0) {
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700338 const AsyncIOAction action =
339 connector->on_connected_cb(connector->on_connected_cb_opaque,
340 connector, ASIO_STATE_STARTED);
341 if (action == ASIO_ACTION_ABORT) {
342 D("%s: AsyncSocketConnector client for socket '%s' has aborted connection",
343 __FUNCTION__, _asc_socket_string(connector));
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700344 return;
345 } else {
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700346 loopIo_init(connector->connector_io, connector->looper,
347 connector->fd, _on_async_socket_connector_io, connector);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700348 status = asyncConnector_init(connector->connector,
349 &connector->address,
350 connector->connector_io);
351 }
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700352 } else {
353 status = ASYNC_ERROR;
354 }
355
356 _on_async_socket_connector_connecting(connector, status);
Vladimir Chtchetkine9d36fe72012-03-26 10:29:20 -0700357}
358
359int
360async_socket_connector_pull_fd(AsyncSocketConnector* connector)
361{
362 const int fd = connector->fd;
363 if (fd >= 0) {
364 connector->fd = -1;
365 }
366 return fd;
367}