683 lines
17 KiB
C
683 lines
17 KiB
C
/*
|
|
* addr_server.c -- socket-based ip address server.
|
|
* 8-92 : Dwayne Fontenot : original coding
|
|
*/
|
|
|
|
#include "std.h"
|
|
#include "addr_server.h"
|
|
#include "socket_ctrl.h"
|
|
#include "file_incl.h"
|
|
#include "port.h"
|
|
|
|
#ifdef MINGW
|
|
#include <ws2tcpip.h>
|
|
#endif
|
|
|
|
#ifdef DEBUG_MACRO
|
|
int debug_level = DBG_addr_server;
|
|
#endif /* DEBUG_MACRO */
|
|
|
|
#define DBG(x) debug(addr_server, x)
|
|
|
|
/*
|
|
* private local variables.
|
|
*/
|
|
static connection all_conns[MAX_CONNS];
|
|
static int total_conns = 0;
|
|
static queue_element_ptr queue_head = NULL;
|
|
static queue_element_ptr queue_tail = NULL;
|
|
static queue_element_ptr stack_head = NULL;
|
|
static int queue_length = 0;
|
|
static int conn_fd;
|
|
|
|
fd_set readmask;
|
|
|
|
int name_by_ip (int, char *);
|
|
int ip_by_name (int, char *);
|
|
INLINE_STATIC void process_queue (void);
|
|
void init_conns (void);
|
|
void init_conn_sock (int, char *);
|
|
|
|
#ifdef SIGNAL_FUNC_TAKES_INT
|
|
void sigpipe_handler (int);
|
|
#else
|
|
void sigpipe_handler (void);
|
|
#endif
|
|
|
|
INLINE void aserv_process_io (int);
|
|
void enqueue_datapending (int, int);
|
|
void handle_top_event (void);
|
|
void dequeue_top_event (void);
|
|
void pop_queue_element (queue_element_ptr *);
|
|
void push_queue_element (queue_element_ptr);
|
|
void new_conn_handler (void);
|
|
void conn_data_handler (int);
|
|
int index_by_fd (int);
|
|
void terminate (int);
|
|
|
|
void debug_perror (const char *, const char *);
|
|
|
|
void debug_perror (const char * what, const char * file) {
|
|
if (file)
|
|
fprintf(stderr, "System Error: %s:%s:%s\n", what, file, port_strerror(errno));
|
|
else
|
|
fprintf(stderr, "System Error: %s:%s\n", what, port_strerror(errno));
|
|
}
|
|
|
|
void init_conns()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_CONNS; i++) {
|
|
all_conns[i].fd = -1;
|
|
all_conns[i].state = CONN_CLOSED;
|
|
all_conns[i].sname[0] = '\0';
|
|
|
|
/* ensure 'leftover' buffer is _always_ null terminated */
|
|
all_conns[i].buf[0] = '\0';
|
|
all_conns[i].buf[IN_BUF_SIZE - 1] = '\0';
|
|
all_conns[i].leftover = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initialize connection socket.
|
|
*/
|
|
void init_conn_sock (int port_num, char * ipaddress)
|
|
{
|
|
#ifdef IPV6
|
|
struct sockaddr_in6 sin;
|
|
#else
|
|
struct sockaddr_in sin;
|
|
#endif
|
|
socklen_t sin_len;
|
|
int optval;
|
|
#ifdef WINSOCK
|
|
WSADATA WSAData;
|
|
|
|
WSAStartup(MAKEWORD(1,1), &WSAData);
|
|
atexit(cleanup_sockets);
|
|
#endif
|
|
|
|
/*
|
|
* create socket of proper type.
|
|
*/
|
|
#ifdef IPV6
|
|
if ((conn_fd = socket(AF_INET6, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
|
#else
|
|
if ((conn_fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
|
#endif
|
|
socket_perror("init_conn_sock: socket", 0);
|
|
exit(1);
|
|
}
|
|
/*
|
|
* enable local address reuse.
|
|
*/
|
|
optval = 1;
|
|
if (setsockopt(conn_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optval,
|
|
sizeof(optval)) == -1) {
|
|
socket_perror("init_conn_sock: setsockopt", 0);
|
|
exit(2);
|
|
}
|
|
/*
|
|
* fill in socket address information.
|
|
*/
|
|
#ifdef IPV6
|
|
sin.sin6_family = AF_INET6;
|
|
if(ipaddress)
|
|
inet_pton(AF_INET6, ipaddress, &(sin.sin6_addr));
|
|
else
|
|
sin.sin6_addr = in6addr_any;
|
|
sin.sin6_port = htons((u_short) port_num);
|
|
#else
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_addr.s_addr = (ipaddress ? inet_addr(ipaddress) : INADDR_ANY);
|
|
sin.sin_port = htons((u_short) port_num);
|
|
#endif
|
|
/*
|
|
* bind name to socket.
|
|
*/
|
|
if (bind(conn_fd, (struct sockaddr *) & sin, sizeof(sin)) == -1) {
|
|
socket_perror("init_conn_sock: bind", 0);
|
|
exit(3);
|
|
}
|
|
/*
|
|
* get socket name.
|
|
*/
|
|
sin_len = sizeof(sin);
|
|
if (getsockname(conn_fd, (struct sockaddr *) & sin, &sin_len) == -1) {
|
|
socket_perror("init_conn_sock: getsockname", 0);
|
|
exit(4);
|
|
}
|
|
/*
|
|
* register signal handler for SIGPIPE.
|
|
*/
|
|
#if defined(SIGPIPE) && defined(SIGNAL_ERROR)/* windows has no SIGPIPE */
|
|
if (signal(SIGPIPE, sigpipe_handler) == SIGNAL_ERROR) {
|
|
socket_perror("init_conn_sock: signal SIGPIPE", 0);
|
|
exit(5);
|
|
}
|
|
#endif
|
|
/*
|
|
* set socket non-blocking
|
|
*/
|
|
if (set_socket_nonblocking(conn_fd, 1) == -1) {
|
|
socket_perror("init_conn_sock: set_socket_nonblocking 1", 0);
|
|
exit(8);
|
|
}
|
|
/*
|
|
* listen on socket for connections.
|
|
*/
|
|
if (listen(conn_fd, 128) == -1) {
|
|
socket_perror("init_conn_sock: listen", 0);
|
|
exit(10);
|
|
}
|
|
DBG(("listening for connections on port %d", port_num));
|
|
}
|
|
|
|
/*
|
|
* SIGPIPE handler -- does very little for now.
|
|
*/
|
|
#ifdef SIGNAL_FUNC_TAKES_INT
|
|
void sigpipe_handler (int sig)
|
|
{
|
|
#else
|
|
void sigpipe_handler()
|
|
{
|
|
#endif
|
|
fprintf(stderr, "SIGPIPE received.\n");
|
|
}
|
|
|
|
/*
|
|
* I/O handler.
|
|
*/
|
|
INLINE void aserv_process_io (int nb)
|
|
{
|
|
int i;
|
|
|
|
switch (nb) {
|
|
case -1:
|
|
debug_perror("sigio_handler: select", 0);
|
|
break;
|
|
case 0:
|
|
break;
|
|
default:
|
|
/*
|
|
* check for new connection.
|
|
*/
|
|
if (FD_ISSET(conn_fd, &readmask)) {
|
|
DBG(("sigio_handler: NEW_CONN"));
|
|
enqueue_datapending(conn_fd, NEW_CONN);
|
|
}
|
|
/*
|
|
* check for data pending on established connections.
|
|
*/
|
|
for (i = 0; i < MAX_CONNS; i++) {
|
|
if (FD_ISSET(all_conns[i].fd, &readmask)) {
|
|
DBG(("sigio_handler: CONN"));
|
|
enqueue_datapending(all_conns[i].fd, CONN);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
INLINE_STATIC void process_queue()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; queue_head && (i < MAX_EVENTS_TO_PROCESS); i++) {
|
|
handle_top_event();
|
|
dequeue_top_event();
|
|
}
|
|
}
|
|
|
|
void enqueue_datapending (int fd, int fd_type)
|
|
{
|
|
queue_element_ptr new_queue_element;
|
|
|
|
pop_queue_element(&new_queue_element);
|
|
new_queue_element->event_type = fd_type;
|
|
new_queue_element->fd = fd;
|
|
new_queue_element->next = NULL;
|
|
if (queue_head) {
|
|
queue_tail->next = new_queue_element;
|
|
} else {
|
|
queue_head = new_queue_element;
|
|
}
|
|
queue_tail = new_queue_element;
|
|
}
|
|
|
|
void dequeue_top_event()
|
|
{
|
|
queue_element_ptr top_queue_element;
|
|
|
|
if (queue_head) {
|
|
top_queue_element = queue_head;
|
|
queue_head = queue_head->next;
|
|
push_queue_element(top_queue_element);
|
|
} else {
|
|
fprintf(stderr, "dequeue_top_event: tried to dequeue from empty queue!\n");
|
|
}
|
|
}
|
|
|
|
void pop_queue_element (queue_element_ptr * the_queue_element)
|
|
{
|
|
if ((*the_queue_element = stack_head))
|
|
stack_head = stack_head->next;
|
|
else
|
|
*the_queue_element = (queue_element_ptr) malloc(sizeof(queue_element));
|
|
queue_length++;
|
|
}
|
|
|
|
void push_queue_element (queue_element_ptr the_queue_element)
|
|
{
|
|
the_queue_element->next = stack_head;
|
|
stack_head = the_queue_element;
|
|
queue_length--;
|
|
}
|
|
|
|
void handle_top_event()
|
|
{
|
|
switch (queue_head->event_type) {
|
|
case NEW_CONN:
|
|
DBG(("handle_top_event: NEW_CONN"));
|
|
new_conn_handler();
|
|
break;
|
|
case CONN:
|
|
DBG(("handle_top_event: CONN data on fd %d", queue_head->fd));
|
|
conn_data_handler(queue_head->fd);
|
|
break;
|
|
default:
|
|
fprintf(stderr, "handle_top_event: unknown event type %d\n",
|
|
queue_head->event_type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This is the new connection handler. This function is called by the
|
|
* event handler when data is pending on the listening socket (conn_fd).
|
|
* If space is available, an interactive data structure is initialized and
|
|
* the connected is established.
|
|
*/
|
|
void new_conn_handler()
|
|
{
|
|
|
|
#ifdef IPV6
|
|
struct sockaddr_in6 client;
|
|
#else
|
|
struct sockaddr_in client;
|
|
#endif
|
|
socklen_t client_len;
|
|
struct hostent *c_hostent;
|
|
int new_fd;
|
|
int conn_index;
|
|
|
|
client_len = sizeof(client);
|
|
new_fd = accept(conn_fd, (struct sockaddr *) & client, &client_len);
|
|
if (new_fd == -1) {
|
|
socket_perror("new_conn_handler: accept", 0);
|
|
return;
|
|
}
|
|
if (set_socket_nonblocking(new_fd, 1) == -1) {
|
|
socket_perror("new_conn_handler: set_socket_nonblocking 1", 0);
|
|
OS_socket_close(new_fd);
|
|
return;
|
|
}
|
|
if (total_conns >= MAX_CONNS) {
|
|
char *message = "no available slots -- closing connection.\n";
|
|
|
|
fprintf(stderr, "new_conn_handler: no available connection slots.\n");
|
|
OS_socket_write(new_fd, message, strlen(message));
|
|
if (OS_socket_close(new_fd) == -1)
|
|
socket_perror("new_conn_handler: close", 0);
|
|
return;
|
|
}
|
|
/* get some information about new connection */
|
|
for (conn_index = 0; conn_index < MAX_CONNS; conn_index++) {
|
|
if (all_conns[conn_index].state == CONN_CLOSED) {
|
|
DBG(("new_conn_handler: opening conn index %d", conn_index));
|
|
/* update global data for new fd */
|
|
all_conns[conn_index].fd = new_fd;
|
|
all_conns[conn_index].state = CONN_OPEN;
|
|
all_conns[conn_index].addr = client;
|
|
|
|
char portname[256];
|
|
if(getnameinfo((struct sockaddr *)&client, sizeof(client), all_conns[conn_index].sname, SNAME_LEN, portname, 255, NI_NAMEREQD|NI_NUMERICHOST))
|
|
strcpy(all_conns[conn_index].sname, "<unknown>");
|
|
total_conns++;
|
|
return;
|
|
}
|
|
}
|
|
fprintf(stderr, "new_conn_handler: sanity check failed!\n");
|
|
}
|
|
|
|
void conn_data_handler (int fd)
|
|
{
|
|
int conn_index;
|
|
int buf_index;
|
|
int num_bytes;
|
|
int msgtype;
|
|
int leftover;
|
|
char *buf;
|
|
int res, msglen, expecting;
|
|
long unread_bytes;
|
|
|
|
if ((conn_index = index_by_fd(fd)) == -1) {
|
|
fprintf(stderr, "conn_data_handler: invalid fd.\n");
|
|
return;
|
|
}
|
|
DBG(("conn_data_handler: read on fd %d", fd));
|
|
|
|
/* append new data to end of leftover data (if any) */
|
|
leftover = all_conns[conn_index].leftover;
|
|
buf = (char *) &all_conns[conn_index].buf[0];
|
|
num_bytes = OS_socket_read(fd, buf + leftover, (IN_BUF_SIZE - 1) - leftover);
|
|
|
|
switch (num_bytes) {
|
|
case -1:
|
|
switch (socket_errno) {
|
|
case EWOULDBLOCK:
|
|
DBG(("conn_data_handler: read on fd %d: Operation would block.",
|
|
fd));
|
|
break;
|
|
default:
|
|
socket_perror("conn_data_handler: read", 0);
|
|
terminate(conn_index);
|
|
break;
|
|
}
|
|
break;
|
|
case 0:
|
|
if (all_conns[conn_index].state == CONN_CLOSED)
|
|
fprintf(stderr, "get_user_data: tried to read from closed fd.\n");
|
|
terminate(conn_index);
|
|
break;
|
|
default:
|
|
DBG(("conn_data_handler: read %d bytes on fd %d", num_bytes, fd));
|
|
num_bytes += leftover;
|
|
buf_index = 0;
|
|
expecting = 0;
|
|
while (num_bytes > sizeof(int) && buf_index < (IN_BUF_SIZE - 1)) {
|
|
/* get message type */
|
|
memcpy((char *) &msgtype, (char *) &buf[buf_index], sizeof(int));
|
|
DBG(("conn_data_handler: message type: %d", msgtype));
|
|
|
|
if (msgtype == NAMEBYIP) {
|
|
if (buf[buf_index + sizeof(int)] == '\0') {
|
|
/* no data here...resync */
|
|
buf_index++;
|
|
num_bytes--;
|
|
continue;
|
|
}
|
|
if (expecting && num_bytes < expecting) {
|
|
/*
|
|
* message truncated...back up to DATALEN message; exit
|
|
* loop...and try again later
|
|
*/
|
|
buf_index -= (sizeof(int) + sizeof(int));
|
|
num_bytes += (sizeof(int) + sizeof(int));
|
|
break;
|
|
}
|
|
res = name_by_ip(conn_index, &buf[buf_index]);
|
|
} else if (msgtype == IPBYNAME) {
|
|
if (buf[buf_index + sizeof(int)] == '\0') {
|
|
/* no data here...resync */
|
|
buf_index++;
|
|
num_bytes--;
|
|
continue;
|
|
}
|
|
if (expecting && num_bytes < expecting) {
|
|
/*
|
|
* message truncated...back up to DATALEN message; exit
|
|
* loop...and try again later
|
|
*/
|
|
buf_index -= (sizeof(int) + sizeof(int));
|
|
num_bytes += (sizeof(int) + sizeof(int));
|
|
break;
|
|
}
|
|
res = ip_by_name(conn_index, &buf[buf_index]);
|
|
} else if (msgtype == DATALEN) {
|
|
if (num_bytes > (sizeof(int) + sizeof(int))) {
|
|
memcpy((char *) &expecting, (char *) &buf[buf_index + sizeof(int)], sizeof(int));
|
|
/*
|
|
* advance to next message
|
|
*/
|
|
buf_index += (sizeof(int) + sizeof(int));
|
|
num_bytes -= (sizeof(int) + sizeof(int));
|
|
if (expecting > IN_BUF_SIZE || expecting <= 0) {
|
|
fprintf(stderr, "conn_data_handler: bad data length %d\n", expecting);
|
|
expecting = 0;
|
|
}
|
|
continue;
|
|
} else {
|
|
/*
|
|
* not enough bytes...assume truncated; exit loop...we'll
|
|
* handle this message later
|
|
*/
|
|
break;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "conn_data_handler: unknown message type %08x\n", msgtype);
|
|
/* advance through buffer */
|
|
buf_index++;
|
|
num_bytes--;
|
|
continue;
|
|
}
|
|
|
|
msglen = (int) (sizeof(int) + strlen(&buf[buf_index + sizeof(int)]) +1);
|
|
if (res) {
|
|
/*
|
|
* ok...advance to next message
|
|
*/
|
|
buf_index += msglen;
|
|
num_bytes -= msglen;
|
|
} else if (msglen < num_bytes || (expecting && expecting == msglen)) {
|
|
/*
|
|
* failed...
|
|
*/
|
|
|
|
/*
|
|
* this was a complete message...advance to the next one
|
|
*/
|
|
msglen = (int) (sizeof(int) + strlen(&buf[buf_index + sizeof(int)]) +1);
|
|
buf_index += msglen;
|
|
num_bytes -= msglen;
|
|
expecting = 0;
|
|
}
|
|
else if (!OS_socket_ioctl(fd, FIONREAD, &unread_bytes) &&
|
|
unread_bytes > 0) {
|
|
/*
|
|
* msglen == num_bytes could be a complete message... if
|
|
* there's unread data we'll assume it was truncated
|
|
*/
|
|
break;
|
|
} else {
|
|
/*
|
|
* nothing more? then discard message (it was the last one)
|
|
*/
|
|
buf_index = 0;
|
|
num_bytes = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* keep track of leftover buffer contents */
|
|
if (num_bytes && buf_index)
|
|
memmove(buf, &buf[buf_index], num_bytes);
|
|
buf[num_bytes] = '\0';
|
|
all_conns[conn_index].leftover = num_bytes;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define OUT_BUF_SIZE 80
|
|
|
|
int ip_by_name (int conn_index, char * buf)
|
|
{
|
|
struct hostent *hp;
|
|
struct in_addr my_in_addr;
|
|
static char out_buf[OUT_BUF_SIZE];
|
|
|
|
hp = gethostbyname(&buf[sizeof(int)]);
|
|
if (hp == NULL) {
|
|
/* Failed :( */
|
|
sprintf(out_buf, "%s 0\n", &buf[sizeof(int)]);
|
|
DBG(("%s", out_buf));
|
|
OS_socket_write(all_conns[conn_index].fd, out_buf, strlen(out_buf));
|
|
return 0;
|
|
} else {
|
|
/* Success! */
|
|
memcpy(&my_in_addr, hp->h_addr, sizeof(struct in_addr));
|
|
sprintf(out_buf, "%s %s\n", &buf[sizeof(int)],
|
|
inet_ntoa(my_in_addr));
|
|
DBG(("%s", out_buf));
|
|
OS_socket_write(all_conns[conn_index].fd, out_buf, strlen(out_buf));
|
|
return 1;
|
|
}
|
|
} /* ip_by_name() */
|
|
|
|
int name_by_ip (int conn_index, char * buf)
|
|
{
|
|
struct addrinfo hints, *res;
|
|
int ret;
|
|
|
|
hints.ai_family = AF_INET6;
|
|
hints.ai_socktype = 0;
|
|
hints.ai_protocol = 0;
|
|
#if defined(AI_V4MAPPED)
|
|
hints.ai_flags = AI_CANONNAME| AI_V4MAPPED;
|
|
#else
|
|
hints.ai_flags = AI_CANONNAME;
|
|
#endif
|
|
static char out_buf[OUT_BUF_SIZE];
|
|
|
|
if((ret = getaddrinfo(&buf[sizeof(int)], NULL, &hints, &res))){
|
|
//failed
|
|
sprintf(out_buf, "%s 0\n", &buf[sizeof(int)]);
|
|
DBG(("name_by_ip: malformed address request (%d).", ret));
|
|
OS_socket_write(all_conns[conn_index].fd, out_buf, strlen(out_buf));
|
|
return 0;
|
|
}
|
|
char tmpbuf[80], tmpp[80];
|
|
if(ret = getnameinfo(res->ai_addr, res->ai_addrlen, tmpbuf, 79, tmpp, 79, NI_NAMEREQD|NI_NUMERICSERV)){
|
|
sprintf(out_buf, "%s 0\n", &buf[sizeof(int)]);
|
|
DBG(("%s", out_buf));
|
|
OS_socket_write(all_conns[conn_index].fd, out_buf, strlen(out_buf));
|
|
DBG(("name_by_ip: unable to resolve address."));
|
|
freeaddrinfo(res);
|
|
return 0;
|
|
}
|
|
sprintf(out_buf, "%s %s\n", &buf[sizeof(int)], tmpbuf);
|
|
DBG(("%s", out_buf));
|
|
OS_socket_write(all_conns[conn_index].fd, out_buf, strlen(out_buf));
|
|
freeaddrinfo(res);
|
|
return 1;
|
|
}
|
|
|
|
int index_by_fd (int fd)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_CONNS; i++) {
|
|
if ((all_conns[i].state == CONN_OPEN) && (all_conns[i].fd == fd))
|
|
return (i);
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
void terminate (int conn_index)
|
|
{
|
|
if (conn_index < 0 || conn_index >= MAX_CONNS) {
|
|
fprintf(stderr, "terminate: conn_index %d out of range.\n", conn_index);
|
|
return;
|
|
}
|
|
if (all_conns[conn_index].state == CONN_CLOSED) {
|
|
fprintf(stderr, "terminate: connection %d already closed.\n", conn_index);
|
|
return;
|
|
}
|
|
DBG(("terminating connection %d", conn_index));
|
|
|
|
if (OS_socket_close(all_conns[conn_index].fd) == -1) {
|
|
socket_perror("terminate: close", 0);
|
|
return;
|
|
}
|
|
all_conns[conn_index].state = CONN_CLOSED;
|
|
total_conns--;
|
|
}
|
|
|
|
int main (int argc, char ** argv)
|
|
{
|
|
int addr_server_port;
|
|
struct timeval timeout;
|
|
int i;
|
|
int nb;
|
|
char *ipaddress = 0;
|
|
|
|
if (argc > 1) {
|
|
if ((addr_server_port = atoi(argv[1])) == 0) {
|
|
fprintf(stderr, "addr_server: malformed port number.\n");
|
|
exit(2);
|
|
}
|
|
if (argc > 2) {
|
|
if (inet_addr((ipaddress = argv[2])) == INADDR_NONE) {
|
|
fprintf(stderr, "addr_server: malformed ip address.\n");
|
|
exit(3);
|
|
}
|
|
}
|
|
} else {
|
|
fprintf(stderr, "addr_server: first arg must be port number.\n");
|
|
exit(1);
|
|
}
|
|
init_conn_sock(addr_server_port, ipaddress);
|
|
while (1) {
|
|
/*
|
|
* use finite timeout for robustness.
|
|
*/
|
|
timeout.tv_sec = 2;
|
|
timeout.tv_usec = 0;
|
|
/*
|
|
* clear selectmasks.
|
|
*/
|
|
FD_ZERO(&readmask);
|
|
/*
|
|
* set new connection accept fd in readmask.
|
|
*/
|
|
FD_SET(conn_fd, &readmask);
|
|
/*
|
|
* set active fds in readmask.
|
|
*/
|
|
for (i = 0; i < MAX_CONNS; i++) {
|
|
if (all_conns[i].state == CONN_OPEN)
|
|
FD_SET(all_conns[i].fd, &readmask);
|
|
}
|
|
#ifndef hpux
|
|
nb = select(FD_SETSIZE, &readmask, (fd_set *) 0, (fd_set *) 0, &timeout);
|
|
#else
|
|
nb = select(FD_SETSIZE, (int *) &readmask, (int *) 0, (int *) 0, &timeout);
|
|
#endif
|
|
if (nb != 0)
|
|
aserv_process_io(nb);
|
|
process_queue();
|
|
}
|
|
/* the following is to shut lint up */
|
|
/*NOTREACHED*/
|
|
return 0; /* never reached */
|
|
}
|
|
|
|
#ifdef WIN32
|
|
void debug_message(char *fmt, ...)
|
|
{
|
|
static char deb_buf[1024];
|
|
static char *deb = deb_buf;
|
|
va_list args;
|
|
|
|
V_START(args, fmt);
|
|
V_VAR(char *, fmt, args);
|
|
vfprintf(stderr, fmt, args);
|
|
fflush(stderr);
|
|
va_end(args);
|
|
}
|
|
#endif
|