blob: daf6a373f365cb1bd34f069be5a95d7e7c721b4a [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];
50 /* Callback to invoke on connection / connection error. */
51 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;
58};
59
60/* Asynchronous I/O looper callback invoked by the connector.
61 * Param:
62 * opaque - AsyncSocketConnector instance.
63 * fd, events - Standard I/O callback parameters.
64 */
65static void _on_async_socket_connector_io(void* opaque, int fd, unsigned events);
66
67/* Gets socket's address string. */
68AINLINED const char*
69_asc_socket_string(AsyncSocketConnector* connector)
70{
71 return sock_address_to_string(&connector->address);
72}
73
74/* Destroys AsyncSocketConnector instance.
75 * Param:
76 * connector - Initialized AsyncSocketConnector instance.
77 */
78static void
79_async_socket_connector_free(AsyncSocketConnector* connector)
80{
81 if (connector != NULL) {
82 if (connector->fd >= 0) {
83 socket_close(connector->fd);
84 }
85
86 if (connector->looper != NULL) {
87 loopTimer_done(connector->connector_timer);
88 looper_free(connector->looper);
89 }
90
91 sock_address_done(&connector->address);
92
93 AFREE(connector);
94 }
95}
96
97/* Opens connection socket.
98 * Param:
99 * connector - Initialized AsyncSocketConnector instance.
100 * Return:
101 * 0 on success, or -1 on failure.
102 */
103static int
104_async_socket_connector_open_socket(AsyncSocketConnector* connector)
105{
106 /* Open socket. */
107 connector->fd = socket_create_inet(SOCKET_STREAM);
108 if (connector->fd < 0) {
109 D("Unable to create connector socket for %s. Error: %s",
110 _asc_socket_string(connector), strerror(errno));
111 return -1;
112 }
113
114 /* Prepare for async I/O on the connector. */
115 socket_set_nonblock(connector->fd);
116 loopIo_init(connector->connector_io, connector->looper, connector->fd,
117 _on_async_socket_connector_io, connector);
118
119 return 0;
120}
121
122/* Closes connection socket.
123 * Param:
124 * connector - Initialized AsyncSocketConnector instance.
125 * Return:
126 * 0 on success, or -1 on failure.
127 */
128static void
129_async_socket_connector_close_socket(AsyncSocketConnector* connector)
130{
131 if (connector->fd >= 0) {
132 socket_close(connector->fd);
133 connector->fd = -1;
134 }
135}
136
137/* Asynchronous connector (AsyncConnector instance) has completed connection
138 * attempt.
139 *
140 * NOTE: Upon exit from this routine AsyncSocketConnector instance might be
141 * destroyed. So, once this routine is called, there must be no further
142 * references to AsyncSocketConnector instance passed to this routine.
143 * Param:
144 * connector - Initialized AsyncSocketConnector instance.
145 * status - Status of the connection attempt.
146 */
147static void
148_on_async_socket_connector_connecting(AsyncSocketConnector* connector,
149 AsyncStatus status)
150{
151 ASCCbRes action;
152 int do_retry = 0;
153
154 switch (status) {
155 case ASYNC_COMPLETE:
156 loopIo_done(connector->connector_io);
157 D("Socket %s is connected", _asc_socket_string(connector));
158 /* Invoke "on connected" callback */
159 action = connector->on_connected_cb(connector->on_connected_cb_opaque,
160 connector, ASC_CONNECTION_SUCCEEDED);
161 if (action == ASC_CB_RETRY) {
162 do_retry = 1;
163 } else if (action == ASC_CB_ABORT) {
164 _async_socket_connector_close_socket(connector);
165 }
166 break;
167
168 case ASYNC_ERROR:
169 loopIo_done(connector->connector_io);
170 D("Error %d while connecting to socket %s: %s",
171 errno, _asc_socket_string(connector), strerror(errno));
172 /* Invoke "on connected" callback */
173 action = connector->on_connected_cb(connector->on_connected_cb_opaque,
174 connector, ASC_CONNECTION_FAILED);
175 if (action == ASC_CB_RETRY) {
176 do_retry = 1;
177 } else if (action == ASC_CB_ABORT) {
178 _async_socket_connector_close_socket(connector);
179 }
180 break;
181
182 case ASYNC_NEED_MORE:
183 return;
184 }
185
186 if (do_retry) {
187 D("Retrying connection to socket %s", _asc_socket_string(connector));
188 loopTimer_startRelative(connector->connector_timer, connector->retry_to);
189 } else {
190 _async_socket_connector_free(connector);
191 }
192}
193
194static void
195_on_async_socket_connector_io(void* opaque, int fd, unsigned events)
196{
197 AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
198
199 /* Complete socket connection. */
200 const AsyncStatus status = asyncConnector_run(connector->connector);
201 _on_async_socket_connector_connecting(connector, status);
202}
203
204/* Retry connection timer callback.
205 * Param:
206 * opaque - AsyncSocketConnector instance.
207 */
208static void
209_on_async_socket_connector_retry(void* opaque)
210{
211 AsyncSocketConnector* const connector = (AsyncSocketConnector*)opaque;
212
213 /* Invoke the callback to notify about a connection retry attempt. */
214 const ASCCbRes action =
215 connector->on_connected_cb(connector->on_connected_cb_opaque,
216 connector, ASC_CONNECTION_RETRY);
217
218 if (action == ASC_CB_RETRY) {
219 AsyncStatus status;
220
221 /* Close handle opened for the previous (failed) attempt. */
222 _async_socket_connector_close_socket(connector);
223
224 /* Retry connection attempt. */
225 if (_async_socket_connector_open_socket(connector) == 0) {
226 status = asyncConnector_init(connector->connector, &connector->address,
227 connector->connector_io);
228 } else {
229 status = ASYNC_ERROR;
230 }
231
232 _on_async_socket_connector_connecting(connector, status);
233 } else {
234 _async_socket_connector_free(connector);
235 }
236}
237
238/********************************************************************************
239 * Async connector implementation
240 *******************************************************************************/
241
242AsyncSocketConnector*
243async_socket_connector_new(const SockAddress* address,
244 int retry_to,
245 asc_event_cb cb,
246 void* cb_opaque)
247{
248 AsyncSocketConnector* connector;
249
250 if (cb == NULL) {
251 W("No callback for AsyncSocketConnector for %s",
252 sock_address_to_string(address));
253 errno = EINVAL;
254 return NULL;
255 }
256
257 ANEW0(connector);
258
259 connector->fd = -1;
260 connector->retry_to = retry_to;
261 connector->on_connected_cb = cb;
262 connector->on_connected_cb_opaque = cb_opaque;
263
264 /* Copy socket address. */
265 if (sock_address_get_family(address) == SOCKET_UNIX) {
266 sock_address_init_unix(&connector->address, sock_address_get_path(address));
267 } else {
268 connector->address = *address;
269 }
270
271 /* Create a looper for asynchronous I/O. */
272 connector->looper = looper_newCore();
273 if (connector->looper != NULL) {
274 /* Create a timer that will be used for connection retries. */
275 loopTimer_init(connector->connector_timer, connector->looper,
276 _on_async_socket_connector_retry, connector);
277 } else {
278 E("Unable to create I/O looper for asynchronous connector to socket %s",
279 _asc_socket_string(connector));
280 _async_socket_connector_free(connector);
281 return NULL;
282 }
283
284 return connector;
285}
286
287ASCConnectRes
288async_socket_connector_connect(AsyncSocketConnector* connector)
289{
290 AsyncStatus status;
291
292 if (_async_socket_connector_open_socket(connector) == 0) {
293 status = asyncConnector_init(connector->connector, &connector->address,
294 connector->connector_io);
295 } else {
296 status = ASYNC_ERROR;
297 }
298
299 _on_async_socket_connector_connecting(connector, status);
300
301 switch (status) {
302 case ASYNC_COMPLETE:
303 return ASC_CONNECT_SUCCEEDED;
304
305 case ASYNC_ERROR:
306 return ASC_CONNECT_FAILED;
307
308 case ASYNC_NEED_MORE:
309 default:
310 return ASC_CONNECT_IN_PROGRESS;
311 }
312}
313
314int
315async_socket_connector_pull_fd(AsyncSocketConnector* connector)
316{
317 const int fd = connector->fd;
318 if (fd >= 0) {
319 connector->fd = -1;
320 }
321 return fd;
322}