#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]; }