1 /* 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
33 typedef struct {
34 int start;
35 int end;
36 void* pending[ SYS_MAX_QUEUE ];
37 }
38 SysQueueRec, *SysQueue;
39
40 static void
sys_queue_reset(SysQueue queue)41 sys_queue_reset( SysQueue queue )
42 {
43 queue->start = queue->end = 0;
44 }
45
46 static void
sys_queue_add(SysQueue queue,void * item)47 sys_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
56 static void
57 sys_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
74 static void*
sys_queue_get(SysQueue queue)75 sys_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 **/
85 typedef 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
102 static SysChannelRec _s_channels0[ SYS_MAX_CHANNELS ];
103 static SysChannel _s_free_channels;
104
105 static SysChannel
sys_channel_alloc(void)106 sys_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
119 static void
sys_channel_free(SysChannel channel)120 sys_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 */
141 static SysChannel _s_channels;
142
143 /* used by select to wait on channel events */
144 static fd_set _s_fdsets[SYS_EVENT_MAX];
145 static int _s_maxfd;
146
147 static void
sys_channel_deactivate(SysChannel channel)148 sys_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
164 static void
sys_channel_activate(SysChannel channel)165 sys_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 */
177 static SysQueueRec _s_pending_channels[1];
178
179
180 static void
sys_init_channels(void)181 sys_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
198 void
sys_channel_on(SysChannel channel,int events,SysChannelCallback callback,void * opaque)199 sys_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
232 int
sys_channel_read(SysChannel channel,void * buffer,int size)233 sys_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
257 int
sys_channel_write(SysChannel channel,const void * buffer,int size)258 sys_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
282 void
sys_channel_close(SysChannel channel)283 sys_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 **/
sys_time_ms(void)305 SysTime 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 **/
314 typedef 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
324 static SysTimerRec _s_timers0[ SYS_MAX_TIMERS ];
325 static SysTimer _s_free_timers;
326 static SysTimer _s_timers;
327
328 static SysQueueRec _s_pending_timers[1];
329
330
331 static void
sys_init_timers(void)332 sys_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
sys_timer_create(void)344 SysTimer 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
sys_timer_unset(SysTimer timer)354 void 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
sys_timer_set(SysTimer timer,SysTime when,SysCallback callback,void * opaque)376 void 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
sys_timer_destroy(SysTimer timer)409 void 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
420 static void
sys_single_loop(void)421 sys_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
sys_main_init(void)501 void sys_main_init( void )
502 {
503 sys_init_channels();
504 sys_init_timers();
505 }
506
507
sys_main_loop(void)508 int 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
543 SysChannel
sys_channel_create_tcp_server(int port)544 sys_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
588 SysChannel
sys_channel_create_tcp_handler(SysChannel server_channel)589 sys_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
608 SysChannel
sys_channel_create_tcp_client(const char * hostname,int port)609 sys_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
646