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 "android/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
45 struct 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 */
75 static void _on_async_socket_connector_io(void* opaque, int fd, unsigned events);
76
77 /* Gets socket's address string. */
78 AINLINED const char*
_asc_socket_string(AsyncSocketConnector * connector)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 */
88 static void
_async_socket_connector_free(AsyncSocketConnector * connector)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 */
129 static int
_async_socket_connector_open_socket(AsyncSocketConnector * connector)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 */
155 static void
_async_socket_connector_close_socket(AsyncSocketConnector * connector)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 */
175 static void
_on_async_socket_connector_connecting(AsyncSocketConnector * connector,AsyncStatus status)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
215 static void
_on_async_socket_connector_io(void * opaque,int fd,unsigned events)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 */
244 static void
_on_async_socket_connector_retry(void * opaque)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
290 AsyncSocketConnector*
async_socket_connector_new(const SockAddress * address,int retry_to,asc_event_cb cb,void * cb_opaque,Looper * looper)291 async_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
350 int
async_socket_connector_reference(AsyncSocketConnector * connector)351 async_socket_connector_reference(AsyncSocketConnector* connector)
352 {
353 assert(connector->ref_count > 0);
354 connector->ref_count++;
355 return connector->ref_count;
356 }
357
358 int
async_socket_connector_release(AsyncSocketConnector * connector)359 async_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
371 void
async_socket_connector_connect(AsyncSocketConnector * connector)372 async_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
401 int
async_socket_connector_pull_fd(AsyncSocketConnector * connector)402 async_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