/
Archipelago/
Archipelago/doc/
Archipelago/lib/misc/
Archipelago/lib/plrobjs/
Archipelago/lib/plrobjs/P-T/
Archipelago/lib/world/mob/
Archipelago/lib/world/obj/
Archipelago/lib/world/shp/
Archipelago/lib/world/wld/
Archipelago/lib/world/zon/
Archipelago/slave/
#include "slave.h"

pid_t slave_pid;
static int slave_socket = -1;   /* handle for the slave task */

..... somewhere in your descriptor structure you should have these fields

    unsigned long addr;         /* numerical address of host            */
    unsigned long port;         /* remote port number                   */
    char host[MAX_HOSTNAME+1];  /* text hostname                        */
    char userid[MAX_USERID+1];  /* userid from rfc1413 lookup           */

..... here is how the beginning of my new_connection routine looks
int new_connection(int s)
{
    int desc, size;
    unsigned long addr;
    struct descriptor_data *newd;
    struct sockaddr_in sock;
    char buf[ MAX_STRING_LENGTH+1 ];
    char *p;

    size = sizeof(sock);
    desc = accept(s, (struct sockaddr *)&sock, &size);
    if( desc < 0 ) {
        syslogf( "new_connection: accept(): %s", strerror( errno ) );
        return(-1);
    }

    addr = ntohl(sock.sin_addr.s_addr);
    
    /* game full check omitted */

    /* mark non-blocking, and close-on-exec */
    if( fcntl( desc, F_SETFL, FNDELAY ) == -1 ) {
        syslogf( "new_connection: fcntl( F_SETFL, FNDELAY ): %s",
            strerror( errno ) );
        close( desc );
        return( 0 );
    }
    if( fcntl( desc, F_SETFD, 1 ) == -1 ) {
        syslogf( "new_connection: fcntl( F_SETFD ): %s", strerror( errno ) );
        /* this isn't really fatal */
    }

    buf[0] = SLAVE_IPTONAME;
    p = format_inet_addr( buf+1, addr );

    /* banned check omitted */

    CREATE(newd, struct descriptor_data, 1);
    newd->descriptor = desc;
    strcpy( newd->host, buf+1 );        /* default to numeric hostname */
    newd->addr = addr;
    newd->port = ntohs( sock.sin_port );

    if( slave_socket != -1 && !SET_is_member( mudmode, MUD_NO_IPTONAME ) ) {
        /* ask slave to do a hostname lookup for us */
        *p = '\n';
        if( write( slave_socket, buf, p - buf + 1 ) != p - buf + 1 ) {
            syslogf( "{SLAVE} losing slave on write: %s", strerror( errno ));
            close( slave_socket );
            slave_socket = -1;
        }
        /* ask slave to do an identquery for us */
        buf[0] = SLAVE_IDENTQ;
        p += sprintf( p, ",%d,%d\n", ntohs( sock.sin_port ), game_port );
        if( write( slave_socket, buf, p - buf ) != p - buf ) {
            syslogf( "{SLAVE} losing slave on write: %s", strerror( errno ));
            close( slave_socket );
            slave_socket = -1;
        }
    }

    ..... remainder of new_connection code
}


......

