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