blob: 4be69f675b3c2a588cf3b730ecf3091e1d9dc108 [file] [log] [blame]
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001/*
2 * Copyright (C) 2012 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 "android/async-socket.h"
28#include "utils/panic.h"
29#include "iolooper.h"
30
31#define E(...) derror(__VA_ARGS__)
32#define W(...) dwarning(__VA_ARGS__)
33#define D(...) VERBOSE_PRINT(asyncsocket,__VA_ARGS__)
34#define D_ACTIVE VERBOSE_CHECK(asyncsocket)
35
36/********************************************************************************
37 * Asynchronous Socket internal API declarations
38 *******************************************************************************/
39
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -070040/* Gets socket's address string. */
41static const char* _async_socket_string(AsyncSocket* as);
42
43/* Gets socket's looper. */
44static Looper* _async_socket_get_looper(AsyncSocket* as);
45
46/* Handler for the I/O time out.
47 * Param:
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -070048 * as - Asynchronous socket for the I/O.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -070049 * asio - Desciptor for the timed out I/O.
50 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -070051static AsyncIOAction _async_socket_io_timed_out(AsyncSocket* as,
52 AsyncSocketIO* asio);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -070053
54/********************************************************************************
55 * Asynchronous Socket Reader / Writer
56 *******************************************************************************/
57
58struct AsyncSocketIO {
59 /* Next I/O in the reader, or writer list. */
60 AsyncSocketIO* next;
61 /* Asynchronous socket for this I/O. */
62 AsyncSocket* as;
63 /* Timer used for time outs on this I/O. */
64 LoopTimer timer[1];
65 /* An opaque pointer associated with this I/O. */
66 void* io_opaque;
67 /* Buffer where to read / write data. */
68 uint8_t* buffer;
69 /* Bytes to transfer through the socket for this I/O. */
70 uint32_t to_transfer;
71 /* Bytes thransferred through the socket in this I/O. */
72 uint32_t transferred;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -070073 /* I/O callback for this I/O. */
74 on_as_io_cb on_io;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -070075 /* I/O type selector: 1 - read, 0 - write. */
76 int is_io_read;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -070077 /* State of the I/O. */
78 AsyncIOState state;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -070079};
80
81/*
82 * Recycling I/O instances.
83 * Since AsyncSocketIO instances are not that large, it makes sence to recycle
84 * them for faster allocation, rather than allocating and freeing them for each
85 * I/O on the socket.
86 */
87
88/* List of recycled I/O descriptors. */
89static AsyncSocketIO* _asio_recycled = NULL;
90/* Number of I/O descriptors that are recycled in the _asio_recycled list. */
91static int _recycled_asio_count = 0;
92/* Maximum number of I/O descriptors that can be recycled. */
93static const int _max_recycled_asio_num = 32;
94
95/* Handler for an I/O time-out timer event.
96 * When this routine is invoked, it indicates that a time out has occurred on an
97 * I/O.
98 * Param:
99 * opaque - AsyncSocketIO instance representing the timed out I/O.
100 */
101static void _on_async_socket_io_timed_out(void* opaque);
102
103/* Creates new I/O descriptor.
104 * Param:
105 * as - Asynchronous socket for the I/O.
106 * is_io_read - I/O type selector: 1 - read, 0 - write.
107 * buffer, len - Reader / writer buffer address.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700108 * io_cb - Callback for this reader / writer.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700109 * io_opaque - An opaque pointer associated with the I/O.
110 * deadline - Deadline to complete the I/O.
111 * Return:
112 * Initialized AsyncSocketIO instance.
113 */
114static AsyncSocketIO*
115_async_socket_rw_new(AsyncSocket* as,
116 int is_io_read,
117 void* buffer,
118 uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700119 on_as_io_cb io_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700120 void* io_opaque,
121 Duration deadline)
122{
123 /* Lookup in the recycler first. */
124 AsyncSocketIO* asio = _asio_recycled;
125 if (asio != NULL) {
126 /* Pull the descriptor from recycler. */
127 _asio_recycled = asio->next;
128 _recycled_asio_count--;
129 } else {
130 /* No recycled descriptors. Allocate new one. */
131 ANEW0(asio);
132 }
133
134 asio->next = NULL;
135 asio->as = as;
136 asio->is_io_read = is_io_read;
137 asio->buffer = (uint8_t*)buffer;
138 asio->to_transfer = len;
139 asio->transferred = 0;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700140 asio->on_io = io_cb;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700141 asio->io_opaque = io_opaque;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700142 asio->state = ASIO_STATE_QUEUED;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700143
144 loopTimer_init(asio->timer, _async_socket_get_looper(as),
145 _on_async_socket_io_timed_out, asio);
146 loopTimer_startAbsolute(asio->timer, deadline);
147
148 return asio;
149}
150
151/* Destroys and frees I/O descriptor. */
152static void
153_async_socket_io_destroy(AsyncSocketIO* asio)
154{
155 loopTimer_stop(asio->timer);
156 loopTimer_done(asio->timer);
157
158 /* Try to recycle it first, and free the memory if recycler is full. */
159 if (_recycled_asio_count < _max_recycled_asio_num) {
160 asio->next = _asio_recycled;
161 _asio_recycled = asio;
162 _recycled_asio_count++;
163 } else {
164 AFREE(asio);
165 }
166}
167
168/* Creates new asynchronous socket reader.
169 * Param:
170 * as - Asynchronous socket for the reader.
171 * buffer, len - Reader's buffer.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700172 * io_cb - Reader's callback.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700173 * reader_opaque - An opaque pointer associated with the reader.
174 * deadline - Deadline to complete the operation.
175 * Return:
176 * An initialized AsyncSocketIO intance.
177 */
178static AsyncSocketIO*
179_async_socket_reader_new(AsyncSocket* as,
180 void* buffer,
181 uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700182 on_as_io_cb io_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700183 void* reader_opaque,
184 Duration deadline)
185{
186 AsyncSocketIO* const asio = _async_socket_rw_new(as, 1, buffer, len, io_cb,
187 reader_opaque, deadline);
188 return asio;
189}
190
191/* Creates new asynchronous socket writer.
192 * Param:
193 * as - Asynchronous socket for the writer.
194 * buffer, len - Writer's buffer.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700195 * io_cb - Writer's callback.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700196 * writer_opaque - An opaque pointer associated with the writer.
197 * deadline - Deadline to complete the operation.
198 * Return:
199 * An initialized AsyncSocketIO intance.
200 */
201static AsyncSocketIO*
202_async_socket_writer_new(AsyncSocket* as,
203 const void* buffer,
204 uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700205 on_as_io_cb io_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700206 void* writer_opaque,
207 Duration deadline)
208{
209 AsyncSocketIO* const asio = _async_socket_rw_new(as, 0, (void*)buffer, len,
210 io_cb, writer_opaque,
211 deadline);
212 return asio;
213}
214
215/* I/O timed out. */
216static void
217_on_async_socket_io_timed_out(void* opaque)
218{
219 AsyncSocketIO* const asio = (AsyncSocketIO*)opaque;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700220 const AsyncIOAction action = _async_socket_io_timed_out(asio->as, asio);
221 if (action != ASIO_ACTION_RETRY) {
222 _async_socket_io_destroy(asio);
223 }
224}
225
226/********************************************************************************
227 * Public Asynchronous Socket I/O API
228 *******************************************************************************/
229
230AsyncSocket*
231async_socket_io_get_socket(const AsyncSocketIO* asio)
232{
233 return asio->as;
234}
235
236void
237async_socket_io_cancel_time_out(AsyncSocketIO* asio)
238{
239 loopTimer_stop(asio->timer);
240}
241
242void*
243async_socket_io_get_io_opaque(const AsyncSocketIO* asio)
244{
245 return asio->io_opaque;
246}
247
248void*
249async_socket_io_get_client_opaque(const AsyncSocketIO* asio)
250{
251 return async_socket_get_client_opaque(asio->as);
252}
253
254void*
255async_socket_io_get_buffer_info(const AsyncSocketIO* asio,
256 uint32_t* transferred,
257 uint32_t* to_transfer)
258{
259 if (transferred != NULL) {
260 *transferred = asio->transferred;
261 }
262 if (to_transfer != NULL) {
263 *to_transfer = asio->to_transfer;
264 }
265 return asio->buffer;
266}
267
268void*
269async_socket_io_get_buffer(const AsyncSocketIO* asio)
270{
271 return asio->buffer;
272}
273
274uint32_t
275async_socket_io_get_transferred(const AsyncSocketIO* asio)
276{
277 return asio->transferred;
278}
279
280uint32_t
281async_socket_io_get_to_transfer(const AsyncSocketIO* asio)
282{
283 return asio->to_transfer;
284}
285
286int
287async_socket_io_is_read(const AsyncSocketIO* asio)
288{
289 return asio->is_io_read;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700290}
291
292/********************************************************************************
293 * Asynchronous Socket internals
294 *******************************************************************************/
295
296struct AsyncSocket {
297 /* TCP address for the socket. */
298 SockAddress address;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700299 /* Connection callback for this socket. */
300 on_as_connection_cb on_connection;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700301 /* An opaque pointer associated with this socket by the client. */
302 void* client_opaque;
303 /* I/O looper for asynchronous I/O on the socket. */
304 Looper* looper;
305 /* I/O descriptor for asynchronous I/O on the socket. */
306 LoopIo io[1];
307 /* Timer to use for reconnection attempts. */
308 LoopTimer reconnect_timer[1];
309 /* Head of the list of the active readers. */
310 AsyncSocketIO* readers_head;
311 /* Tail of the list of the active readers. */
312 AsyncSocketIO* readers_tail;
313 /* Head of the list of the active writers. */
314 AsyncSocketIO* writers_head;
315 /* Tail of the list of the active writers. */
316 AsyncSocketIO* writers_tail;
317 /* Socket's file descriptor. */
318 int fd;
319 /* Timeout to use for reconnection attempts. */
320 int reconnect_to;
321};
322
323static const char*
324_async_socket_string(AsyncSocket* as)
325{
326 return sock_address_to_string(&as->address);
327}
328
329static Looper*
330_async_socket_get_looper(AsyncSocket* as)
331{
332 return as->looper;
333}
334
335/* Pulls first reader out of the list.
336 * Param:
337 * as - Initialized AsyncSocket instance.
338 * Return:
339 * First I/O pulled out of the list, or NULL if there are no I/O in the list.
340 */
341static AsyncSocketIO*
342_async_socket_pull_first_io(AsyncSocket* as,
343 AsyncSocketIO** list_head,
344 AsyncSocketIO** list_tail)
345{
346 AsyncSocketIO* const ret = *list_head;
347 if (ret != NULL) {
348 *list_head = ret->next;
349 ret->next = NULL;
350 if (*list_head == NULL) {
351 *list_tail = NULL;
352 }
353 }
354 return ret;
355}
356
357/* Pulls first reader out of the list.
358 * Param:
359 * as - Initialized AsyncSocket instance.
360 * Return:
361 * First reader pulled out of the list, or NULL if there are no readers in the
362 * list.
363 */
364static AsyncSocketIO*
365_async_socket_pull_first_reader(AsyncSocket* as)
366{
367 return _async_socket_pull_first_io(as, &as->readers_head, &as->readers_tail);
368}
369
370/* Pulls first writer out of the list.
371 * Param:
372 * as - Initialized AsyncSocket instance.
373 * Return:
374 * First writer pulled out of the list, or NULL if there are no writers in the
375 * list.
376 */
377static AsyncSocketIO*
378_async_socket_pull_first_writer(AsyncSocket* as)
379{
380 return _async_socket_pull_first_io(as, &as->writers_head, &as->writers_tail);
381}
382
383/* Removes an I/O descriptor from a list of active I/O.
384 * Param:
385 * as - Initialized AsyncSocket instance.
386 * list_head, list_tail - Pointers to the list head and tail.
387 * io - I/O to remove.
388 * Return:
389 * Boolean: 1 if I/O has been removed, or 0 if I/O has not been found in the list.
390 */
391static int
392_async_socket_remove_io(AsyncSocket* as,
393 AsyncSocketIO** list_head,
394 AsyncSocketIO** list_tail,
395 AsyncSocketIO* io)
396{
397 AsyncSocketIO* prev = NULL;
398
399 while (*list_head != NULL && io != *list_head) {
400 prev = *list_head;
401 list_head = &((*list_head)->next);
402 }
403 if (*list_head == NULL) {
404 D("%s: I/O %p is not found in the list for socket '%s'",
405 __FUNCTION__, io, _async_socket_string(as));
406 return 0;
407 }
408
409 *list_head = io->next;
410 if (prev != NULL) {
411 prev->next = io->next;
412 }
413 if (*list_tail == io) {
414 *list_tail = prev;
415 }
416
417 return 1;
418}
419
420/* Advances to the next I/O in the list.
421 * Param:
422 * as - Initialized AsyncSocket instance.
423 * list_head, list_tail - Pointers to the list head and tail.
424 * Return:
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700425 * Next I/O at the head of the list, or NULL if I/O list became empty.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700426 */
427static AsyncSocketIO*
428_async_socket_advance_io(AsyncSocket* as,
429 AsyncSocketIO** list_head,
430 AsyncSocketIO** list_tail)
431{
432 AsyncSocketIO* first_io = *list_head;
433 if (first_io != NULL) {
434 *list_head = first_io->next;
435 first_io->next = NULL;
436 }
437 if (*list_head == NULL) {
438 *list_tail = NULL;
439 }
440 return *list_head;
441}
442
443/* Advances to the next reader in the list.
444 * Param:
445 * as - Initialized AsyncSocket instance.
446 * Return:
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700447 * Next reader at the head of the list, or NULL if reader list became empty.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700448 */
449static AsyncSocketIO*
450_async_socket_advance_reader(AsyncSocket* as)
451{
452 return _async_socket_advance_io(as, &as->readers_head, &as->readers_tail);
453}
454
455/* Advances to the next writer in the list.
456 * Param:
457 * as - Initialized AsyncSocket instance.
458 * Return:
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700459 * Next writer at the head of the list, or NULL if writer list became empty.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700460 */
461static AsyncSocketIO*
462_async_socket_advance_writer(AsyncSocket* as)
463{
464 return _async_socket_advance_io(as, &as->writers_head, &as->writers_tail);
465}
466
467/* Completes an I/O.
468 * Param:
469 * as - Initialized AsyncSocket instance.
470 * asio - I/O to complete.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700471 * Return:
472 * One of AsyncIOAction values.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700473 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700474static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700475_async_socket_complete_io(AsyncSocket* as, AsyncSocketIO* asio)
476{
477 /* Stop the timer. */
478 loopTimer_stop(asio->timer);
479
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700480 return asio->on_io(asio->io_opaque, asio, ASIO_STATE_SUCCEEDED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700481}
482
483/* Timeouts an I/O.
484 * Param:
485 * as - Initialized AsyncSocket instance.
486 * asio - An I/O that has timed out.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700487 * Return:
488 * One of AsyncIOAction values.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700489 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700490static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700491_async_socket_io_timed_out(AsyncSocket* as, AsyncSocketIO* asio)
492{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700493 /* Report to the client. */
494 const AsyncIOAction action = asio->on_io(asio->io_opaque, asio,
495 ASIO_STATE_TIMED_OUT);
496
497 /* Remove the I/O from a list of active I/O for actions other than retry. */
498 if (action != ASIO_ACTION_RETRY) {
499 if (asio->is_io_read) {
500 _async_socket_remove_io(as, &as->readers_head, &as->readers_tail, asio);
501 } else {
502 _async_socket_remove_io(as, &as->writers_head, &as->writers_tail, asio);
503 }
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700504 }
505
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700506 return action;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700507}
508
509/* Cancels an I/O.
510 * Param:
511 * as - Initialized AsyncSocket instance.
512 * asio - An I/O to cancel.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700513 * Return:
514 * One of AsyncIOAction values.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700515 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700516static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700517_async_socket_cancel_io(AsyncSocket* as, AsyncSocketIO* asio)
518{
519 /* Stop the timer. */
520 loopTimer_stop(asio->timer);
521
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700522 return asio->on_io(asio->io_opaque, asio, ASIO_STATE_CANCELLED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700523}
524
525/* Reports an I/O failure.
526 * Param:
527 * as - Initialized AsyncSocket instance.
528 * asio - An I/O that has failed. Can be NULL for general failures.
529 * failure - Failure (errno) that has occurred.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700530 * Return:
531 * One of AsyncIOAction values.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700532 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700533static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700534_async_socket_io_failure(AsyncSocket* as, AsyncSocketIO* asio, int failure)
535{
536 /* Stop the timer. */
537 loopTimer_stop(asio->timer);
538
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700539 errno = failure;
540 return asio->on_io(asio->io_opaque, asio, ASIO_STATE_FAILED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700541}
542
543/* Cancels all the active socket readers.
544 * Param:
545 * as - Initialized AsyncSocket instance.
546 */
547static void
548_async_socket_cancel_readers(AsyncSocket* as)
549{
550 while (as->readers_head != NULL) {
551 AsyncSocketIO* const to_cancel = _async_socket_pull_first_reader(as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700552 /* We ignore action returned from the cancellation callback, since we're
553 * in a disconnected state here. */
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700554 _async_socket_cancel_io(as, to_cancel);
555 _async_socket_io_destroy(to_cancel);
556 }
557}
558
559/* Cancels all the active socket writers.
560 * Param:
561 * as - Initialized AsyncSocket instance.
562 */
563static void
564_async_socket_cancel_writers(AsyncSocket* as)
565{
566 while (as->writers_head != NULL) {
567 AsyncSocketIO* const to_cancel = _async_socket_pull_first_writer(as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700568 /* We ignore action returned from the cancellation callback, since we're
569 * in a disconnected state here. */
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700570 _async_socket_cancel_io(as, to_cancel);
571 _async_socket_io_destroy(to_cancel);
572 }
573}
574
575/* Cancels all the I/O on the socket. */
576static void
577_async_socket_cancel_all_io(AsyncSocket* as)
578{
579 /* Stop the reconnection timer. */
580 loopTimer_stop(as->reconnect_timer);
581
582 /* Stop read / write on the socket. */
583 loopIo_dontWantWrite(as->io);
584 loopIo_dontWantRead(as->io);
585
586 /* Cancel active readers and writers. */
587 _async_socket_cancel_readers(as);
588 _async_socket_cancel_writers(as);
589}
590
591/* Closes socket handle used by the async socket.
592 * Param:
593 * as - Initialized AsyncSocket instance.
594 */
595static void
596_async_socket_close_socket(AsyncSocket* as)
597{
598 if (as->fd >= 0) {
599 loopIo_done(as->io);
600 socket_close(as->fd);
601 as->fd = -1;
602 }
603}
604
605/* Destroys AsyncSocket instance.
606 * Param:
607 * as - Initialized AsyncSocket instance.
608 */
609static void
610_async_socket_destroy(AsyncSocket* as)
611{
612 if (as != NULL) {
613 /* Cancel all the I/O */
614 _async_socket_cancel_all_io(as);
615
616 /* Close socket. */
617 _async_socket_close_socket(as);
618
619 /* Free allocated resources. */
620 if (as->looper != NULL) {
621 loopTimer_done(as->reconnect_timer);
622 looper_free(as->looper);
623 }
624 sock_address_done(&as->address);
625 AFREE(as);
626 }
627}
628
629/* Starts reconnection attempts after connection has been lost.
630 * Param:
631 * as - Initialized AsyncSocket instance.
632 * to - Milliseconds to wait before reconnection attempt.
633 */
634static void
635_async_socket_reconnect(AsyncSocket* as, int to)
636{
637 /* Make sure that no I/O is active, and socket is closed before we
638 * reconnect. */
639 _async_socket_cancel_all_io(as);
640
641 /* Set the timer for reconnection attempt. */
642 loopTimer_startRelative(as->reconnect_timer, to);
643}
644
645/********************************************************************************
646 * Asynchronous Socket callbacks
647 *******************************************************************************/
648
649/* A callback that is invoked when socket gets disconnected.
650 * Param:
651 * as - Initialized AsyncSocket instance.
652 */
653static void
654_on_async_socket_disconnected(AsyncSocket* as)
655{
656 /* Save error to restore it for the client's callback. */
657 const int save_errno = errno;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700658 AsyncIOAction action = ASIO_ACTION_ABORT;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700659
660 D("Async socket '%s' is disconnected. Error %d -> %s",
661 _async_socket_string(as), errno, strerror(errno));
662
663 /* Cancel all the I/O on this socket. */
664 _async_socket_cancel_all_io(as);
665
666 /* Close the socket. */
667 _async_socket_close_socket(as);
668
669 /* Restore errno, and invoke client's callback. */
670 errno = save_errno;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700671 action = as->on_connection(as->client_opaque, as, ASIO_STATE_FAILED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700672
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700673 if (action == ASIO_ACTION_RETRY) {
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700674 /* Client requested reconnection. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700675 _async_socket_reconnect(as, as->reconnect_to);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700676 }
677}
678
679/* A callback that is invoked on socket's I/O failure.
680 * Param:
681 * as - Initialized AsyncSocket instance.
682 * asio - Descriptor for the failed I/O. Can be NULL for general failures.
683 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700684static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700685_on_async_socket_failure(AsyncSocket* as, AsyncSocketIO* asio)
686{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700687 D("Async socket '%s' I/O failure: %d -> %s",
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700688 _async_socket_string(as), errno, strerror(errno));
689
690 /* Report the failure. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700691 return _async_socket_io_failure(as, asio, errno);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700692}
693
694/* A callback that is invoked when there is data available to read.
695 * Param:
696 * as - Initialized AsyncSocket instance.
697 * Return:
698 * 0 on success, or -1 on failure. Failure returned from this routine will
699 * skip writes (if awailable) behind this read.
700 */
701static int
702_on_async_socket_recv(AsyncSocket* as)
703{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700704 AsyncIOAction action;
705
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700706 /* Get current reader. */
707 AsyncSocketIO* const asr = as->readers_head;
708 if (asr == NULL) {
709 D("No async socket reader available on IO_READ for '%s'",
710 _async_socket_string(as));
711 loopIo_dontWantRead(as->io);
712 return 0;
713 }
714
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700715 /* Bump I/O state, and inform the client that I/O is in progress. */
716 if (asr->state == ASIO_STATE_QUEUED) {
717 asr->state = ASIO_STATE_STARTED;
718 } else {
719 asr->state = ASIO_STATE_CONTINUES;
720 }
721 action = asr->on_io(asr->io_opaque, asr, asr->state);
722 if (action == ASIO_ACTION_ABORT) {
723 D("Read is aborted by the client of async socket '%s'",
724 _async_socket_string(as));
725 /* Move on to the next reader. */
726 _async_socket_advance_reader(as);
727 _async_socket_io_destroy(asr);
728 /* Lets see if there are still active readers, and enable, or disable
729 * read I/O callback accordingly. */
730 if (as->readers_head != NULL) {
731 loopIo_wantRead(as->io);
732 } else {
733 loopIo_dontWantRead(as->io);
734 }
735 return 0;
736 }
737
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700738 /* Read next chunk of data. */
739 int res = socket_recv(as->fd, asr->buffer + asr->transferred,
740 asr->to_transfer - asr->transferred);
741 while (res < 0 && errno == EINTR) {
742 res = socket_recv(as->fd, asr->buffer + asr->transferred,
743 asr->to_transfer - asr->transferred);
744 }
745
746 if (res == 0) {
747 /* Socket has been disconnected. */
748 errno = ECONNRESET;
749 _on_async_socket_disconnected(as);
750 return -1;
751 }
752
753 if (res < 0) {
754 if (errno == EWOULDBLOCK || errno == EAGAIN) {
755 /* Yield to writes behind this read. */
756 loopIo_wantRead(as->io);
757 return 0;
758 }
759
760 /* An I/O error. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700761 action = _on_async_socket_failure(as, asr);
762 if (action == ASIO_ACTION_ABORT) {
763 D("Read is aborted on failure by the client of async socket '%s'",
764 _async_socket_string(as));
765 /* Move on to the next reader. */
766 _async_socket_advance_reader(as);
767 _async_socket_io_destroy(asr);
768 /* Lets see if there are still active readers, and enable, or disable
769 * read I/O callback accordingly. */
770 if (as->readers_head != NULL) {
771 loopIo_wantRead(as->io);
772 } else {
773 loopIo_dontWantRead(as->io);
774 }
775 }
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700776 return -1;
777 }
778
779 /* Update the reader's descriptor. */
780 asr->transferred += res;
781 if (asr->transferred == asr->to_transfer) {
782 /* This read is completed. Move on to the next reader. */
783 _async_socket_advance_reader(as);
784
785 /* Notify reader completion. */
786 _async_socket_complete_io(as, asr);
787 _async_socket_io_destroy(asr);
788 }
789
790 /* Lets see if there are still active readers, and enable, or disable read
791 * I/O callback accordingly. */
792 if (as->readers_head != NULL) {
793 loopIo_wantRead(as->io);
794 } else {
795 loopIo_dontWantRead(as->io);
796 }
797
798 return 0;
799}
800
801/* A callback that is invoked when there is data available to write.
802 * Param:
803 * as - Initialized AsyncSocket instance.
804 * Return:
805 * 0 on success, or -1 on failure. Failure returned from this routine will
806 * skip reads (if awailable) behind this write.
807 */
808static int
809_on_async_socket_send(AsyncSocket* as)
810{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700811 AsyncIOAction action;
812
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700813 /* Get current writer. */
814 AsyncSocketIO* const asw = as->writers_head;
815 if (asw == NULL) {
816 D("No async socket writer available on IO_WRITE for '%s'",
817 _async_socket_string(as));
818 loopIo_dontWantWrite(as->io);
819 return 0;
820 }
821
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700822 /* Bump I/O state, and inform the client that I/O is in progress. */
823 if (asw->state == ASIO_STATE_QUEUED) {
824 asw->state = ASIO_STATE_STARTED;
825 } else {
826 asw->state = ASIO_STATE_CONTINUES;
827 }
828 action = asw->on_io(asw->io_opaque, asw, asw->state);
829 if (action == ASIO_ACTION_ABORT) {
830 D("Write is aborted by the client of async socket '%s'",
831 _async_socket_string(as));
832 /* Move on to the next reader. */
833 _async_socket_advance_reader(as);
834 _async_socket_io_destroy(asw);
835 /* Lets see if there are still active writers, and enable, or disable
836 * write I/O callback accordingly. */
837 if (as->writers_head != NULL) {
838 loopIo_wantWrite(as->io);
839 } else {
840 loopIo_dontWantWrite(as->io);
841 }
842 return 0;
843 }
844
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700845 /* Write next chunk of data. */
846 int res = socket_send(as->fd, asw->buffer + asw->transferred,
847 asw->to_transfer - asw->transferred);
848 while (res < 0 && errno == EINTR) {
849 res = socket_send(as->fd, asw->buffer + asw->transferred,
850 asw->to_transfer - asw->transferred);
851 }
852
853 if (res == 0) {
854 /* Socket has been disconnected. */
855 errno = ECONNRESET;
856 _on_async_socket_disconnected(as);
857 return -1;
858 }
859
860 if (res < 0) {
861 if (errno == EWOULDBLOCK || errno == EAGAIN) {
862 /* Yield to reads behind this write. */
863 loopIo_wantWrite(as->io);
864 return 0;
865 }
866
867 /* An I/O error. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700868 /* An I/O error. */
869 action = _on_async_socket_failure(as, asw);
870 if (action == ASIO_ACTION_ABORT) {
871 D("Write is aborted on failure by the client of async socket '%s'",
872 _async_socket_string(as));
873 /* Move on to the next reader. */
874 _async_socket_advance_reader(as);
875 _async_socket_io_destroy(asw);
876 /* Lets see if there are still active writers, and enable, or disable
877 * write I/O callback accordingly. */
878 if (as->writers_head != NULL) {
879 loopIo_wantWrite(as->io);
880 } else {
881 loopIo_dontWantWrite(as->io);
882 }
883 }
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700884 return -1;
885 }
886
887 /* Update the reader descriptor. */
888 asw->transferred += res;
889 if (asw->transferred == asw->to_transfer) {
890 /* This write is completed. Move on to the next writer. */
891 _async_socket_advance_writer(as);
892
893 /* Notify writer completion. */
894 _async_socket_complete_io(as, asw);
895 _async_socket_io_destroy(asw);
896 }
897
898 /* Lets see if there are still active writers, and enable, or disable write
899 * I/O callback accordingly. */
900 if (as->writers_head != NULL) {
901 loopIo_wantWrite(as->io);
902 } else {
903 loopIo_dontWantWrite(as->io);
904 }
905
906 return 0;
907}
908
909/* A callback that is invoked when an I/O is available on socket.
910 * Param:
911 * as - Initialized AsyncSocket instance.
912 * fd - Socket's file descriptor.
913 * events - LOOP_IO_READ | LOOP_IO_WRITE bitmask.
914 */
915static void
916_on_async_socket_io(void* opaque, int fd, unsigned events)
917{
918 AsyncSocket* const as = (AsyncSocket*)opaque;
919
920 if ((events & LOOP_IO_READ) != 0) {
921 if (_on_async_socket_recv(as) != 0) {
922 return;
923 }
924 }
925
926 if ((events & LOOP_IO_WRITE) != 0) {
927 if (_on_async_socket_send(as) != 0) {
928 return;
929 }
930 }
931}
932
933/* A callback that is invoked by asynchronous socket connector on connection
934 * events.
935 * Param:
936 * opaque - Initialized AsyncSocket instance.
937 * connector - Connector that is used to connect this socket.
938 * event - Connection event.
939 * Return:
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700940 * One of AsyncIOAction values.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700941 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700942static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700943_on_connector_events(void* opaque,
944 AsyncSocketConnector* connector,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700945 AsyncIOState event)
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700946{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700947 AsyncIOAction action;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700948 AsyncSocket* const as = (AsyncSocket*)opaque;
949
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700950 if (event == ASIO_STATE_SUCCEEDED) {
951 /* Accept the connection. */
952 as->fd = async_socket_connector_pull_fd(connector);
953 loopIo_init(as->io, as->looper, as->fd, _on_async_socket_io, as);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700954 }
955
956 /* Invoke client's callback. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700957 action = as->on_connection(as->client_opaque, as, event);
958 if (event == ASIO_STATE_SUCCEEDED && action != ASIO_ACTION_DONE) {
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700959 /* For whatever reason the client didn't want to keep this connection.
960 * Close it. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700961 D("Connection is discarded by a client of async socket '%s'",
962 _async_socket_string(as));
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700963 _async_socket_close_socket(as);
964 }
965
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700966 return action;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700967}
968
969/* Timer callback invoked to reconnect the lost connection.
970 * Param:
971 * as - Initialized AsyncSocket instance.
972 */
973void
974_on_async_socket_reconnect(void* opaque)
975{
976 AsyncSocket* as = (AsyncSocket*)opaque;
977 async_socket_connect(as, as->reconnect_to);
978}
979
980
981/********************************************************************************
982 * Android Device Socket public API
983 *******************************************************************************/
984
985AsyncSocket*
986async_socket_new(int port,
987 int reconnect_to,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700988 on_as_connection_cb client_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700989 void* client_opaque)
990{
991 AsyncSocket* as;
992
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700993 if (client_cb == NULL) {
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700994 E("Invalid client_cb parameter");
995 return NULL;
996 }
997
998 ANEW0(as);
999
1000 as->fd = -1;
1001 as->client_opaque = client_opaque;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001002 as->on_connection = client_cb;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001003 as->readers_head = as->readers_tail = NULL;
1004 as->reconnect_to = reconnect_to;
1005 sock_address_init_inet(&as->address, SOCK_ADDRESS_INET_LOOPBACK, port);
1006 as->looper = looper_newCore();
1007 if (as->looper == NULL) {
1008 E("Unable to create I/O looper for async socket '%s'",
1009 _async_socket_string(as));
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001010 client_cb(client_opaque, as, ASIO_STATE_FAILED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001011 _async_socket_destroy(as);
1012 return NULL;
1013 }
1014 loopTimer_init(as->reconnect_timer, as->looper, _on_async_socket_reconnect, as);
1015
1016 return as;
1017}
1018
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001019void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001020async_socket_connect(AsyncSocket* as, int retry_to)
1021{
1022 AsyncSocketConnector* const connector =
1023 async_socket_connector_new(&as->address, retry_to, _on_connector_events, as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001024 if (connector != NULL) {
1025 async_socket_connector_connect(connector);
1026 } else {
1027 as->on_connection(as->client_opaque, as, ASIO_STATE_FAILED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001028 }
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001029}
1030
1031void
1032async_socket_disconnect(AsyncSocket* as)
1033{
1034 if (as != NULL) {
1035 _async_socket_cancel_all_io(as);
1036 _async_socket_close_socket(as);
1037 _async_socket_destroy(as);
1038 }
1039}
1040
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001041void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001042async_socket_reconnect(AsyncSocket* as, int retry_to)
1043{
1044 _async_socket_cancel_all_io(as);
1045 _async_socket_close_socket(as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001046 async_socket_connect(as, retry_to);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001047}
1048
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001049void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001050async_socket_read_abs(AsyncSocket* as,
1051 void* buffer, uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001052 on_as_io_cb reader_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001053 void* reader_opaque,
1054 Duration deadline)
1055{
1056 AsyncSocketIO* const asr =
1057 _async_socket_reader_new(as, buffer, len, reader_cb, reader_opaque,
1058 deadline);
1059 if (as->readers_head == NULL) {
1060 as->readers_head = as->readers_tail = asr;
1061 } else {
1062 as->readers_tail->next = asr;
1063 as->readers_tail = asr;
1064 }
1065 loopIo_wantRead(as->io);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001066}
1067
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001068void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001069async_socket_read_rel(AsyncSocket* as,
1070 void* buffer, uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001071 on_as_io_cb reader_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001072 void* reader_opaque,
1073 int to)
1074{
1075 const Duration dl = (to >= 0) ? looper_now(_async_socket_get_looper(as)) + to :
1076 DURATION_INFINITE;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001077 async_socket_read_abs(as, buffer, len, reader_cb, reader_opaque, dl);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001078}
1079
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001080void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001081async_socket_write_abs(AsyncSocket* as,
1082 const void* buffer, uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001083 on_as_io_cb writer_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001084 void* writer_opaque,
1085 Duration deadline)
1086{
1087 AsyncSocketIO* const asw =
1088 _async_socket_writer_new(as, buffer, len, writer_cb, writer_opaque,
1089 deadline);
1090 if (as->writers_head == NULL) {
1091 as->writers_head = as->writers_tail = asw;
1092 } else {
1093 as->writers_tail->next = asw;
1094 as->writers_tail = asw;
1095 }
1096 loopIo_wantWrite(as->io);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001097}
1098
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001099void
1100async_socket_write_rel(AsyncSocket* as,
1101 const void* buffer, uint32_t len,
1102 on_as_io_cb writer_cb,
1103 void* writer_opaque,
1104 int to)
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001105{
1106 const Duration dl = (to >= 0) ? looper_now(_async_socket_get_looper(as)) + to :
1107 DURATION_INFINITE;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001108 async_socket_write_abs(as, buffer, len, writer_cb, writer_opaque, dl);
1109}
1110
1111void*
1112async_socket_get_client_opaque(const AsyncSocket* as)
1113{
1114 return as->client_opaque;
1115}
1116
1117Duration
1118async_socket_deadline(AsyncSocket* as, int rel)
1119{
1120 return (rel >= 0) ? looper_now(_async_socket_get_looper(as)) + rel :
1121 DURATION_INFINITE;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001122}