Hi
I'm installing KaVir's MSDP Protocol snippet in my smaufuss 1.9 based code. It aparently works, but when I do a hotboot
"Core was generated by `ff 6969 hotboot 3 -1'.
Program terminated with signal 11, Segmentation fault.
#0 0x000000000052eb00 in write_to_buffer (d=0x17b3440,
txt=0x6c1d5d "\033[1;34m", length=0) at comm.c:1628
1628 if ( d->pProtocol->WriteOOB > 0 )"
/*
* Append onto an output buffer.
*/
void write_to_buffer( DD * d, const char *txt, size_t length )
{
if( !d )
{
bug( "Write_to_buffer: NULL descriptor" );
return;
}
/*
* Normally a bug... but can happen if loadup is used.
*/
if( !d->outbuf )
return;
txt = ProtocolOutput( d, txt, &length );
if ( d->pProtocol->WriteOOB > 0 ) // line 1628
--d->pProtocol->WriteOOB;
/*
* Find length in case caller didn't.
*/
if( length <= 0 )
length = strlen( txt );
/* Uncomment if debugging or something
if ( length != strlen(txt) )
{
bug( "Write_to_buffer: length(%d) != strlen(txt)!", length );
length = strlen(txt);
}
*/
/*
* Initial \r\n if needed.
*/
if( d->outtop == 0 && !d->fcommand && !d->pProtocol->WriteOOB )
{
d->outbuf[0] = '\r';
d->outbuf[1] = '\n';
d->outtop = 2;
}
/*
* Expand the buffer as needed.
*/
while( d->outtop + length >= d->outsize )
{
if( d->outsize > 32000 )
{
/*
* empty buffer
*/
d->outtop = 0;
/*
* Bugfix by Samson - moved bug() call up
*/
bug( "Inundación del buffer. Desconectando (%s).", d->character ? d->character->name : "???" );
close_socket( d, TRUE );
return;
}
d->outsize *= 2;
RECREATE( d->outbuf, char, d->outsize );
}
/*
* Copy.
*/
strncpy( d->outbuf + d->outtop, txt, length );
d->outtop += length;
d->outbuf[d->outtop] = '\0';
return;
}
It's strange becouse the same function works fine before the hotboot. So I've tried the same with cygwin and I got almost the same result:
LEIA@LEIA-PC /home/leia/felixfelicis/src
$ awk '/^[0-9]/{print $2}' ff.exe.stackdump | addr2line -f -e ff.exe
_Z15write_to_bufferP15descriptor_dataPKcj
/home/leia/felixfelicis/src/comm.c:1628
_Z14set_char_colorsP9char_data
/home/leia/felixfelicis/color.c:1426
_Z3actsPKcP9char_dataPKvS4_i
/home/leia/felixfelicis/src/comm.c:4928
_Z15hotboot_recoverv
/home/leia/felixfelicis/src/hotboot.c:829
main
/home/leia/felixfelicis/src/comm.c:534
They all seem to be points where the code is sending text. So I thought the diference between it working before the hotboot and not working after the hotboot could be due to the way I'm preserving the protocol data during the hotboot.
In the snippet KaVir says:
Some muds use an exec() function to replace the current process with a new one,
effectively rebooting the mud without shutting it down. The problem with this
is that the client can't detect it, and because clients need to protect against
negotiation loops they may end up ignoring your attempts to renegotiate.
Therefore in order to store the data across reboots, you need to save it when
you do the copyover, and then load it again afterwards.
The snippet offers CopyoverSet() and CopyoverGet() functions to make this a
bit easier. When writing descriptors to the temporary file in your copyover
code, add an extra "%s" to each row and copy the string from CopyoverGet() into
it. Then when you load the file again after the copyover, pass the string back
into CopyoverSet(), and it'll restore the settings.
So I did it this way:
/* Warm reboot stuff, gotta make sure to thank Erwin for this
*/
CMDF( do_hotboot )
{
FILE *fp;
CD *vch = NULL;
DD *d, *de_next;
char buf[100], buf2[100], buf3[100];
char log_buf[MSL];
extern int control;
int count = 0;
bool found = FALSE;
for( d = first_descriptor; d; d = d->next )
{
if( ( d->connected == CON_PLAYING || d->connected == CON_EDITING )
&& ( vch = d->character ) != NULL && IS_PC( vch ) && vch->in_room
&& vch->fighting && vch->level >= 1 && vch->level <= MAX_LEVEL )
{
found = TRUE;
count++;
}
}
if( found )
{
ch_printf( ch, "&cNo podemos recargar. Hay %d combates en progreso.&D\r\n", count );
return;
}
found = FALSE;
for( d = first_descriptor; d; d = d->next )
{
if( d->connected == CON_EDITING && d->character )
{
found = TRUE;
break;
}
}
if( found )
{
send_to_char( "&cNo podemos recargar FelixFelicis, alguien está usando el editor!&D\r\n", ch );
return;
}
snprintf( log_buf, sizeof( log_buf ), "Recarga iniciada por %s.", ch->name );
log_string( log_buf );
fp = FileOpen( HOTBOOT_FILE, "w" );
if( !fp )
{
send_to_char( "No se puede escribir el archivo de la recarga, recarga abortada.\r\n", ch );
bug( "Could not write to hotboot file: %s. Hotboot aborted.", HOTBOOT_FILE );
perror( "do_copyover:FileOpen" );
return;
}
/*
* And this one here will save the status of all objects and mobs in the game.
* * This really should ONLY ever be used here. The less we do stuff like this the better.
*/
save_world( );
log_string( "Guardando las fichas de los jugadores y sus estados de conexión.." );
if( ch && ch->desc )
write_to_descriptor( ch->desc, "\033[0m", 0 );
snprintf( buf, sizeof( buf ), "\r\n&W¡&zEl tiempo se congela mientras la magia del mundo se renueva&W!&D\r\n" );
/*
* For each playing descriptor, save its state
*/
for( d = first_descriptor; d; d = de_next )
{
CD *och = CH( d );
de_next = d->next; /* We delete from the list , so need to save this */
if( !d->character || d->connected < CON_PLAYING ) /* drop those logging on */
{
write_to_descriptor( d, "\r\nDisculpa, estamos renovando la magia. Regresa en un minutito.\r\n", 0 );
close_socket( d, FALSE ); /* throw'em out */
}
else
{
fprintf( fp, "%d %d %d %d %d %s %s %s\n", d->descriptor,
d->can_compress, och->in_room->vnum, d->port, d->idle, och->name, d->host, CopyoverGet(d) );
/*
* One of two places this gets changed
*/
och->pcdata->hotboot = TRUE;
save_char_obj( och );
write_to_descriptor( d, colorize( buf, d ), 0 );
/* compressEnd( d ); */
}
}
fprintf( fp, "0 0 0 0 %d maxp maxp\n", sysdata.maxplayers );
fprintf( fp, "%s", "-1\n" );
FileClose( fp );
fp = NULL;
#ifdef IMC
imc_hotboot( );
#endif
/*
* added this in case there's a need to debug the contents of the various files
*/
if( argument && compare( argument, "debug" ) )
{
log_string( "Hotboot debug - Aborting before execl" );
return;
}
log_string( "Ejecutando la recarga.." );
/*
* exec - descriptors are inherited
*/
snprintf( buf, sizeof( buf ), "%d", port );
snprintf( buf2, sizeof( buf2 ), "%d", control );
#ifdef IMC
if( this_imcmud )
snprintf( buf3, sizeof( buf3 ), "%d", this_imcmud->desc );
else
strncpy( buf3, "-1", sizeof( buf3 ) );
#else
strncpy( buf3, "-1", sizeof( buf3 ) );
#endif
set_alarm( 0 );
dlclose( sysdata.dlHandle );
execl( EXE_FILE, "ff", buf, "hotboot", buf2, buf3, ( char * )NULL );
/*
* Failed - sucessful exec will not return
*/
perror( "do_hotboot: execl" );
sysdata.dlHandle = dlopen( NULL, RTLD_LAZY );
if( !sysdata.dlHandle )
{
bug( "%s", "FATAL ERROR: Unable to reopen system executable handle!" );
exit( 1 );
}
bug( "%s", "Hotboot execution failed!!" );
send_to_char( "&RRecarga FALLIDA!&D\r\n", ch );
}
/* Recover from a hotboot - load players */
void hotboot_recover( void )
{
DD *d = NULL;
FILE *fp;
char name[100], protocol[100];
char host[MSL];
int desc, dcompress, room, dport, idle, maxp = 0;
bool fOld;
fp = FileOpen( HOTBOOT_FILE, "r" );
if( !fp ) /* there are some descriptors open which will hang forever then ? */
{
perror( "hotboot_recover: FileOpen" );
bug( "%s", "Hotboot file not found. Exitting." );
exit( 1 );
}
unlink( HOTBOOT_FILE ); /* In case something crashes - doesn't prevent reading */
for( ;; )
{
d = NULL;
fscanf( fp, "%d %d %d %d %d %s %s %s\n", &desc, &dcompress, &room, &dport, &idle, name, host, protocol );
if( desc == -1 || feof( fp ) )
break;
if( compare( name, "maxp" ) || compare( host, "maxp" ) )
{
maxp = idle;
continue;
}
/*
* Write something, and check if it goes error-free
*/
if( !dcompress && !write_to_descriptor_old( desc, "\r\n&cUn torbellino mágico provoca el caos.&D\r\n", 0 ) )
{
close( desc ); /* nope */
continue;
}
CREATE( d, DD, 1 );
d->next = NULL;
d->descriptor = desc;
d->connected = CON_GET_NAME;
d->outsize = 2000;
d->idle = 0;
d->lines = 0;
d->scrlen = 24;
d->newstate = 0;
d->prevcolor = 0x08;
d->ifd = -1;
d->ipid = -1;
CREATE( d->outbuf, char, d->outsize );
d->host = STRALLOC( host );
d->port = dport;
d->idle = idle;
CREATE( d->mccp, MCCP, 1 );
d->can_compress = dcompress;
/* if( d->can_compress )
compressStart( d ); */
CopyoverSet( d, protocol );
LINK( d, first_descriptor, last_descriptor, next, prev );
d->connected = CON_COPYOVER_RECOVER; /* negative so close_socket will cut them off */
/*
* Now, find the pfile
*/
fOld = load_char_obj( d, name, FALSE, TRUE );
if( !fOld ) /* Player file not found?! */
{
write_to_descriptor( d, colorize( "\r\nLamentamos informarte que tu ficha se perdio durante la recarga, por favor, contacta con un administrador.&D\r\n", d ), 0 );
close_socket( d, FALSE );
}
else /* ok! */
{
write_to_descriptor( d, colorize( "&gEl tiempo vuelve a transcurrir con normalidad&G.&D", d ), 0 );
d->character->in_room = get_room_index( room );
if( !d->character->in_room )
d->character->in_room = get_room_index( ROOM_VNUM_TEMPLE );
/*
* Insert in the char_list
*/
LINK( d->character, first_char, last_char, next, prev );
char_to_room( d->character, d->character->in_room );
act( AT_MAGIC, "&C¡&cUn soplo de &zhumo &Wblanco &cse disipa a tu alrededor&C!&D\r\n", d->character, NULL, NULL, TO_CHAR );
act( AT_MAGIC, "&C¡&c$n aparece tras un sonoro crack&C!&D", d->character, NULL, NULL, TO_ROOM );
d->connected = CON_PLAYING;
if( ++num_descriptors > sysdata.maxplayers )
sysdata.maxplayers = num_descriptors;
#ifdef AUTO_AUTH
check_auth_state( d->character ); /* new auth */
#endif
}
}
FileClose( fp );
fp = NULL;
if( maxp > sysdata.maxplayers )
sysdata.maxplayers = maxp;
log_string( "&GRecarga completada con éxito&Y. &P
&D\r\n" );
return;
}
Any hint of what I may be doing wrong is welcome