/* get a result from the slave */
static int get_slave_result( void )
{
    char buf[ MAX_STRING_LENGTH +1 ];
    char token[ MAX_STRING_LENGTH ];
    char os[ MAX_STRING_LENGTH ];
    char userid[ MAX_STRING_LENGTH ];
    int octet[4];
    int local_port, remote_port;
    char *p;
    struct descriptor_data *d;
    long addr;
    int len;

    len = read( slave_socket, buf, MAX_STRING_LENGTH );
    if( len < 0 ) {
        if( errno == EAGAIN || errno == EWOULDBLOCK ) return( -1 );
        syslogf( "{SLAVE} losing slave on read: %s", strerror( errno ) );
        close( slave_socket );
        slave_socket = -1;
        return( -1 );
    } else if( len == 0 ) {
        return( -1 );
    }
    buf[len] = 0;

    switch( buf[0] ) {
    case SLAVE_IDENTQ:
        if( sscanf( buf+1, "%d.%d.%d.%d %d , %d : %[^: ] : %[^:] : %s",
            &octet[0], &octet[1], &octet[2], &octet[3],
            &remote_port, &local_port,
            token, os, userid ) != 9 ) {
            /* don't bother logging "ERROR" result codes */
            if( sscanf( buf+1, "%d.%d.%d.%d %d , %d : %[^:] : %s",
                &octet[0], &octet[1], &octet[2], &octet[3],
                &remote_port, &local_port,
                token, userid ) != 8 || strnicmp( token, "ERROR", 5 ) ) {
                p = strchr( buf, '\n' );
                *p = 0;
                syslogf( "{SLAVE} invalid: '%s'", buf );
            }
            return( 0 );
        }
        if( local_port != game_port ) {
            syslogf( "{SLAVE} invalid local port: '%s'", buf );
            return( 0 );
        }
        addr = ( octet[0] << 24 )
            + ( octet[1] << 16 )
            + ( octet[2] << 8 )
            + ( octet[3] );
        for( d = descriptor_list; d; d = d->next ) {
            if( d->port != remote_port ) continue;
            if( d->addr != addr ) continue;
            strncpy( d->userid, userid, MAX_USERID );
            d->userid[MAX_USERID] = 0;
            return( 0 );
        }
        break;
    
    case SLAVE_IPTONAME:
        if( sscanf( buf+1, "%d.%d.%d.%d %s",
                &octet[0], &octet[1], &octet[2], &octet[3], token ) != 5 ) {
            syslogf( "{SLAVE} invalid: %s", buf );
            return( 0 );
        }
        addr = ( octet[0] << 24 )
            + ( octet[1] << 16 )
            + ( octet[2] << 8 )
            + ( octet[3] );
        for( d = descriptor_list; d; d = d->next ) {
            if( d->addr != addr ) continue;
            strncpy( d->host, token, MAX_HOSTNAME );
            d->host[MAX_HOSTNAME] = 0;
        }
        break;

    default:
        syslogf( "{SLAVE} invalid: %s", buf );
        break;
    }
    return( 0 );
}


....


void game_loop(int s)
{

    ..... in the main game loop before the select() call
            /* Check what's happening out there */
            ARGV0( ARGV0_select );
            FD_ZERO(&input_set);
            FD_ZERO(&output_set);
            FD_ZERO(&exc_set);
            FD_SET(s, &input_set);
            if( slave_socket != -1 ) {
                FD_SET( slave_socket, &input_set );
            }

    .... somewhere after the select() call
                /* slave result? */
                if( slave_socket != -1
                    && FD_ISSET( slave_socket, &input_set ) ) {
                    while( get_slave_result() == 0 )
                        ;
                }

    .... somewhere while shutting down

    /* deal with slave */
    if( slave_socket != -1 ) {
        kill( slave_pid, SIGKILL );
    }
}


void boot_slave( void )
{
    int sv[2];
    int i;

    if( slave_socket != -1 ) {
        close( slave_socket );
        slave_socket = -1;
    }

    syslogf( "{BOOT} booting slave" );
    syslogf( "{BOOT} slave: ouch" );

    if( socketpair( AF_UNIX, SOCK_DGRAM, 0, sv ) < 0 ) {
        syslogf( "boot_slave: socketpair: %s", strerror( errno ) );
        return;
    }
    /* set to nonblocking */
    if( fcntl( sv[0], F_SETFL, FNDELAY ) == -1 ) {
        syslogf( "boot_slave: fcntl( F_SETFL, FNDELAY ): %s",
            strerror( errno ) );
        close(sv[0]);
        close(sv[1]);
        return;
    }
    slave_pid = vfork();
    switch( slave_pid ) {
    case -1:
        syslogf( "boot_slave: vfork: %s", strerror( errno ) );
        close( sv[0] );
        close( sv[1] );
        return;

    case 0: /* child */
        close( sv[0] );
        close( 0 );
        close( 1 );
        if( dup2( sv[1], 0 ) == -1 ) {
            syslogf( "boot_slave: child: unable to dup stdin: %s", strerror( errno ) );
            _exit( 1 );
        }
        if( dup2( sv[1], 1 ) == -1 ) {
            syslogf( "boot_slave: child: unable to dup stdout: %s", strerror( errno ) );
            _exit( 1 );
        }
        for( i = 3; i < system_max_handle; ++i ) {
            close( i );
        }
        execlp( "slave", "slave", NULL );
        syslogf( "boot_slave: child: unable to exec: %s", strerror( errno ) );
        _exit( 1 );
    }
    close( sv[1] );

    if( fcntl(sv[0], F_SETFL, FNDELAY ) == -1 ) {
        syslogf( "boot_slave: fcntl: %s", strerror( errno ) );
        close( sv[0] );
        return;
    }
    slave_socket = sv[0];
}