ds3.0/bin/
ds3.0/extra/
ds3.0/extra/crat/
ds3.0/extra/creremote/
ds3.0/extra/mingw/
ds3.0/extra/wolfpaw/
ds3.0/fluffos-2.18-ds07/
ds3.0/fluffos-2.18-ds07/Win32/
ds3.0/fluffos-2.18-ds07/compat/
ds3.0/fluffos-2.18-ds07/compat/simuls/
ds3.0/fluffos-2.18-ds07/testsuite/
ds3.0/fluffos-2.18-ds07/testsuite/clone/
ds3.0/fluffos-2.18-ds07/testsuite/command/
ds3.0/fluffos-2.18-ds07/testsuite/data/
ds3.0/fluffos-2.18-ds07/testsuite/etc/
ds3.0/fluffos-2.18-ds07/testsuite/include/
ds3.0/fluffos-2.18-ds07/testsuite/inherit/
ds3.0/fluffos-2.18-ds07/testsuite/inherit/master/
ds3.0/fluffos-2.18-ds07/testsuite/log/
ds3.0/fluffos-2.18-ds07/testsuite/single/
ds3.0/fluffos-2.18-ds07/testsuite/single/tests/compiler/
ds3.0/fluffos-2.18-ds07/testsuite/single/tests/efuns/
ds3.0/fluffos-2.18-ds07/testsuite/single/tests/operators/
ds3.0/fluffos-2.18-ds07/testsuite/u/
ds3.0/fluffos-2.18-ds07/tmp/
ds3.0/lib/cmds/admins/
ds3.0/lib/cmds/common/
ds3.0/lib/cmds/creators/include/
ds3.0/lib/daemon/services/
ds3.0/lib/daemon/tmp/
ds3.0/lib/doc/
ds3.0/lib/doc/bguide/
ds3.0/lib/doc/efun/all/
ds3.0/lib/doc/efun/arrays/
ds3.0/lib/doc/efun/buffers/
ds3.0/lib/doc/efun/compile/
ds3.0/lib/doc/efun/floats/
ds3.0/lib/doc/efun/functions/
ds3.0/lib/doc/efun/mixed/
ds3.0/lib/doc/efun/numbers/
ds3.0/lib/doc/efun/parsing/
ds3.0/lib/doc/help/classes/
ds3.0/lib/doc/help/races/
ds3.0/lib/doc/lfun/
ds3.0/lib/doc/lfun/all/
ds3.0/lib/doc/lfun/lib/abilities/
ds3.0/lib/doc/lfun/lib/armor/
ds3.0/lib/doc/lfun/lib/bank/
ds3.0/lib/doc/lfun/lib/bot/
ds3.0/lib/doc/lfun/lib/clay/
ds3.0/lib/doc/lfun/lib/clean/
ds3.0/lib/doc/lfun/lib/clerk/
ds3.0/lib/doc/lfun/lib/client/
ds3.0/lib/doc/lfun/lib/combat/
ds3.0/lib/doc/lfun/lib/connect/
ds3.0/lib/doc/lfun/lib/container/
ds3.0/lib/doc/lfun/lib/corpse/
ds3.0/lib/doc/lfun/lib/creator/
ds3.0/lib/doc/lfun/lib/daemon/
ds3.0/lib/doc/lfun/lib/damage/
ds3.0/lib/doc/lfun/lib/deterioration/
ds3.0/lib/doc/lfun/lib/donate/
ds3.0/lib/doc/lfun/lib/door/
ds3.0/lib/doc/lfun/lib/equip/
ds3.0/lib/doc/lfun/lib/file/
ds3.0/lib/doc/lfun/lib/fish/
ds3.0/lib/doc/lfun/lib/fishing/
ds3.0/lib/doc/lfun/lib/flashlight/
ds3.0/lib/doc/lfun/lib/follow/
ds3.0/lib/doc/lfun/lib/ftp_client/
ds3.0/lib/doc/lfun/lib/ftp_data_connection/
ds3.0/lib/doc/lfun/lib/fuel/
ds3.0/lib/doc/lfun/lib/furnace/
ds3.0/lib/doc/lfun/lib/genetics/
ds3.0/lib/doc/lfun/lib/holder/
ds3.0/lib/doc/lfun/lib/id/
ds3.0/lib/doc/lfun/lib/interactive/
ds3.0/lib/doc/lfun/lib/lamp/
ds3.0/lib/doc/lfun/lib/leader/
ds3.0/lib/doc/lfun/lib/light/
ds3.0/lib/doc/lfun/lib/limb/
ds3.0/lib/doc/lfun/lib/living/
ds3.0/lib/doc/lfun/lib/load/
ds3.0/lib/doc/lfun/lib/look/
ds3.0/lib/doc/lfun/lib/manipulate/
ds3.0/lib/doc/lfun/lib/meal/
ds3.0/lib/doc/lfun/lib/messages/
ds3.0/lib/doc/lfun/lib/player/
ds3.0/lib/doc/lfun/lib/poison/
ds3.0/lib/doc/lfun/lib/position/
ds3.0/lib/doc/lfun/lib/post_office/
ds3.0/lib/doc/lfun/lib/potion/
ds3.0/lib/doc/lfun/lib/room/
ds3.0/lib/doc/lfun/lib/server/
ds3.0/lib/doc/lfun/lib/spell/
ds3.0/lib/doc/lfun/lib/torch/
ds3.0/lib/doc/lfun/lib/vendor/
ds3.0/lib/doc/lfun/lib/virt_sky/
ds3.0/lib/doc/lfun/lib/weapon/
ds3.0/lib/doc/lfun/lib/worn_storage/
ds3.0/lib/doc/lpc/constructs/
ds3.0/lib/doc/lpc/etc/
ds3.0/lib/doc/lpc/intermediate/
ds3.0/lib/doc/lpc/types/
ds3.0/lib/doc/misc/
ds3.0/lib/doc/old/
ds3.0/lib/doc/phints/
ds3.0/lib/domains/
ds3.0/lib/domains/Praxis/adm/
ds3.0/lib/domains/Praxis/attic/
ds3.0/lib/domains/Praxis/cemetery/mon/
ds3.0/lib/domains/Praxis/data/
ds3.0/lib/domains/Praxis/death/
ds3.0/lib/domains/Praxis/mountains/
ds3.0/lib/domains/Praxis/obj/armour/
ds3.0/lib/domains/Praxis/obj/magic/
ds3.0/lib/domains/Praxis/obj/weapon/
ds3.0/lib/domains/Praxis/orc_valley/
ds3.0/lib/domains/Ylsrim/
ds3.0/lib/domains/Ylsrim/adm/
ds3.0/lib/domains/Ylsrim/armor/
ds3.0/lib/domains/Ylsrim/broken/
ds3.0/lib/domains/Ylsrim/fish/
ds3.0/lib/domains/Ylsrim/meal/
ds3.0/lib/domains/Ylsrim/npc/
ds3.0/lib/domains/Ylsrim/obj/
ds3.0/lib/domains/Ylsrim/virtual/
ds3.0/lib/domains/Ylsrim/weapon/
ds3.0/lib/domains/campus/adm/
ds3.0/lib/domains/campus/chamber/
ds3.0/lib/domains/campus/etc/
ds3.0/lib/domains/campus/meals/
ds3.0/lib/domains/campus/txt/ai/charles/
ds3.0/lib/domains/campus/txt/ai/charles/bak2/
ds3.0/lib/domains/campus/txt/ai/charles/bak2/bak1/
ds3.0/lib/domains/campus/txt/ai/charly/
ds3.0/lib/domains/campus/txt/ai/charly/bak/
ds3.0/lib/domains/campus/txt/jenny/
ds3.0/lib/domains/cave/doors/
ds3.0/lib/domains/cave/etc/
ds3.0/lib/domains/cave/meals/
ds3.0/lib/domains/cave/weap/
ds3.0/lib/domains/default/chamber/
ds3.0/lib/domains/default/creator/
ds3.0/lib/domains/default/doors/
ds3.0/lib/domains/default/etc/
ds3.0/lib/domains/default/vehicle/
ds3.0/lib/domains/default/virtual/
ds3.0/lib/domains/town/save/
ds3.0/lib/domains/town/txt/shame/
ds3.0/lib/domains/town/virtual/
ds3.0/lib/domains/town/virtual/bottom/
ds3.0/lib/domains/town/virtual/space/
ds3.0/lib/estates/
ds3.0/lib/ftp/
ds3.0/lib/lib/comp/
ds3.0/lib/lib/daemons/
ds3.0/lib/lib/daemons/include/
ds3.0/lib/lib/lvs/
ds3.0/lib/lib/user/
ds3.0/lib/lib/virtual/
ds3.0/lib/log/
ds3.0/lib/log/adm/
ds3.0/lib/log/archive/
ds3.0/lib/log/chan/
ds3.0/lib/log/errors/
ds3.0/lib/log/law/adm/
ds3.0/lib/log/law/email/
ds3.0/lib/log/law/names/
ds3.0/lib/log/law/sites-misc/
ds3.0/lib/log/law/sites-register/
ds3.0/lib/log/law/sites-tempban/
ds3.0/lib/log/law/sites-watch/
ds3.0/lib/log/open/
ds3.0/lib/log/reports/
ds3.0/lib/log/router/
ds3.0/lib/log/secure/
ds3.0/lib/log/watch/
ds3.0/lib/obj/book_source/
ds3.0/lib/obj/include/
ds3.0/lib/powers/prayers/
ds3.0/lib/powers/spells/
ds3.0/lib/realms/template/
ds3.0/lib/realms/template/adm/
ds3.0/lib/realms/template/area/
ds3.0/lib/realms/template/area/armor/
ds3.0/lib/realms/template/area/npc/
ds3.0/lib/realms/template/area/obj/
ds3.0/lib/realms/template/area/room/
ds3.0/lib/realms/template/area/weap/
ds3.0/lib/realms/template/bak/
ds3.0/lib/realms/template/cmds/
ds3.0/lib/save/kills/o/
ds3.0/lib/secure/cfg/classes/
ds3.0/lib/secure/cmds/builders/
ds3.0/lib/secure/cmds/creators/include/
ds3.0/lib/secure/cmds/players/
ds3.0/lib/secure/cmds/players/include/
ds3.0/lib/secure/daemon/imc2server/
ds3.0/lib/secure/daemon/include/
ds3.0/lib/secure/lib/
ds3.0/lib/secure/lib/include/
ds3.0/lib/secure/lib/net/include/
ds3.0/lib/secure/lib/std/
ds3.0/lib/secure/log/adm/
ds3.0/lib/secure/log/bak/
ds3.0/lib/secure/log/intermud/
ds3.0/lib/secure/log/network/
ds3.0/lib/secure/modules/
ds3.0/lib/secure/npc/
ds3.0/lib/secure/obj/include/
ds3.0/lib/secure/room/
ds3.0/lib/secure/save/
ds3.0/lib/secure/save/backup/
ds3.0/lib/secure/save/boards/
ds3.0/lib/secure/save/players/g/
ds3.0/lib/secure/tmp/
ds3.0/lib/secure/upgrades/files/
ds3.0/lib/secure/verbs/creators/
ds3.0/lib/std/board/
ds3.0/lib/std/lib/
ds3.0/lib/verbs/admins/include/
ds3.0/lib/verbs/builders/
ds3.0/lib/verbs/common/
ds3.0/lib/verbs/common/include/
ds3.0/lib/verbs/creators/
ds3.0/lib/verbs/creators/include/
ds3.0/lib/verbs/rooms/
ds3.0/lib/verbs/rooms/include/
ds3.0/lib/www/client/
ds3.0/lib/www/errors/
ds3.0/lib/www/images/
ds3.0/win32/
/*
 *  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)], 0, &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