• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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