blob: 8c5eb12315a36dfa01b6100467c1f773bbb89f08 [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10** GNU General Public License for more details.
11*/
12#include "sysdeps.h"
13#include <assert.h>
14#include <unistd.h>
15#include <sys/select.h>
16#include <errno.h>
17#include <memory.h>
18#include <stdio.h>
19#ifndef HAVE_WINSOCK
20#include <fcntl.h>
21#include <sys/socket.h>
22#include <sys/select.h>
23#include <sys/types.h>
24#include <netinet/in.h>
25#include <netinet/tcp.h>
26#include <netdb.h>
27#endif
28
29/** QUEUE
30 **/
31#define SYS_MAX_QUEUE 16
32
33typedef struct {
34 int start;
35 int end;
36 void* pending[ SYS_MAX_QUEUE ];
37}
38SysQueueRec, *SysQueue;
39
40static void
41sys_queue_reset( SysQueue queue )
42{
43 queue->start = queue->end = 0;
44}
45
46static void
47sys_queue_add( SysQueue queue, void* item )
48{
49 assert( queue->end - queue->start < SYS_MAX_QUEUE );
50 assert( queue->start == 0 );
51 assert( item != NULL );
52 queue->pending[ queue->end++ ] = item;
53}
54
55#if 0
56static void
57sys_queue_remove( SysQueue queue, void* item )
58{
59 int nn, count;
60 assert( queue->end > queue->start );
61 assert( item != NULL );
62 count = queue->end - queue->start;
63 for ( nn = queue->start; count > 0; ++nn, --count ) {
64 if ( queue->pending[nn] == item ) {
65 queue->pending[nn] = queue->pending[nn+count-1];
66 queue->end -= 1;
67 break;
68 }
69 }
70 assert( 0 && "sys_queue_remove: item not found" );
71}
72#endif
73
74static void*
75sys_queue_get( SysQueue queue )
76{
77 if (queue->end > queue->start) {
78 return queue->pending[ queue->start++ ];
79 }
80 return NULL;
81}
82
83/** CHANNELS
84 **/
85typedef struct SysChannelRec_ {
86 SysChannel next;
87 int fd;
88 char active;
89 char pending;
90 char closed;
91 int wanted;
92 int ready;
93 SysChannelCallback callback;
94 void* opaque;
95} SysChannelRec;
96
97
98/*** channel allocation ***/
99#define SYS_EVENT_MAX 3
100#define SYS_MAX_CHANNELS 16
101
102static SysChannelRec _s_channels0[ SYS_MAX_CHANNELS ];
103static SysChannel _s_free_channels;
104
105static SysChannel
106sys_channel_alloc( void )
107{
108 SysChannel channel = _s_free_channels;
109 assert( channel != NULL && "out of free channels" );
110 _s_free_channels = channel->next;
111 channel->next = NULL;
112 channel->active = 0;
113 channel->closed = 0;
114 channel->pending = 0;
115 channel->wanted = 0;
116 return channel;
117}
118
119static void
120sys_channel_free( SysChannel channel )
121{
122 if (channel->fd >= 0) {
123#ifdef _WIN32
124 shutdown( channel->fd, SD_BOTH );
125#else
126 shutdown( channel->fd, SHUT_RDWR );
127#endif
128 close(channel->fd);
129 channel->fd = -1;
130 }
131 channel->wanted = 0;
132 channel->ready = 0;
133 channel->callback = NULL;
134
135 channel->next = _s_free_channels;
136 _s_free_channels = channel;
137}
138
139
140/* list of active channels */
141static SysChannel _s_channels;
142
143/* used by select to wait on channel events */
144static fd_set _s_fdsets[SYS_EVENT_MAX];
145static int _s_maxfd;
146
147static void
148sys_channel_deactivate( SysChannel channel )
149{
150 assert( channel->active != 0 );
151 SysChannel *pnode = &_s_channels;
152 for (;;) {
153 SysChannel node = *pnode;
154 assert( node != NULL );
155 if (node == channel)
156 break;
157 pnode = &node->next;
158 }
159 *pnode = channel->next;
160 channel->next = NULL;
161 channel->active = 0;
162}
163
164static void
165sys_channel_activate( SysChannel channel )
166{
167 assert( channel->active == 0 );
168 channel->next = _s_channels;
169 _s_channels = channel;
170 channel->active = 1;
171 if (channel->fd > _s_maxfd)
172 _s_maxfd = channel->fd;
173}
174
175
176/* queue of pending channels */
177static SysQueueRec _s_pending_channels[1];
178
179
180static void
181sys_init_channels( void )
182{
183 int nn;
184
185 for (nn = 0; nn < SYS_MAX_CHANNELS-1; nn++)
186 _s_channels0[nn].next = &_s_channels0[nn+1];
187 _s_free_channels = &_s_channels0[0];
188
189 for (nn = 0; nn < SYS_EVENT_MAX; nn++)
190 FD_ZERO( &_s_fdsets[nn] );
191
192 _s_maxfd = -1;
193
194 sys_queue_reset( _s_pending_channels );
195}
196
197
198void
199sys_channel_on( SysChannel channel,
200 int events,
201 SysChannelCallback callback,
202 void* opaque )
203{
204 int adds = events & ~channel->wanted;
205 int removes = channel->wanted & ~events;
206
207 channel->wanted = events;
208 channel->callback = callback;
209 channel->opaque = opaque;
210
211 /* update global fdsets */
212 if (adds) {
213 int ee;
214 for (ee = 0; ee < SYS_EVENT_MAX; ee++)
215 if (adds & (1 << ee))
216 FD_SET( channel->fd, &_s_fdsets[ee] );
217 }
218 if (removes) {
219 int ee;
220 for (ee = 0; ee < SYS_EVENT_MAX; ee++)
221 if (removes & (1 << ee))
222 FD_CLR( channel->fd, &_s_fdsets[ee] );
223 }
224 if (events && !channel->active) {
225 sys_channel_activate( channel );
226 }
227 else if (!events && channel->active) {
228 sys_channel_deactivate( channel );
229 }
230}
231
232int
233sys_channel_read( SysChannel channel, void* buffer, int size )
234{
235 char* buff = buffer;
236 int count = 0;
237
238 assert( !channel->closed );
239
240 while (size > 0) {
241 int len = read(channel->fd, buff, size);
242 if (len < 0) {
243 if (errno == EINTR)
244 continue;
245 if (count == 0)
246 count = -1;
247 break;
248 }
249 buff += len;
250 size -= len;
251 count += len;
252 }
253 return count;
254}
255
256
257int
258sys_channel_write( SysChannel channel, const void* buffer, int size )
259{
260 const char* buff = buffer;
261 int count = 0;
262
263 assert( !channel->closed );
264
265 while (size > 0) {
266 int len = write(channel->fd, buff, size);
267 if (len < 0) {
268 if (errno == EINTR)
269 continue;
270 if (count == 0)
271 count = -1;
272 break;
273 }
274 buff += len;
275 size -= len;
276 count += len;
277 }
278 return count;
279}
280
281
282void
283sys_channel_close( SysChannel channel )
284{
285 if (channel->active) {
286 sys_channel_on( channel, 0, NULL, NULL );
287 }
288
289 if (channel->pending) {
290 /* we can't free the channel right now because it */
291 /* is in the pending list, set a flag */
292 channel->closed = 1;
293 return;
294 }
295
296 if (!channel->closed) {
297 channel->closed = 1;
298 }
299
300 sys_channel_free( channel );
301}
302
303/** time measurement
304 **/
305SysTime sys_time_ms( void )
306{
307 struct timeval tv;
308 gettimeofday( &tv, NULL );
309 return (SysTime)(tv.tv_usec / 1000) + (SysTime)tv.tv_sec * 1000;
310}
311
312/** timers
313 **/
314typedef struct SysTimerRec_
315{
316 SysTimer next;
317 SysTime when;
318 SysCallback callback;
319 void* opaque;
320} SysTimerRec;
321
322#define SYS_MAX_TIMERS 16
323
324static SysTimerRec _s_timers0[ SYS_MAX_TIMERS ];
325static SysTimer _s_free_timers;
326static SysTimer _s_timers;
327
328static SysQueueRec _s_pending_timers[1];
329
330
331static void
332sys_init_timers( void )
333{
334 int nn;
335 for (nn = 0; nn < SYS_MAX_TIMERS-1; nn++) {
336 _s_timers0[nn].next = & _s_timers0[nn+1];
337 }
338 _s_free_timers = &_s_timers0[0];
339
340 sys_queue_reset( _s_pending_timers );
341}
342
343
344SysTimer sys_timer_create( void )
345{
346 SysTimer timer = _s_free_timers;
347 assert( timer != NULL && "too many timers allocated" );
348 _s_free_timers = timer->next;
349 timer->next = NULL;
350 return timer;
351}
352
353
354void sys_timer_unset( SysTimer timer )
355{
356 if (timer->callback != NULL) {
357 SysTimer *pnode, node;
358 pnode = &_s_timers;
359 for (;;) {
360 node = *pnode;
361 if (node == NULL)
362 break;
363 if (node == timer) {
364 *pnode = node->next;
365 break;
366 }
367 pnode = &node->next;
368 }
369 timer->next = NULL;
370 timer->callback = NULL;
371 timer->opaque = NULL;
372 }
373}
374
375
376void sys_timer_set( SysTimer timer,
377 SysTime when,
378 SysCallback callback,
379 void* opaque )
380{
381 if (timer->callback != NULL)
382 sys_timer_unset(timer);
383
384 if (callback != NULL) {
385 SysTime now = sys_time_ms();
386
387 if (now >= when) {
388 callback( opaque );
389 } else {
390 SysTimer *pnode, node;
391 pnode = &_s_timers;
392 for (;;) {
393 node = *pnode;
394 if (node == NULL || node->when >= when) {
395 break;
396 }
397 pnode = &node->next;
398 }
399 timer->next = *pnode;
400 *pnode = timer;
401 timer->when = when;
402 timer->callback = callback;
403 timer->opaque = opaque;
404 }
405 }
406}
407
408
409void sys_timer_destroy( SysTimer timer )
410{
411 assert( timer != NULL && "sys_timer_destroy: bad argument" );
412 if (timer->callback != NULL)
413 sys_timer_unset(timer);
414
415 timer->next = _s_free_timers;
416 _s_free_timers = timer;
417}
418
419
420static void
421sys_single_loop( void )
422{
423 fd_set rfd, wfd, efd;
424 struct timeval timeout_tv, *timeout = NULL;
425 int n;
426
427 memcpy(&rfd, &_s_fdsets[0], sizeof(fd_set));
428 memcpy(&wfd, &_s_fdsets[1], sizeof(fd_set));
429 memcpy(&efd, &_s_fdsets[2], sizeof(fd_set));
430
431 if ( _s_timers != NULL ) {
432 SysTime now = sys_time_ms();
433 SysTimer first = _s_timers;
434
435 timeout = &timeout_tv;
436 if (first->when <= now) {
437 timeout->tv_sec = 0;
438 timeout->tv_usec = 0;
439 } else {
440 SysTime diff = first->when - now;
441 timeout->tv_sec = diff / 1000;
442 timeout->tv_usec = (diff - timeout->tv_sec*1000) * 1000;
443 }
444 }
445
446 n = select( _s_maxfd+1, &rfd, &wfd, &efd, timeout);
447 if(n < 0) {
448 if(errno == EINTR) return;
449 perror("select");
450 return;
451 }
452
453 /* enqueue pending channels */
454 {
455 int i;
456
457 sys_queue_reset( _s_pending_channels );
458 for(i = 0; (i <= _s_maxfd) && (n > 0); i++)
459 {
460 int events = 0;
461
462 if(FD_ISSET(i, &rfd)) events |= SYS_EVENT_READ;
463 if(FD_ISSET(i, &wfd)) events |= SYS_EVENT_WRITE;
464 if(FD_ISSET(i, &efd)) events |= SYS_EVENT_ERROR;
465
466 if (events) {
467 SysChannel channel;
468
469 n--;
470 for (channel = _s_channels; channel; channel = channel->next)
471 {
472 if (channel->fd != i)
473 continue;
474
475 channel->ready = events;
476 channel->pending = 1;
477 sys_queue_add( _s_pending_channels, channel );
478 break;
479 }
480 }
481 }
482 }
483
484 /* enqueue pending timers */
485 {
486 SysTimer timer = _s_timers;
487 SysTime now = sys_time_ms();
488
489 sys_queue_reset( _s_pending_timers );
490 while (timer != NULL)
491 {
492 if (timer->when > now)
493 break;
494
495 sys_queue_add( _s_pending_timers, timer );
496 _s_timers = timer = timer->next;
497 }
498 }
499}
500
501void sys_main_init( void )
502{
503 sys_init_channels();
504 sys_init_timers();
505}
506
507
508int sys_main_loop( void )
509{
510 for (;;) {
511 SysTimer timer;
512 SysChannel channel;
513
514 /* exit if we have nothing to do */
515 if (_s_channels == NULL && _s_timers == NULL)
516 break;
517
518 sys_single_loop();
519
520 while ((timer = sys_queue_get( _s_pending_timers )) != NULL) {
521 timer->callback( timer->opaque );
522 }
523
524 while ((channel = sys_queue_get( _s_pending_channels )) != NULL) {
525 int events;
526
527 channel->pending = 0;
528 if (channel->closed) {
529 /* the channel was closed by a previous callback */
530 sys_channel_close(channel);
531 }
532 events = channel->ready;
533 channel->ready = 0;
534 channel->callback( channel->opaque, events );
535 }
536 }
537 return 0;
538}
539
540
541
542
543SysChannel
544sys_channel_create_tcp_server( int port )
545{
546 SysChannel channel;
547 int on = 1;
548 const int BACKLOG = 4;
549
550 channel = sys_channel_alloc();
551 if (-1==(channel->fd=socket(AF_INET, SOCK_STREAM, 0))) {
552 perror("socket");
553 sys_channel_free( channel );
554 return NULL;
555 }
556
557 /* Enable address re-use for server mode */
558 if ( -1==setsockopt( channel->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) )) {
559 perror("setsockopt(SO_REUSEADDR)");
560 }
561
562 {
563 struct sockaddr_in servname;
564 long in_addr = INADDR_ANY;
565
566 servname.sin_family = AF_INET;
567 servname.sin_port = htons(port);
568
569 servname.sin_addr.s_addr=in_addr;
570
571 if (-1==bind(channel->fd, (struct sockaddr*)&servname, sizeof(servname))) {
572 perror("bind");
573 sys_channel_close(channel);
574 return NULL;
575 }
576
577 /* Listen but don't accept */
578 if ( listen(channel->fd, BACKLOG) < 0 ) {
579 perror("listen");
580 sys_channel_close(channel);
581 return NULL;
582 }
583 }
584 return channel;
585}
586
587
588SysChannel
589sys_channel_create_tcp_handler( SysChannel server_channel )
590{
591 int on = 1;
592 SysChannel channel = sys_channel_alloc();
593
594 channel->fd = accept( server_channel->fd, NULL, 0 );
595 if (channel->fd < 0) {
596 perror( "accept" );
597 sys_channel_free( channel );
598 return NULL;
599 }
600
601 /* set to non-blocking and disable TCP Nagle algorithm */
602 fcntl(channel->fd, F_SETFL, O_NONBLOCK);
603 setsockopt(channel->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
604 return channel;
605}
606
607
608SysChannel
609sys_channel_create_tcp_client( const char* hostname, int port )
610{
611 struct hostent* hp;
612 struct sockaddr_in addr;
613 SysChannel channel = sys_channel_alloc();
614 int on = 1;
615
616 hp = gethostbyname(hostname);
617 if(hp == 0) {
618 fprintf(stderr, "unknown host: %s\n", hostname);
619 sys_channel_free(channel);
620 return NULL;
621 };
622
623 memset(&addr, 0, sizeof(addr));
624 addr.sin_family = hp->h_addrtype;
625 addr.sin_port = htons(port);
626 memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
627
628 channel->fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
629 if(channel->fd < 0) {
630 sys_channel_free(channel);
631 return NULL;
632 }
633
634 if(connect( channel->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
635 perror( "connect" );
636 sys_channel_free(channel);
637 return NULL;
638 }
639
640 /* set to non-blocking and disable Nagle algorithm */
641 fcntl(channel->fd, F_SETFL, O_NONBLOCK);
642 setsockopt( channel->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on) );
643 return channel;
644}
645