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
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
646