void CHSInterface::BroadcastWithFlags(HS_INT32 iFlags, HS_INT32 iToggles, const HS_INT8 * pcFormat, ...) #endif { va_list args; static char buff[HSPACE_MAX_HSPRINTF_LEN]; va_start(args, pcFormat); vsnprintf(buff, HSPACE_MAX_HSPRINTF_LEN, pcFormat, args); buff[HSPACE_MAX_HSPRINTF_LEN - 1] = '\0'; va_end(args); #ifdef PENNMUSH flag_broadcast(iFlags, iToggles, buff); #endif #if defined(TM3) || defined(MUX) raw_broadcast(iToggles, buff); #endif }
void boot_slave( void ) { int sv[2]; int i; int maxfds; char *s; #ifdef HAVE_GETDTABLESIZE maxfds = getdtablesize(); #else maxfds = sysconf( _SC_OPEN_MAX ); #endif if( slave_socket != -1 ) { close( slave_socket ); slave_socket = -1; } if( socketpair( AF_UNIX, SOCK_DGRAM, 0, sv ) < 0 ) { return; } /* * set to nonblocking */ #ifdef FNDELAY if( fcntl( sv[0], F_SETFL, FNDELAY ) == -1 ) { #else if( fcntl( sv[0], F_SETFL, O_NDELAY ) == -1 ) { #endif close( sv[0] ); close( sv[1] ); return; } slave_pid = vfork(); switch( slave_pid ) { case -1: close( sv[0] ); close( sv[1] ); return; case 0: /* child */ close( sv[0] ); if( dup2( sv[1], 0 ) == -1 ) { _exit( 1 ); } if( dup2( sv[1], 1 ) == -1 ) { _exit( 1 ); } for( i = 3; i < maxfds; ++i ) { close( i ); } s = ( char * ) XMALLOC( MBUF_SIZE, "boot_slave" ); sprintf( s, "%s/slave", mudconf.binhome ); execlp( s, "slave", NULL ); XFREE( s, "boot_slave" ); _exit( 1 ); } close( sv[1] ); #ifdef FNDELAY if( fcntl( sv[0], F_SETFL, FNDELAY ) == -1 ) { #else if( fcntl( sv[0], F_SETFL, O_NDELAY ) == -1 ) { #endif close( sv[0] ); return; } slave_socket = sv[0]; log_write( LOG_ALWAYS, "NET", "SLAVE", "DNS lookup slave started on fd %d", slave_socket ); } int make_socket( int port ) { int s, opt; struct sockaddr_in server; s = socket( AF_INET, SOCK_STREAM, 0 ); if( s < 0 ) { log_perror( "NET", "FAIL", NULL, "creating master socket" ); exit( 3 ); } opt = 1; if( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, ( char * ) &opt, sizeof( opt ) ) < 0 ) { log_perror( "NET", "FAIL", NULL, "setsockopt" ); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = ( unsigned short ) htons( ( unsigned short ) port ); if( !mudstate.restarting ) if( bind( s, ( struct sockaddr * ) &server, sizeof( server ) ) ) { log_perror( "NET", "FAIL", NULL, "bind" ); close( s ); exit( 4 ); } listen( s, 5 ); return s; } void shovechars( int port ) { fd_set input_set, output_set; struct timeval last_slice, current_time, next_slice, timeout, slice_timeout; int found, check; DESC *d, *dnext, *newd; int avail_descriptors, maxfds; struct stat fstatbuf; #define CheckInput(x) FD_ISSET(x, &input_set) #define CheckOutput(x) FD_ISSET(x, &output_set) mudstate.debug_cmd = ( char * ) "< shovechars >"; if( !mudstate.restarting ) { sock = make_socket( port ); } if( !mudstate.restarting ) { maxd = sock + 1; } get_tod( &last_slice ); #ifdef HAVE_GETDTABLESIZE maxfds = getdtablesize(); #else maxfds = sysconf( _SC_OPEN_MAX ); #endif avail_descriptors = maxfds - 7; while( mudstate.shutdown_flag == 0 ) { get_tod( ¤t_time ); last_slice = update_quotas( last_slice, current_time ); process_commands(); if( mudstate.shutdown_flag ) { break; } /* * We've gotten a signal to dump flatfiles */ if( mudstate.flatfile_flag && !mudstate.dumping ) { if( *mudconf.dump_msg ) { raw_broadcast( 0, "%s", mudconf.dump_msg ); } mudstate.dumping = 1; log_write( LOG_DBSAVES, "DMP", "CHKPT", "Flatfiling: %s.#%d#", mudconf.db_file, mudstate.epoch ); dump_database_internal( DUMP_DB_FLATFILE ); mudstate.dumping = 0; if( *mudconf.postdump_msg ) { raw_broadcast( 0, "%s", mudconf.postdump_msg ); } mudstate.flatfile_flag = 0; } /* * test for events */ dispatch(); /* * any queued robot commands waiting? */ timeout.tv_sec = que_next(); timeout.tv_usec = 0; next_slice = msec_add( last_slice, mudconf.timeslice ); slice_timeout = timeval_sub( next_slice, current_time ); FD_ZERO( &input_set ); FD_ZERO( &output_set ); /* * Listen for new connections if there are free descriptors */ if( ndescriptors < avail_descriptors ) { FD_SET( sock, &input_set ); } /* * Listen for replies from the slave socket */ if( slave_socket != -1 ) { FD_SET( slave_socket, &input_set ); } /* * Mark sockets that we want to test for change in status */ DESC_ITER_ALL( d ) { if( !d->input_head ) { FD_SET( d->descriptor, &input_set ); } if( d->output_head ) { FD_SET( d->descriptor, &output_set ); } } /* * Wait for something to happen */ found = select( maxd, &input_set, &output_set, ( fd_set * ) NULL, &timeout ); if( found < 0 ) { if( errno == EBADF ) { /* * This one is bad, as it results in a spiral * of doom, unless we can figure out what the * bad file descriptor is and get rid of it. */ log_perror( "NET", "FAIL", "checking for activity", "select" ); DESC_ITER_ALL( d ) { if( fstat( d->descriptor, &fstatbuf ) < 0 ) { /* * It's a player. Just toss * the connection. */ log_write( LOG_PROBLEMS, "ERR", "EBADF", "Bad descriptor %d", d->descriptor ); shutdownsock( d,R_SOCKDIED ); } } if( ( slave_socket == -1 ) || ( fstat( slave_socket, &fstatbuf ) < 0 ) ) { /* * Try to restart the slave, since it * presumably died. */ log_write( LOG_PROBLEMS, "ERR", "EBADF", "Bad slave descriptor %d", slave_socket ); boot_slave(); } if( ( sock != -1 ) && ( fstat( sock, &fstatbuf ) < 0 ) ) { /* * That's it, game over. */ log_write( LOG_PROBLEMS, "ERR", "EBADF", "Bad game port descriptor %d", sock ); break; } } else if( errno != EINTR ) { log_perror( "NET", "FAIL", "checking for activity", "select" ); } continue; }
void do_kill (dbref player, dbref cause, int key, char *what, char *costchar) { dbref victim; char *buf1, *buf2; int cost; init_match(player, what, TYPE_PLAYER); match_neighbor(); match_me(); match_here(); if (Wizard(player)) { match_player(); match_absolute(); } victim = match_result(); switch (victim) { case NOTHING: notify(player, "I don't see that player here."); break; case AMBIGUOUS: notify(player, "I don't know who you mean!"); break; default: if ((Typeof(victim) != TYPE_PLAYER) && (Typeof(victim) != TYPE_THING)) { notify(player, "Sorry, you can only kill players and things."); break; } if ((Haven(Location(victim)) && !Wizard(player)) || (controls(victim, Location(victim)) && !controls(player, Location(victim))) || Immortal(victim)) { notify(player, "Sorry."); break; } if (key == KILL_SLAY) { if (Builder(player) && Builder(victim)) { notify(player, "Sorry."); break; } } /* go for it */ cost = atoi(costchar); if (key == KILL_KILL) { if (HasPriv(victim,player,POWER_NOKILL,POWER4,NOTHING)) { notify(player, "Sorry."); break; } if (cost < mudconf.killmin) cost = mudconf.killmin; if (cost > mudconf.killmax) cost = mudconf.killmax; /* see if it works */ if (!payfor(player, cost)) { notify(player, unsafe_tprintf("You don't have enough %s.", mudconf.many_coins)); return; } } else { cost = 0; } if (!(((random() % mudconf.killguarantee) < cost) || (key == KILL_SLAY)) || Wizard(victim)) { /* Failure: notify player and victim only */ notify(player, "Your murder attempt failed."); buf1 = alloc_lbuf("do_kill.failed"); sprintf(buf1, "%s tried to kill you!", Name(player)); notify_with_cause(victim, player, buf1); if (Suspect(player)) { strcpy(buf1, Name(player)); if (player == Owner(player)) { raw_broadcast(0, WIZARD, "[Suspect] %s tried to kill %s(#%d).", buf1, Name(victim), victim); } else { buf2 = alloc_lbuf("do_kill.SUSP.failed"); strcpy(buf2, Name(Owner(player))); raw_broadcast(0, WIZARD, "[Suspect] %s <via %s(#%d)> tried to kill %s(#%d).", buf2, buf1, player, Name(victim), victim); free_lbuf(buf2); } } free_lbuf(buf1); break; } /* Success! You killed him */ buf1 = alloc_lbuf("do_kill.succ.1"); buf2 = alloc_lbuf("do_kill.succ.2"); if (Suspect(player)) { strcpy(buf1, Name(player)); if (player == Owner(player)) { raw_broadcast(0, WIZARD, "[Suspect] %s killed %s(#%d).", buf1, Name(victim), victim); } else { strcpy(buf2, Name(Owner(player))); raw_broadcast(0, WIZARD, "[Suspect] %s <via %s(#%d)> killed %s(#%d).", buf2, buf1, player, Name(victim), victim); } } sprintf(buf1, "You killed %s!", Name(victim)); sprintf(buf2, "killed %s!", Name(victim)); if (Typeof(victim) != TYPE_PLAYER) if (halt_que(NOTHING, victim) > 0) if (!Quiet(victim)) notify(Owner(victim), "Halted."); did_it(player, victim, A_KILL, buf1, A_OKILL, buf2, A_AKILL, (char **)NULL, 0); /* notify victim */ sprintf(buf1, "%s killed you!", Name(player)); notify_with_cause(victim, player, buf1); /* Pay off the bonus */ if (key == KILL_KILL) { cost /= 2; /* victim gets half */ if (Pennies(Owner(victim)) < mudconf.paylimit) { sprintf(buf1, "Your insurance policy pays %d %s.", cost, mudconf.many_coins); notify(victim, buf1); giveto(Owner(victim), cost, NOTHING); } else { notify(victim, "Your insurance policy has been revoked."); } } free_lbuf(buf1); free_lbuf(buf2); /* send him home */ move_via_generic(victim, HOME, NOTHING, 0); divest_object(victim); break; } }
void do_dbclean( dbref player, dbref cause, int key ) { VATTR *vp, *vpx; dbref i, end; int ca, n_oldtotal, n_oldtop, n_deleted, n_renumbered, n_objt, n_atrt, got; char *as, *str; int *used_table; ATTR **new_table; UFUN *ufp; CMDENT *cmdp; ADDENT *addp; raw_broadcast( 0, "GAME: Cleaning database. Game may freeze for a few minutes." ); used_table = ( int * ) XCALLOC( mudstate.attr_next, sizeof( int ), "dbclean.used_table" ); n_oldtotal = mudstate.attr_next; n_oldtop = anum_alc_top; n_deleted = n_renumbered = n_objt = n_atrt = 0; /* * Non-user-defined attributes are always considered used. */ for( i = 0; i < A_USER_START; i++ ) { used_table[i] = i; } /* * Walk the database. Mark all the attribute numbers in use. */ atr_push(); DO_WHOLE_DB( i ) { for( ca = atr_head( i, &as ); ca; ca = atr_next( &as ) ) { used_table[ca] = ca; } } atr_pop(); /* * Walk the vattr table. If a number isn't in use, zorch it. */ vp = vattr_first(); while( vp ) { vpx = vp; vp = vattr_next( vp ); if( used_table[vpx->number] == 0 ) { anum_set( vpx->number, NULL ); hashdelete( vpx->name, &mudstate.vattr_name_htab ); XFREE( vpx, "dbclean.vpx" ); n_deleted++; } } /* * The user-defined function, added command, and hook structures embed * * attribute numbers. Clean out the ones we've deleted, resetting them * * to the *Invalid (A_TEMP) attr. */ for( ufp = ( UFUN * ) hash_firstentry( &mudstate.ufunc_htab ); ufp != NULL; ufp = ( UFUN * ) hash_nextentry( &mudstate.ufunc_htab ) ) { if( used_table[ufp->atr] == 0 ) { ufp->atr = A_TEMP; } } for( cmdp = ( CMDENT * ) hash_firstentry( &mudstate.command_htab ); cmdp != NULL; cmdp = ( CMDENT * ) hash_nextentry( &mudstate.command_htab ) ) { if( cmdp->pre_hook ) { if( used_table[cmdp->pre_hook->atr] == 0 ) { cmdp->pre_hook->atr = A_TEMP; } } if( cmdp->post_hook ) { if( used_table[cmdp->post_hook->atr] == 0 ) { cmdp->post_hook->atr = A_TEMP; } } if( cmdp->userperms ) { if( used_table[cmdp->userperms->atr] == 0 ) { cmdp->userperms->atr = A_TEMP; } } if( cmdp->callseq & CS_ADDED ) { for( addp = ( ADDENT * ) cmdp->info.added; addp != NULL; addp = addp->next ) { if( used_table[addp->atr] == 0 ) { addp->atr = A_TEMP; } } } } /* * Walk the table we've created of used statuses. When we find free * * slots, walk backwards to the first used slot at the end of the * * table. Write the number of the free slot into that used slot. */ for( i = A_USER_START, end = mudstate.attr_next - 1; ( i < mudstate.attr_next ) && ( i < end ); i++ ) { if( used_table[i] == 0 ) { while( ( end > i ) && ( used_table[end] == 0 ) ) { end--; } if( end > i ) { used_table[end] = used_table[i] = i; end--; } } } /* * Renumber the necessary attributes in the vattr tables. */ for( i = A_USER_START; i < mudstate.attr_next; i++ ) { if( used_table[i] != i ) { vp = ( VATTR * ) anum_get( i ); if( vp ) { vp->number = used_table[i]; vp->flags |= AF_DIRTY; anum_set( used_table[i], ( ATTR * ) vp ); anum_set( i, NULL ); n_renumbered++; } } } /* * Now we walk the database. For every object, if we have an attribute * * we're renumbering (the slot number is not equal to the array value * * at that slot), we delete the old attribute and add the new one. */ atr_push(); DO_WHOLE_DB( i ) { got = 0; for( ca = atr_head( i, &as ); ca; ca = atr_next( &as ) ) { if( used_table[ca] != ca ) { str = atr_get_raw( i, ca ); atr_add_raw( i, used_table[ca], str ); atr_clr( i, ca ); n_atrt++; got = 1; } } if( got ) { n_objt++; } } atr_pop(); /* * The new end of the attribute table is the first thing we've * * renumbered. */ for( end = A_USER_START; ( ( end == used_table[end] ) && ( end < mudstate.attr_next ) ); end++ ); mudstate.attr_next = end; /* * We might be able to shrink the size of the attribute table. * * If the current size of the table is less than the initial * * size, shrink it back down to the initial size. * * Otherwise, shrink it down so it's the current top plus the * * initial size, as if we'd just called anum_extend() for it. */ if( anum_alc_top > mudconf.init_size + A_USER_START ) { if( mudstate.attr_next < mudconf.init_size + A_USER_START ) { end = mudconf.init_size + A_USER_START; } else { end = mudstate.attr_next + mudconf.init_size; } if( end < anum_alc_top ) { new_table = ( ATTR ** ) XCALLOC( end + 1, sizeof( ATTR * ), "dbclean.new_table" ); for( i = 0; i < mudstate.attr_next; i++ ) { new_table[i] = anum_table[i]; } XFREE( anum_table, "dbclean.anum_table" ); anum_table = new_table; anum_alc_top = end; } } /* * Go through the function and added command tables again, and * * take care of the attributes that got renumbered. */ for( ufp = ( UFUN * ) hash_firstentry( &mudstate.ufunc_htab ); ufp != NULL; ufp = ( UFUN * ) hash_nextentry( &mudstate.ufunc_htab ) ) { if( used_table[ufp->atr] != ufp->atr ) { ufp->atr = used_table[ufp->atr]; } } for( cmdp = ( CMDENT * ) hash_firstentry( &mudstate.command_htab ); cmdp != NULL; cmdp = ( CMDENT * ) hash_nextentry( &mudstate.command_htab ) ) { if( cmdp->pre_hook ) { if( used_table[cmdp->pre_hook->atr] != cmdp->pre_hook->atr ) cmdp->pre_hook->atr = used_table[cmdp->pre_hook->atr]; } if( cmdp->post_hook ) { if( used_table[cmdp->post_hook->atr] != cmdp->post_hook->atr ) cmdp->post_hook->atr = used_table[cmdp->post_hook->atr]; } if( cmdp->userperms ) { if( used_table[cmdp->userperms->atr] != cmdp->userperms->atr ) cmdp->userperms->atr = used_table[cmdp->userperms->atr]; } if( cmdp->callseq & CS_ADDED ) { for( addp = ( ADDENT * ) cmdp->info.added; addp != NULL; addp = addp->next ) { if( used_table[addp->atr] != addp->atr ) { addp->atr = used_table[addp->atr]; } } } } /* * Clean up. */ XFREE( used_table, "dbclean.used_table" ); if( anum_alc_top != n_oldtop ) { notify_check( player, player, MSG_PUP_ALWAYS|MSG_ME_ALL|MSG_F_DOWN, "Cleaned %d user attribute slots (reduced to %d): %d deleted, %d renumbered (%d objects and %d individual attrs touched). Table size reduced from %d to %d.", n_oldtotal - A_USER_START, mudstate.attr_next - A_USER_START, n_deleted, n_renumbered, n_objt, n_atrt, n_oldtop, anum_alc_top ); } else { notify_check( player, player, MSG_PUP_ALWAYS|MSG_ME_ALL|MSG_F_DOWN, "Cleaned %d attributes (now %d): %d deleted, %d renumbered (%d objects and %d individual attrs touched).", n_oldtotal, mudstate.attr_next, n_deleted, n_renumbered, n_objt, n_atrt ); } raw_broadcast( 0, "GAME: Database cleaning complete." ); }