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