blob: a2577c901f5167b5237421ed445d8f1f03e262e6 [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 Chtchetkineef4ccd32012-04-03 10:27:12 -070079 /* Number of outstanding references to the I/O. */
80 int ref_count;
81 /* Deadline for this I/O */
82 Duration deadline;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -070083};
84
85/*
86 * Recycling I/O instances.
87 * Since AsyncSocketIO instances are not that large, it makes sence to recycle
88 * them for faster allocation, rather than allocating and freeing them for each
89 * I/O on the socket.
90 */
91
92/* List of recycled I/O descriptors. */
93static AsyncSocketIO* _asio_recycled = NULL;
94/* Number of I/O descriptors that are recycled in the _asio_recycled list. */
95static int _recycled_asio_count = 0;
96/* Maximum number of I/O descriptors that can be recycled. */
97static const int _max_recycled_asio_num = 32;
98
99/* Handler for an I/O time-out timer event.
100 * When this routine is invoked, it indicates that a time out has occurred on an
101 * I/O.
102 * Param:
103 * opaque - AsyncSocketIO instance representing the timed out I/O.
104 */
105static void _on_async_socket_io_timed_out(void* opaque);
106
107/* Creates new I/O descriptor.
108 * Param:
109 * as - Asynchronous socket for the I/O.
110 * is_io_read - I/O type selector: 1 - read, 0 - write.
111 * buffer, len - Reader / writer buffer address.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700112 * io_cb - Callback for this reader / writer.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700113 * io_opaque - An opaque pointer associated with the I/O.
114 * deadline - Deadline to complete the I/O.
115 * Return:
116 * Initialized AsyncSocketIO instance.
117 */
118static AsyncSocketIO*
119_async_socket_rw_new(AsyncSocket* as,
120 int is_io_read,
121 void* buffer,
122 uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700123 on_as_io_cb io_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700124 void* io_opaque,
125 Duration deadline)
126{
127 /* Lookup in the recycler first. */
128 AsyncSocketIO* asio = _asio_recycled;
129 if (asio != NULL) {
130 /* Pull the descriptor from recycler. */
131 _asio_recycled = asio->next;
132 _recycled_asio_count--;
133 } else {
134 /* No recycled descriptors. Allocate new one. */
135 ANEW0(asio);
136 }
137
138 asio->next = NULL;
139 asio->as = as;
140 asio->is_io_read = is_io_read;
141 asio->buffer = (uint8_t*)buffer;
142 asio->to_transfer = len;
143 asio->transferred = 0;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700144 asio->on_io = io_cb;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700145 asio->io_opaque = io_opaque;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700146 asio->state = ASIO_STATE_QUEUED;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700147 asio->ref_count = 1;
148 asio->deadline = deadline;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700149 loopTimer_init(asio->timer, _async_socket_get_looper(as),
150 _on_async_socket_io_timed_out, asio);
151 loopTimer_startAbsolute(asio->timer, deadline);
152
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700153 /* Reference socket that is holding this I/O. */
154 async_socket_reference(as);
155
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700156 return asio;
157}
158
159/* Destroys and frees I/O descriptor. */
160static void
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700161_async_socket_io_free(AsyncSocketIO* asio)
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700162{
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700163 AsyncSocket* const as = asio->as;
164
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700165 loopTimer_stop(asio->timer);
166 loopTimer_done(asio->timer);
167
168 /* Try to recycle it first, and free the memory if recycler is full. */
169 if (_recycled_asio_count < _max_recycled_asio_num) {
170 asio->next = _asio_recycled;
171 _asio_recycled = asio;
172 _recycled_asio_count++;
173 } else {
174 AFREE(asio);
175 }
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700176
177 /* Release socket that is holding this I/O. */
178 async_socket_release(as);
179}
180
181int
182async_socket_io_reference(AsyncSocketIO* asio)
183{
184 assert(asio->ref_count > 0);
185 asio->ref_count++;
186 return asio->ref_count;
187}
188
189int
190async_socket_io_release(AsyncSocketIO* asio)
191{
192 assert(asio->ref_count > 0);
193 asio->ref_count--;
194 if (asio->ref_count == 0) {
195 /* Last reference has been dropped. Destroy this object. */
196 _async_socket_io_free(asio);
197 return 0;
198 }
199 return asio->ref_count;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700200}
201
202/* Creates new asynchronous socket reader.
203 * Param:
204 * as - Asynchronous socket for the reader.
205 * buffer, len - Reader's buffer.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700206 * io_cb - Reader's callback.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700207 * reader_opaque - An opaque pointer associated with the reader.
208 * deadline - Deadline to complete the operation.
209 * Return:
210 * An initialized AsyncSocketIO intance.
211 */
212static AsyncSocketIO*
213_async_socket_reader_new(AsyncSocket* as,
214 void* buffer,
215 uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700216 on_as_io_cb io_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700217 void* reader_opaque,
218 Duration deadline)
219{
220 AsyncSocketIO* const asio = _async_socket_rw_new(as, 1, buffer, len, io_cb,
221 reader_opaque, deadline);
222 return asio;
223}
224
225/* Creates new asynchronous socket writer.
226 * Param:
227 * as - Asynchronous socket for the writer.
228 * buffer, len - Writer's buffer.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700229 * io_cb - Writer's callback.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700230 * writer_opaque - An opaque pointer associated with the writer.
231 * deadline - Deadline to complete the operation.
232 * Return:
233 * An initialized AsyncSocketIO intance.
234 */
235static AsyncSocketIO*
236_async_socket_writer_new(AsyncSocket* as,
237 const void* buffer,
238 uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700239 on_as_io_cb io_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700240 void* writer_opaque,
241 Duration deadline)
242{
243 AsyncSocketIO* const asio = _async_socket_rw_new(as, 0, (void*)buffer, len,
244 io_cb, writer_opaque,
245 deadline);
246 return asio;
247}
248
249/* I/O timed out. */
250static void
251_on_async_socket_io_timed_out(void* opaque)
252{
253 AsyncSocketIO* const asio = (AsyncSocketIO*)opaque;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700254 AsyncSocket* const as = asio->as;
255
256 D("%s: %s I/O (deadline = %lld) timed out at %lld",
257 _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE",
258 asio->deadline, async_socket_deadline(as, 0));
259
260 /* Reference while in callback. */
261 async_socket_io_reference(asio);
262 _async_socket_io_timed_out(asio->as, asio);
263 async_socket_io_release(asio);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700264}
265
266/********************************************************************************
267 * Public Asynchronous Socket I/O API
268 *******************************************************************************/
269
270AsyncSocket*
271async_socket_io_get_socket(const AsyncSocketIO* asio)
272{
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700273 async_socket_reference(asio->as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700274 return asio->as;
275}
276
277void
278async_socket_io_cancel_time_out(AsyncSocketIO* asio)
279{
280 loopTimer_stop(asio->timer);
281}
282
283void*
284async_socket_io_get_io_opaque(const AsyncSocketIO* asio)
285{
286 return asio->io_opaque;
287}
288
289void*
290async_socket_io_get_client_opaque(const AsyncSocketIO* asio)
291{
292 return async_socket_get_client_opaque(asio->as);
293}
294
295void*
296async_socket_io_get_buffer_info(const AsyncSocketIO* asio,
297 uint32_t* transferred,
298 uint32_t* to_transfer)
299{
300 if (transferred != NULL) {
301 *transferred = asio->transferred;
302 }
303 if (to_transfer != NULL) {
304 *to_transfer = asio->to_transfer;
305 }
306 return asio->buffer;
307}
308
309void*
310async_socket_io_get_buffer(const AsyncSocketIO* asio)
311{
312 return asio->buffer;
313}
314
315uint32_t
316async_socket_io_get_transferred(const AsyncSocketIO* asio)
317{
318 return asio->transferred;
319}
320
321uint32_t
322async_socket_io_get_to_transfer(const AsyncSocketIO* asio)
323{
324 return asio->to_transfer;
325}
326
327int
328async_socket_io_is_read(const AsyncSocketIO* asio)
329{
330 return asio->is_io_read;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700331}
332
333/********************************************************************************
334 * Asynchronous Socket internals
335 *******************************************************************************/
336
337struct AsyncSocket {
338 /* TCP address for the socket. */
339 SockAddress address;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700340 /* Connection callback for this socket. */
341 on_as_connection_cb on_connection;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700342 /* An opaque pointer associated with this socket by the client. */
343 void* client_opaque;
344 /* I/O looper for asynchronous I/O on the socket. */
345 Looper* looper;
346 /* I/O descriptor for asynchronous I/O on the socket. */
347 LoopIo io[1];
348 /* Timer to use for reconnection attempts. */
349 LoopTimer reconnect_timer[1];
350 /* Head of the list of the active readers. */
351 AsyncSocketIO* readers_head;
352 /* Tail of the list of the active readers. */
353 AsyncSocketIO* readers_tail;
354 /* Head of the list of the active writers. */
355 AsyncSocketIO* writers_head;
356 /* Tail of the list of the active writers. */
357 AsyncSocketIO* writers_tail;
358 /* Socket's file descriptor. */
359 int fd;
360 /* Timeout to use for reconnection attempts. */
361 int reconnect_to;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700362 /* Number of outstanding references to the socket. */
363 int ref_count;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700364};
365
366static const char*
367_async_socket_string(AsyncSocket* as)
368{
369 return sock_address_to_string(&as->address);
370}
371
372static Looper*
373_async_socket_get_looper(AsyncSocket* as)
374{
375 return as->looper;
376}
377
378/* Pulls first reader out of the list.
379 * Param:
380 * as - Initialized AsyncSocket instance.
381 * Return:
382 * First I/O pulled out of the list, or NULL if there are no I/O in the list.
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700383 * Note that the caller is responsible for releasing the I/O object returned
384 * from this routine.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700385 */
386static AsyncSocketIO*
387_async_socket_pull_first_io(AsyncSocket* as,
388 AsyncSocketIO** list_head,
389 AsyncSocketIO** list_tail)
390{
391 AsyncSocketIO* const ret = *list_head;
392 if (ret != NULL) {
393 *list_head = ret->next;
394 ret->next = NULL;
395 if (*list_head == NULL) {
396 *list_tail = NULL;
397 }
398 }
399 return ret;
400}
401
402/* Pulls first reader out of the list.
403 * Param:
404 * as - Initialized AsyncSocket instance.
405 * Return:
406 * First reader pulled out of the list, or NULL if there are no readers in the
407 * list.
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700408 * Note that the caller is responsible for releasing the I/O object returned
409 * from this routine.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700410 */
411static AsyncSocketIO*
412_async_socket_pull_first_reader(AsyncSocket* as)
413{
414 return _async_socket_pull_first_io(as, &as->readers_head, &as->readers_tail);
415}
416
417/* Pulls first writer out of the list.
418 * Param:
419 * as - Initialized AsyncSocket instance.
420 * Return:
421 * First writer pulled out of the list, or NULL if there are no writers in the
422 * list.
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700423 * Note that the caller is responsible for releasing the I/O object returned
424 * from this routine.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700425 */
426static AsyncSocketIO*
427_async_socket_pull_first_writer(AsyncSocket* as)
428{
429 return _async_socket_pull_first_io(as, &as->writers_head, &as->writers_tail);
430}
431
432/* Removes an I/O descriptor from a list of active I/O.
433 * Param:
434 * as - Initialized AsyncSocket instance.
435 * list_head, list_tail - Pointers to the list head and tail.
436 * io - I/O to remove.
437 * Return:
438 * Boolean: 1 if I/O has been removed, or 0 if I/O has not been found in the list.
439 */
440static int
441_async_socket_remove_io(AsyncSocket* as,
442 AsyncSocketIO** list_head,
443 AsyncSocketIO** list_tail,
444 AsyncSocketIO* io)
445{
446 AsyncSocketIO* prev = NULL;
447
448 while (*list_head != NULL && io != *list_head) {
449 prev = *list_head;
450 list_head = &((*list_head)->next);
451 }
452 if (*list_head == NULL) {
453 D("%s: I/O %p is not found in the list for socket '%s'",
454 __FUNCTION__, io, _async_socket_string(as));
455 return 0;
456 }
457
458 *list_head = io->next;
459 if (prev != NULL) {
460 prev->next = io->next;
461 }
462 if (*list_tail == io) {
463 *list_tail = prev;
464 }
465
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700466 /* Release I/O adjusting reference added when I/O has been saved in the list. */
467 async_socket_io_release(io);
468
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700469 return 1;
470}
471
472/* Advances to the next I/O in the list.
473 * Param:
474 * as - Initialized AsyncSocket instance.
475 * list_head, list_tail - Pointers to the list head and tail.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700476 */
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700477static void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700478_async_socket_advance_io(AsyncSocket* as,
479 AsyncSocketIO** list_head,
480 AsyncSocketIO** list_tail)
481{
482 AsyncSocketIO* first_io = *list_head;
483 if (first_io != NULL) {
484 *list_head = first_io->next;
485 first_io->next = NULL;
486 }
487 if (*list_head == NULL) {
488 *list_tail = NULL;
489 }
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700490 if (first_io != NULL) {
491 /* Release I/O removed from the head of the list. */
492 async_socket_io_release(first_io);
493 }
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700494}
495
496/* Advances to the next reader in the list.
497 * Param:
498 * as - Initialized AsyncSocket instance.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700499 */
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700500static void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700501_async_socket_advance_reader(AsyncSocket* as)
502{
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700503 _async_socket_advance_io(as, &as->readers_head, &as->readers_tail);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700504}
505
506/* Advances to the next writer in the list.
507 * Param:
508 * as - Initialized AsyncSocket instance.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700509 */
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700510static void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700511_async_socket_advance_writer(AsyncSocket* as)
512{
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700513 _async_socket_advance_io(as, &as->writers_head, &as->writers_tail);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700514}
515
516/* Completes an I/O.
517 * Param:
518 * as - Initialized AsyncSocket instance.
519 * asio - I/O to complete.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700520 * Return:
521 * One of AsyncIOAction values.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700522 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700523static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700524_async_socket_complete_io(AsyncSocket* as, AsyncSocketIO* asio)
525{
526 /* Stop the timer. */
527 loopTimer_stop(asio->timer);
528
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700529 return asio->on_io(asio->io_opaque, asio, ASIO_STATE_SUCCEEDED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700530}
531
532/* Timeouts an I/O.
533 * Param:
534 * as - Initialized AsyncSocket instance.
535 * asio - An I/O that has timed out.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700536 * Return:
537 * One of AsyncIOAction values.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700538 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700539static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700540_async_socket_io_timed_out(AsyncSocket* as, AsyncSocketIO* asio)
541{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700542 /* Report to the client. */
543 const AsyncIOAction action = asio->on_io(asio->io_opaque, asio,
544 ASIO_STATE_TIMED_OUT);
545
546 /* Remove the I/O from a list of active I/O for actions other than retry. */
547 if (action != ASIO_ACTION_RETRY) {
548 if (asio->is_io_read) {
549 _async_socket_remove_io(as, &as->readers_head, &as->readers_tail, asio);
550 } else {
551 _async_socket_remove_io(as, &as->writers_head, &as->writers_tail, asio);
552 }
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700553 }
554
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700555 return action;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700556}
557
558/* Cancels an I/O.
559 * Param:
560 * as - Initialized AsyncSocket instance.
561 * asio - An I/O to cancel.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700562 * Return:
563 * One of AsyncIOAction values.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700564 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700565static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700566_async_socket_cancel_io(AsyncSocket* as, AsyncSocketIO* asio)
567{
568 /* Stop the timer. */
569 loopTimer_stop(asio->timer);
570
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700571 return asio->on_io(asio->io_opaque, asio, ASIO_STATE_CANCELLED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700572}
573
574/* Reports an I/O failure.
575 * Param:
576 * as - Initialized AsyncSocket instance.
577 * asio - An I/O that has failed. Can be NULL for general failures.
578 * failure - Failure (errno) that has occurred.
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700579 * Return:
580 * One of AsyncIOAction values.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700581 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700582static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700583_async_socket_io_failure(AsyncSocket* as, AsyncSocketIO* asio, int failure)
584{
585 /* Stop the timer. */
586 loopTimer_stop(asio->timer);
587
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700588 errno = failure;
589 return asio->on_io(asio->io_opaque, asio, ASIO_STATE_FAILED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700590}
591
592/* Cancels all the active socket readers.
593 * Param:
594 * as - Initialized AsyncSocket instance.
595 */
596static void
597_async_socket_cancel_readers(AsyncSocket* as)
598{
599 while (as->readers_head != NULL) {
600 AsyncSocketIO* const to_cancel = _async_socket_pull_first_reader(as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700601 /* We ignore action returned from the cancellation callback, since we're
602 * in a disconnected state here. */
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700603 _async_socket_cancel_io(as, to_cancel);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700604 async_socket_io_release(to_cancel);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700605 }
606}
607
608/* Cancels all the active socket writers.
609 * Param:
610 * as - Initialized AsyncSocket instance.
611 */
612static void
613_async_socket_cancel_writers(AsyncSocket* as)
614{
615 while (as->writers_head != NULL) {
616 AsyncSocketIO* const to_cancel = _async_socket_pull_first_writer(as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700617 /* We ignore action returned from the cancellation callback, since we're
618 * in a disconnected state here. */
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700619 _async_socket_cancel_io(as, to_cancel);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700620 async_socket_io_release(to_cancel);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700621 }
622}
623
624/* Cancels all the I/O on the socket. */
625static void
626_async_socket_cancel_all_io(AsyncSocket* as)
627{
628 /* Stop the reconnection timer. */
629 loopTimer_stop(as->reconnect_timer);
630
631 /* Stop read / write on the socket. */
632 loopIo_dontWantWrite(as->io);
633 loopIo_dontWantRead(as->io);
634
635 /* Cancel active readers and writers. */
636 _async_socket_cancel_readers(as);
637 _async_socket_cancel_writers(as);
638}
639
640/* Closes socket handle used by the async socket.
641 * Param:
642 * as - Initialized AsyncSocket instance.
643 */
644static void
645_async_socket_close_socket(AsyncSocket* as)
646{
647 if (as->fd >= 0) {
648 loopIo_done(as->io);
649 socket_close(as->fd);
650 as->fd = -1;
651 }
652}
653
654/* Destroys AsyncSocket instance.
655 * Param:
656 * as - Initialized AsyncSocket instance.
657 */
658static void
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700659_async_socket_free(AsyncSocket* as)
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700660{
661 if (as != NULL) {
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700662 D("AsyncSocket '%s' is destroyed", _async_socket_string(as));
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700663
664 /* Close socket. */
665 _async_socket_close_socket(as);
666
667 /* Free allocated resources. */
668 if (as->looper != NULL) {
669 loopTimer_done(as->reconnect_timer);
670 looper_free(as->looper);
671 }
672 sock_address_done(&as->address);
673 AFREE(as);
674 }
675}
676
677/* Starts reconnection attempts after connection has been lost.
678 * Param:
679 * as - Initialized AsyncSocket instance.
680 * to - Milliseconds to wait before reconnection attempt.
681 */
682static void
683_async_socket_reconnect(AsyncSocket* as, int to)
684{
685 /* Make sure that no I/O is active, and socket is closed before we
686 * reconnect. */
687 _async_socket_cancel_all_io(as);
688
689 /* Set the timer for reconnection attempt. */
690 loopTimer_startRelative(as->reconnect_timer, to);
691}
692
693/********************************************************************************
694 * Asynchronous Socket callbacks
695 *******************************************************************************/
696
697/* A callback that is invoked when socket gets disconnected.
698 * Param:
699 * as - Initialized AsyncSocket instance.
700 */
701static void
702_on_async_socket_disconnected(AsyncSocket* as)
703{
704 /* Save error to restore it for the client's callback. */
705 const int save_errno = errno;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700706 AsyncIOAction action = ASIO_ACTION_ABORT;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700707
708 D("Async socket '%s' is disconnected. Error %d -> %s",
709 _async_socket_string(as), errno, strerror(errno));
710
711 /* Cancel all the I/O on this socket. */
712 _async_socket_cancel_all_io(as);
713
714 /* Close the socket. */
715 _async_socket_close_socket(as);
716
717 /* Restore errno, and invoke client's callback. */
718 errno = save_errno;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700719 action = as->on_connection(as->client_opaque, as, ASIO_STATE_FAILED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700720
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700721 if (action == ASIO_ACTION_RETRY) {
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700722 /* Client requested reconnection. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700723 _async_socket_reconnect(as, as->reconnect_to);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700724 }
725}
726
727/* A callback that is invoked on socket's I/O failure.
728 * Param:
729 * as - Initialized AsyncSocket instance.
730 * asio - Descriptor for the failed I/O. Can be NULL for general failures.
731 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700732static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700733_on_async_socket_failure(AsyncSocket* as, AsyncSocketIO* asio)
734{
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700735 D("Async socket '%s' %s I/O failure: %d -> %s",
736 _async_socket_string(as), asio->is_io_read ? "READ" : "WRITE",
737 errno, strerror(errno));
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700738
739 /* Report the failure. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700740 return _async_socket_io_failure(as, asio, errno);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700741}
742
743/* A callback that is invoked when there is data available to read.
744 * Param:
745 * as - Initialized AsyncSocket instance.
746 * Return:
747 * 0 on success, or -1 on failure. Failure returned from this routine will
748 * skip writes (if awailable) behind this read.
749 */
750static int
751_on_async_socket_recv(AsyncSocket* as)
752{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700753 AsyncIOAction action;
754
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700755 /* Get current reader. */
756 AsyncSocketIO* const asr = as->readers_head;
757 if (asr == NULL) {
758 D("No async socket reader available on IO_READ for '%s'",
759 _async_socket_string(as));
760 loopIo_dontWantRead(as->io);
761 return 0;
762 }
763
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700764 /* Reference the reader while we're working with it in this callback. */
765 async_socket_io_reference(asr);
766
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700767 /* Bump I/O state, and inform the client that I/O is in progress. */
768 if (asr->state == ASIO_STATE_QUEUED) {
769 asr->state = ASIO_STATE_STARTED;
770 } else {
771 asr->state = ASIO_STATE_CONTINUES;
772 }
773 action = asr->on_io(asr->io_opaque, asr, asr->state);
774 if (action == ASIO_ACTION_ABORT) {
775 D("Read is aborted by the client of async socket '%s'",
776 _async_socket_string(as));
777 /* Move on to the next reader. */
778 _async_socket_advance_reader(as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700779 /* Lets see if there are still active readers, and enable, or disable
780 * read I/O callback accordingly. */
781 if (as->readers_head != NULL) {
782 loopIo_wantRead(as->io);
783 } else {
784 loopIo_dontWantRead(as->io);
785 }
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700786 async_socket_io_release(asr);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700787 return 0;
788 }
789
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700790 /* Read next chunk of data. */
791 int res = socket_recv(as->fd, asr->buffer + asr->transferred,
792 asr->to_transfer - asr->transferred);
793 while (res < 0 && errno == EINTR) {
794 res = socket_recv(as->fd, asr->buffer + asr->transferred,
795 asr->to_transfer - asr->transferred);
796 }
797
798 if (res == 0) {
799 /* Socket has been disconnected. */
800 errno = ECONNRESET;
801 _on_async_socket_disconnected(as);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700802 async_socket_io_release(asr);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700803 return -1;
804 }
805
806 if (res < 0) {
807 if (errno == EWOULDBLOCK || errno == EAGAIN) {
808 /* Yield to writes behind this read. */
809 loopIo_wantRead(as->io);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700810 async_socket_io_release(asr);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700811 return 0;
812 }
813
814 /* An I/O error. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700815 action = _on_async_socket_failure(as, asr);
816 if (action == ASIO_ACTION_ABORT) {
817 D("Read is aborted on failure by the client of async socket '%s'",
818 _async_socket_string(as));
819 /* Move on to the next reader. */
820 _async_socket_advance_reader(as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700821 /* Lets see if there are still active readers, and enable, or disable
822 * read I/O callback accordingly. */
823 if (as->readers_head != NULL) {
824 loopIo_wantRead(as->io);
825 } else {
826 loopIo_dontWantRead(as->io);
827 }
828 }
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700829 async_socket_io_release(asr);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700830 return -1;
831 }
832
833 /* Update the reader's descriptor. */
834 asr->transferred += res;
835 if (asr->transferred == asr->to_transfer) {
836 /* This read is completed. Move on to the next reader. */
837 _async_socket_advance_reader(as);
838
839 /* Notify reader completion. */
840 _async_socket_complete_io(as, asr);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700841 }
842
843 /* Lets see if there are still active readers, and enable, or disable read
844 * I/O callback accordingly. */
845 if (as->readers_head != NULL) {
846 loopIo_wantRead(as->io);
847 } else {
848 loopIo_dontWantRead(as->io);
849 }
850
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700851 async_socket_io_release(asr);
852
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700853 return 0;
854}
855
856/* A callback that is invoked when there is data available to write.
857 * Param:
858 * as - Initialized AsyncSocket instance.
859 * Return:
860 * 0 on success, or -1 on failure. Failure returned from this routine will
861 * skip reads (if awailable) behind this write.
862 */
863static int
864_on_async_socket_send(AsyncSocket* as)
865{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700866 AsyncIOAction action;
867
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700868 /* Get current writer. */
869 AsyncSocketIO* const asw = as->writers_head;
870 if (asw == NULL) {
871 D("No async socket writer available on IO_WRITE for '%s'",
872 _async_socket_string(as));
873 loopIo_dontWantWrite(as->io);
874 return 0;
875 }
876
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700877 /* Reference the writer while we're working with it in this callback. */
878 async_socket_io_reference(asw);
879
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700880 /* Bump I/O state, and inform the client that I/O is in progress. */
881 if (asw->state == ASIO_STATE_QUEUED) {
882 asw->state = ASIO_STATE_STARTED;
883 } else {
884 asw->state = ASIO_STATE_CONTINUES;
885 }
886 action = asw->on_io(asw->io_opaque, asw, asw->state);
887 if (action == ASIO_ACTION_ABORT) {
888 D("Write is aborted by the client of async socket '%s'",
889 _async_socket_string(as));
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700890 /* Move on to the next writer. */
891 _async_socket_advance_writer(as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700892 /* Lets see if there are still active writers, and enable, or disable
893 * write I/O callback accordingly. */
894 if (as->writers_head != NULL) {
895 loopIo_wantWrite(as->io);
896 } else {
897 loopIo_dontWantWrite(as->io);
898 }
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700899 async_socket_io_release(asw);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700900 return 0;
901 }
902
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700903 /* Write next chunk of data. */
904 int res = socket_send(as->fd, asw->buffer + asw->transferred,
905 asw->to_transfer - asw->transferred);
906 while (res < 0 && errno == EINTR) {
907 res = socket_send(as->fd, asw->buffer + asw->transferred,
908 asw->to_transfer - asw->transferred);
909 }
910
911 if (res == 0) {
912 /* Socket has been disconnected. */
913 errno = ECONNRESET;
914 _on_async_socket_disconnected(as);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700915 async_socket_io_release(asw);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700916 return -1;
917 }
918
919 if (res < 0) {
920 if (errno == EWOULDBLOCK || errno == EAGAIN) {
921 /* Yield to reads behind this write. */
922 loopIo_wantWrite(as->io);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700923 async_socket_io_release(asw);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700924 return 0;
925 }
926
927 /* An I/O error. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700928 action = _on_async_socket_failure(as, asw);
929 if (action == ASIO_ACTION_ABORT) {
930 D("Write is aborted on failure by the client of async socket '%s'",
931 _async_socket_string(as));
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700932 /* Move on to the next writer. */
933 _async_socket_advance_writer(as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -0700934 /* Lets see if there are still active writers, and enable, or disable
935 * write I/O callback accordingly. */
936 if (as->writers_head != NULL) {
937 loopIo_wantWrite(as->io);
938 } else {
939 loopIo_dontWantWrite(as->io);
940 }
941 }
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700942 async_socket_io_release(asw);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700943 return -1;
944 }
945
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700946 /* Update the writer descriptor. */
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700947 asw->transferred += res;
948 if (asw->transferred == asw->to_transfer) {
949 /* This write is completed. Move on to the next writer. */
950 _async_socket_advance_writer(as);
951
952 /* Notify writer completion. */
953 _async_socket_complete_io(as, asw);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700954 }
955
956 /* Lets see if there are still active writers, and enable, or disable write
957 * I/O callback accordingly. */
958 if (as->writers_head != NULL) {
959 loopIo_wantWrite(as->io);
960 } else {
961 loopIo_dontWantWrite(as->io);
962 }
963
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700964 async_socket_io_release(asw);
965
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700966 return 0;
967}
968
969/* A callback that is invoked when an I/O is available on socket.
970 * Param:
971 * as - Initialized AsyncSocket instance.
972 * fd - Socket's file descriptor.
973 * events - LOOP_IO_READ | LOOP_IO_WRITE bitmask.
974 */
975static void
976_on_async_socket_io(void* opaque, int fd, unsigned events)
977{
978 AsyncSocket* const as = (AsyncSocket*)opaque;
979
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700980 /* Reference the socket while we're working with it in this callback. */
981 async_socket_reference(as);
982
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700983 if ((events & LOOP_IO_READ) != 0) {
984 if (_on_async_socket_recv(as) != 0) {
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700985 async_socket_release(as);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700986 return;
987 }
988 }
989
990 if ((events & LOOP_IO_WRITE) != 0) {
991 if (_on_async_socket_send(as) != 0) {
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700992 async_socket_release(as);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700993 return;
994 }
995 }
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -0700996
997 async_socket_release(as);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -0700998}
999
1000/* A callback that is invoked by asynchronous socket connector on connection
1001 * events.
1002 * Param:
1003 * opaque - Initialized AsyncSocket instance.
1004 * connector - Connector that is used to connect this socket.
1005 * event - Connection event.
1006 * Return:
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001007 * One of AsyncIOAction values.
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001008 */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001009static AsyncIOAction
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001010_on_connector_events(void* opaque,
1011 AsyncSocketConnector* connector,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001012 AsyncIOState event)
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001013{
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001014 AsyncIOAction action;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001015 AsyncSocket* const as = (AsyncSocket*)opaque;
1016
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -07001017 /* Reference the socket while we're working with it in this callback. */
1018 async_socket_reference(as);
1019
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001020 if (event == ASIO_STATE_SUCCEEDED) {
1021 /* Accept the connection. */
1022 as->fd = async_socket_connector_pull_fd(connector);
1023 loopIo_init(as->io, as->looper, as->fd, _on_async_socket_io, as);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001024 }
1025
1026 /* Invoke client's callback. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001027 action = as->on_connection(as->client_opaque, as, event);
1028 if (event == ASIO_STATE_SUCCEEDED && action != ASIO_ACTION_DONE) {
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001029 /* For whatever reason the client didn't want to keep this connection.
1030 * Close it. */
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001031 D("Connection is discarded by a client of async socket '%s'",
1032 _async_socket_string(as));
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001033 _async_socket_close_socket(as);
1034 }
1035
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -07001036 if (action != ASIO_ACTION_RETRY) {
1037 async_socket_connector_release(connector);
1038 }
1039
1040 async_socket_release(as);
1041
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001042 return action;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001043}
1044
1045/* Timer callback invoked to reconnect the lost connection.
1046 * Param:
1047 * as - Initialized AsyncSocket instance.
1048 */
1049void
1050_on_async_socket_reconnect(void* opaque)
1051{
1052 AsyncSocket* as = (AsyncSocket*)opaque;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -07001053
1054 /* Reference the socket while we're working with it in this callback. */
1055 async_socket_reference(as);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001056 async_socket_connect(as, as->reconnect_to);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -07001057 async_socket_release(as);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001058}
1059
1060
1061/********************************************************************************
1062 * Android Device Socket public API
1063 *******************************************************************************/
1064
1065AsyncSocket*
1066async_socket_new(int port,
1067 int reconnect_to,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001068 on_as_connection_cb client_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001069 void* client_opaque)
1070{
1071 AsyncSocket* as;
1072
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001073 if (client_cb == NULL) {
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001074 E("Invalid client_cb parameter");
1075 return NULL;
1076 }
1077
1078 ANEW0(as);
1079
1080 as->fd = -1;
1081 as->client_opaque = client_opaque;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001082 as->on_connection = client_cb;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001083 as->readers_head = as->readers_tail = NULL;
1084 as->reconnect_to = reconnect_to;
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -07001085 as->ref_count = 1;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001086 sock_address_init_inet(&as->address, SOCK_ADDRESS_INET_LOOPBACK, port);
1087 as->looper = looper_newCore();
1088 if (as->looper == NULL) {
1089 E("Unable to create I/O looper for async socket '%s'",
1090 _async_socket_string(as));
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001091 client_cb(client_opaque, as, ASIO_STATE_FAILED);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -07001092 _async_socket_free(as);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001093 return NULL;
1094 }
1095 loopTimer_init(as->reconnect_timer, as->looper, _on_async_socket_reconnect, as);
1096
1097 return as;
1098}
1099
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -07001100int
1101async_socket_reference(AsyncSocket* as)
1102{
1103 assert(as->ref_count > 0);
1104 as->ref_count++;
1105 return as->ref_count;
1106}
1107
1108int
1109async_socket_release(AsyncSocket* as)
1110{
1111 assert(as->ref_count > 0);
1112 as->ref_count--;
1113 if (as->ref_count == 0) {
1114 /* Last reference has been dropped. Destroy this object. */
1115 _async_socket_cancel_all_io(as);
1116 _async_socket_free(as);
1117 return 0;
1118 }
1119 return as->ref_count;
1120}
1121
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001122void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001123async_socket_connect(AsyncSocket* as, int retry_to)
1124{
1125 AsyncSocketConnector* const connector =
1126 async_socket_connector_new(&as->address, retry_to, _on_connector_events, as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001127 if (connector != NULL) {
1128 async_socket_connector_connect(connector);
1129 } else {
1130 as->on_connection(as->client_opaque, as, ASIO_STATE_FAILED);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001131 }
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001132}
1133
1134void
1135async_socket_disconnect(AsyncSocket* as)
1136{
1137 if (as != NULL) {
1138 _async_socket_cancel_all_io(as);
1139 _async_socket_close_socket(as);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001140 }
1141}
1142
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001143void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001144async_socket_reconnect(AsyncSocket* as, int retry_to)
1145{
1146 _async_socket_cancel_all_io(as);
1147 _async_socket_close_socket(as);
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001148 async_socket_connect(as, retry_to);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001149}
1150
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001151void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001152async_socket_read_abs(AsyncSocket* as,
1153 void* buffer, uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001154 on_as_io_cb reader_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001155 void* reader_opaque,
1156 Duration deadline)
1157{
1158 AsyncSocketIO* const asr =
1159 _async_socket_reader_new(as, buffer, len, reader_cb, reader_opaque,
1160 deadline);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -07001161 /* Add new reader to the list. Note that we use initial reference from I/O
1162 * 'new' routine as "in the list" reference counter. */
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001163 if (as->readers_head == NULL) {
1164 as->readers_head = as->readers_tail = asr;
1165 } else {
1166 as->readers_tail->next = asr;
1167 as->readers_tail = asr;
1168 }
1169 loopIo_wantRead(as->io);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001170}
1171
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001172void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001173async_socket_read_rel(AsyncSocket* as,
1174 void* buffer, uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001175 on_as_io_cb reader_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001176 void* reader_opaque,
1177 int to)
1178{
1179 const Duration dl = (to >= 0) ? looper_now(_async_socket_get_looper(as)) + to :
1180 DURATION_INFINITE;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001181 async_socket_read_abs(as, buffer, len, reader_cb, reader_opaque, dl);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001182}
1183
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001184void
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001185async_socket_write_abs(AsyncSocket* as,
1186 const void* buffer, uint32_t len,
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001187 on_as_io_cb writer_cb,
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001188 void* writer_opaque,
1189 Duration deadline)
1190{
1191 AsyncSocketIO* const asw =
1192 _async_socket_writer_new(as, buffer, len, writer_cb, writer_opaque,
1193 deadline);
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -07001194 /* Add new writer to the list. Note that we use initial reference from I/O
1195 * 'new' routine as "in the list" reference counter. */
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001196 if (as->writers_head == NULL) {
1197 as->writers_head = as->writers_tail = asw;
1198 } else {
1199 as->writers_tail->next = asw;
1200 as->writers_tail = asw;
1201 }
1202 loopIo_wantWrite(as->io);
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001203}
1204
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001205void
1206async_socket_write_rel(AsyncSocket* as,
1207 const void* buffer, uint32_t len,
1208 on_as_io_cb writer_cb,
1209 void* writer_opaque,
1210 int to)
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001211{
1212 const Duration dl = (to >= 0) ? looper_now(_async_socket_get_looper(as)) + to :
1213 DURATION_INFINITE;
Vladimir Chtchetkine6dc5c2c2012-04-02 07:48:19 -07001214 async_socket_write_abs(as, buffer, len, writer_cb, writer_opaque, dl);
1215}
1216
1217void*
1218async_socket_get_client_opaque(const AsyncSocket* as)
1219{
1220 return as->client_opaque;
1221}
1222
1223Duration
1224async_socket_deadline(AsyncSocket* as, int rel)
1225{
1226 return (rel >= 0) ? looper_now(_async_socket_get_looper(as)) + rel :
1227 DURATION_INFINITE;
Vladimir Chtchetkinea7383ef2012-03-29 07:34:07 -07001228}
Vladimir Chtchetkineef4ccd32012-04-03 10:27:12 -07001229
1230int
1231async_socket_get_port(const AsyncSocket* as)
1232{
1233 return sock_address_get_port(&as->address);
1234}