mux/src/bsd.cpp File Reference

#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "externs.h"
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include "attrs.h"
#include "command.h"
#include "file_c.h"
#include "slave.h"

Include dependency graph for bsd.cpp:

Go to the source code of this file.

Data Structures

struct  SIGNALTYPE
struct  MUX_SIGNAMES

Defines

#define CheckInput(x)   FD_ISSET(x, &input_set)
#define CheckOutput(x)   FD_ISSET(x, &output_set)
#define CAST_SIGNAL_FUNC

Typedefs

typedef struct SIGNALTYPEPSIGNALTYPE

Functions

static void TelnetSetup (DESC *d)
 Begin initial telnet negotiations on a socket.
static void SiteMonSend (int, const char *, DESC *, const char *)
static DESCinitializesock (SOCKET, struct sockaddr_in *)
static DESCnew_connection (PortInfo *Port, int *piError)
static bool process_input (DESC *)
static int make_nonblocking (SOCKET s)
void CleanUpSlaveSocket (void)
void CleanUpSlaveProcess (void)
void boot_slave (dbref executor, dbref caller, dbref enactor, int)
 Lauch reverse-DNS slave process.
static int get_slave_result (void)
static void make_socket (PortInfo *Port)
void SetupPorts (int *pnPorts, PortInfo aPorts[], IntArray *pia)
bool ValidSocket (SOCKET s)
void shovechars (int nPorts, PortInfo aPorts[])
void shutdownsock (DESC *d, int reason)
static void make_nolinger (SOCKET s)
static void config_socket (SOCKET s)
void process_output (void *dvoid, int bHandleShutdown)
int HimState (DESC *d, unsigned char chOption)
 Return the other side's negotiation state.
int UsState (DESC *d, unsigned char chOption)
 Return our side's negotiation state.
static void SetHimState (DESC *d, unsigned char chOption, int iHimState)
 Change the other side's negotiation state.
static void SetUsState (DESC *d, unsigned char chOption, int iUsState)
 Change our side's negotiation state.
static void SendWill (DESC *d, unsigned char chOption)
 Transmit a Telnet WILL sequence for the given option.
static void SendDont (DESC *d, unsigned char chOption)
 Transmit a Telnet DONT sequence for the given option.
static void SendDo (DESC *d, unsigned char chOption)
 Transmit a Telnet DO sequence for the given option.
static void SendWont (DESC *d, unsigned char chOption)
 Transmit a Telnet WONT sequence for the given option.
static bool DesiredHimOption (DESC *d, unsigned char chOption)
 Determine whether we want a particular option on his side of the link to be enabled.
static bool DesiredUsOption (DESC *d, unsigned char chOption)
 Determine whether we want a particular option on our side of the link to be enabled.
void EnableHim (DESC *d, unsigned char chOption)
 Start the process of negotiating the enablement of an option on his side.
void DisableHim (DESC *d, unsigned char chOption)
 Start the process of negotiating the disablement of an option on his side.
void EnableUs (DESC *d, unsigned char chOption)
 Start the process of negotiating the enablement of an option on our side.
void DisableUs (DESC *d, unsigned char chOption)
 Start the process of negotiating the disablement of an option on our side.
static void process_input_helper (DESC *d, char *pBytes, int nBytes)
 Parse raw data from network connection into command lines and Telnet indications.
void close_sockets (bool emergency, char *message)
void emergency_shutdown (void)
static void check_panicking (int sig)
static void unset_signals (void)
void BuildSignalNamesTable (void)
static char * SignalDesc (int iSignal)
static void log_signal (int iSignal)
static void log_signal_ignore (int iSignal)
void LogStatBuf (int stat_buf, const char *Name)
static RETSIGTYPE DCL_CDECL sighandler (int sig)
void set_signals (void)
void list_system_resources (dbref player)

Variables

PortInfo aMainGamePorts [MAX_LISTEN_PORTS]
int nMainGamePorts = 0
unsigned int ndescriptors = 0
DESCdescriptor_list = NULL
int maxd = 0
pid_t slave_pid = 0
int slave_socket = INVALID_SOCKET
pid_t game_pid
static const char * disc_reasons []
static const char * disc_messages []
static const unsigned char nvt_input_xlat_table [256]
 Table to quickly classify characters recieved from the wire with their Telnet meaning.
static const int nvt_input_action_table [8][14]
 Table to map current telnet parsing state state and input to specific actions and state changes.
const SIGNALTYPE aSigTypes []
static MUX_SIGNAMES signames [NSIG]
NAMETAB sigactions_nametab []


Detailed Description

File for most TCP socket-related code. Some socket-related code also exists in netcommon.cpp, but most of it is here.

Id
bsd.cpp,v 1.81 2006/11/26 05:05:21 sdennis Exp

Definition in file bsd.cpp.


Define Documentation

#define CAST_SIGNAL_FUNC

Definition at line 3413 of file bsd.cpp.

Referenced by alarm_signal(), child_signal(), main(), set_signals(), and sighandler().

#define CheckInput (  )     FD_ISSET(x, &input_set)

Referenced by shovechars().

#define CheckOutput (  )     FD_ISSET(x, &output_set)

Referenced by shovechars().


Typedef Documentation

typedef struct SIGNALTYPE * PSIGNALTYPE


Function Documentation

void boot_slave ( dbref  executor,
dbref  caller,
dbref  enactor,
int   
)

Lauch reverse-DNS slave process.

This spawns the reverse-DNS slave process and creates a socket-oriented, bi-directional communiocation path between that process and this process. Any existing slave process is killed.

Parameters:
executor dbref of Executor.
caller dbref of Caller.
enactor dbref of Enactor.
Returns:
None.

Definition at line 649 of file bsd.cpp.

References CleanUpSlaveProcess(), CleanUpSlaveSocket(), CMuxAlarm::Clear(), DebugTotalSockets, ENDLOG, LOG_ALWAYS, log_number(), log_text(), make_nonblocking(), maxd, MuxAlarm, slave_pid, slave_socket, and STARTLOG.

Referenced by main(), and shovechars().

00650 {
00651     char *pFailedFunc = 0;
00652     int sv[2];
00653     int i;
00654     int maxfds;
00655 
00656 #ifdef HAVE_GETDTABLESIZE
00657     maxfds = getdtablesize();
00658 #else // HAVE_GETDTABLESIZE
00659     maxfds = sysconf(_SC_OPEN_MAX);
00660 #endif // HAVE_GETDTABLESIZE
00661 
00662     CleanUpSlaveSocket();
00663     CleanUpSlaveProcess();
00664 
00665     if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0)
00666     {
00667         pFailedFunc = "socketpair() error: ";
00668         goto failure;
00669     }
00670 
00671     // Set to nonblocking.
00672     //
00673     if (make_nonblocking(sv[0]) < 0)
00674     {
00675         pFailedFunc = "make_nonblocking() error: ";
00676         close(sv[0]);
00677         close(sv[1]);
00678         goto failure;
00679     }
00680     slave_pid = fork();
00681     switch (slave_pid)
00682     {
00683     case -1:
00684 
00685         pFailedFunc = "fork() error: ";
00686         close(sv[0]);
00687         close(sv[1]);
00688         goto failure;
00689 
00690     case 0:
00691 
00692         // If we don't clear this alarm, the child will eventually receive a
00693         // SIG_PROF.
00694         //
00695         MuxAlarm.Clear();
00696 
00697         // Child.  The following calls to dup2() assume only the minimal
00698         // dup2() functionality.  That is, the destination descriptor is
00699         // always available for it, and sv[1] is never that descriptor.
00700         // It is likely that the standard defined behavior of dup2()
00701         // would handle the job by itself more directly, but a little
00702         // extra code is low-cost insurance.
00703         //
00704         close(sv[0]);
00705         if (sv[1] != 0)
00706         {
00707             close(0);
00708             if (dup2(sv[1], 0) == -1)
00709             {
00710                 _exit(1);
00711             }
00712         }
00713         if (sv[1] != 1)
00714         {
00715             close(1);
00716             if (dup2(sv[1], 1) == -1)
00717             {
00718                 _exit(1);
00719             }
00720         }
00721         for (i = 3; i < maxfds; i++)
00722         {
00723             close(i);
00724         }
00725         execlp("bin/slave", "slave", NULL);
00726         _exit(1);
00727     }
00728     close(sv[1]);
00729 
00730     slave_socket = sv[0];
00731     DebugTotalSockets++;
00732     if (make_nonblocking(slave_socket) < 0)
00733     {
00734         pFailedFunc = "make_nonblocking() error: ";
00735         CleanUpSlaveSocket();
00736         goto failure;
00737     }
00738     if (maxd <= slave_socket)
00739     {
00740         maxd = slave_socket + 1;
00741     }
00742 
00743     STARTLOG(LOG_ALWAYS, "NET", "SLAVE");
00744     log_text("DNS lookup slave started on fd ");
00745     log_number(slave_socket);
00746     ENDLOG;
00747     return;
00748 
00749 failure:
00750 
00751     CleanUpSlaveProcess();
00752     STARTLOG(LOG_ALWAYS, "NET", "SLAVE");
00753     log_text(pFailedFunc);
00754     log_number(errno);
00755     ENDLOG;
00756 }

void BuildSignalNamesTable ( void   ) 

Definition at line 3632 of file bsd.cpp.

References aSigTypes, SIGNALTYPE::iSignal, MUX_SIGNAMES::pLongName, MUX_SIGNAMES::pShortName, signames, and SIGNALTYPE::szSignal.

Referenced by main().

03633 {
03634     int i;
03635     for (i = 0; i < NSIG; i++)
03636     {
03637         signames[i].pShortName = NULL;
03638         signames[i].pLongName  = NULL;
03639     }
03640 
03641     const SIGNALTYPE *pst = aSigTypes;
03642     while (pst->szSignal)
03643     {
03644         int sig = pst->iSignal;
03645         if (  0 <= sig
03646            && sig < NSIG)
03647         {
03648             MUX_SIGNAMES *tsn = &signames[sig];
03649             if (tsn->pShortName == NULL)
03650             {
03651                 tsn->pShortName = pst->szSignal;
03652 #ifndef WIN32
03653                 if (sig == SIGUSR1)
03654                 {
03655                     tsn->pLongName = "Restart server";
03656                 }
03657                 else if (sig == SIGUSR2)
03658                 {
03659                     tsn->pLongName = "Drop flatfile";
03660                 }
03661 #endif // WIN32
03662 #ifdef SysSigNames
03663                 if (  tsn->pLongName == NULL
03664                    && SysSigNames[sig]
03665                    && strcmp(tsn->pShortName, SysSigNames[sig]) != 0)
03666                 {
03667                     tsn->pLongName = SysSigNames[sig];
03668                 }
03669 #endif // SysSigNames
03670             }
03671         }
03672         pst++;
03673     }
03674     for (i = 0; i < NSIG; i++)
03675     {
03676         MUX_SIGNAMES *tsn = &signames[i];
03677         if (tsn->pShortName == NULL)
03678         {
03679 #ifdef SysSigNames
03680             if (SysSigNames[i])
03681             {
03682                 tsn->pLongName = SysSigNames[i];
03683             }
03684 #endif // SysSigNames
03685 
03686             // This is the only non-const memory case.
03687             //
03688             tsn->pShortName = StringClone(tprintf("SIG%03d", i));
03689         }
03690     }
03691 }

static void check_panicking ( int  sig  )  [static]

Definition at line 3380 of file bsd.cpp.

References game_pid, mudstate, statedata::panicking, and UNUSED_PARAMETER.

Referenced by sighandler().

03381 {
03382     // If we are panicking, turn off signal catching and resignal.
03383     //
03384     if (mudstate.panicking)
03385     {
03386         for (int i = 0; i < NSIG; i++)
03387         {
03388             signal(i, SIG_DFL);
03389         }
03390 #ifdef WIN32
03391         UNUSED_PARAMETER(sig);
03392         abort();
03393 #else // WIN32
03394         kill(game_pid, sig);
03395 #endif // WIN32
03396     }
03397     mudstate.panicking = true;
03398 }

void CleanUpSlaveProcess ( void   ) 

Definition at line 478 of file bsd.cpp.

References slave_pid.

Referenced by boot_slave(), do_restart(), get_slave_result(), main(), new_connection(), and sighandler().

00479 {
00480     if (slave_pid > 0)
00481     {
00482         kill(slave_pid, SIGKILL);
00483         waitpid(slave_pid, NULL, 0);
00484     }
00485     slave_pid = 0;
00486 }

void CleanUpSlaveSocket ( void   ) 

Definition at line 465 of file bsd.cpp.

References DebugTotalSockets, INVALID_SOCKET, IS_INVALID_SOCKET, SD_BOTH, and slave_socket.

Referenced by boot_slave(), do_restart(), get_slave_result(), main(), new_connection(), and sighandler().

00466 {
00467     if (!IS_INVALID_SOCKET(slave_socket))
00468     {
00469         shutdown(slave_socket, SD_BOTH);
00470         if (close(slave_socket) == 0)
00471         {
00472             DebugTotalSockets--;
00473         }
00474         slave_socket = INVALID_SOCKET;
00475     }
00476 }

void close_sockets ( bool  emergency,
char *  message 
)

Definition at line 3336 of file bsd.cpp.

References aMainGamePorts, DebugTotalSockets, DESC_SAFEITER_ALL, descriptor_data::descriptor, INVALID_SOCKET, IS_SOCKET_ERROR, log_perror(), nMainGamePorts, queue_string(), queue_write_LEN(), R_GOING_DOWN, SD_BOTH, shutdownsock(), PortInfo::socket, SOCKET_CLOSE, and SOCKET_WRITE.

Referenced by emergency_shutdown(), and main().

03337 {
03338     DESC *d, *dnext;
03339 
03340     DESC_SAFEITER_ALL(d, dnext)
03341     {
03342         if (emergency)
03343         {
03344             SOCKET_WRITE(d->descriptor, message, strlen(message), 0);
03345             if (IS_SOCKET_ERROR(shutdown(d->descriptor, SD_BOTH)))
03346             {
03347                 log_perror("NET", "FAIL", NULL, "shutdown");
03348             }
03349             if (SOCKET_CLOSE(d->descriptor) == 0)
03350             {
03351                 DebugTotalSockets--;
03352             }
03353         }
03354         else
03355         {
03356             queue_string(d, message);
03357             queue_write_LEN(d, "\r\n", 2);
03358             shutdownsock(d, R_GOING_DOWN);
03359         }
03360     }
03361     for (int i = 0; i < nMainGamePorts; i++)
03362     {
03363         if (SOCKET_CLOSE(aMainGamePorts[i].socket) == 0)
03364         {
03365             DebugTotalSockets--;
03366         }
03367         aMainGamePorts[i].socket = INVALID_SOCKET;
03368     }
03369 }

static void config_socket ( SOCKET  s  )  [static]

Definition at line 2202 of file bsd.cpp.

References make_nolinger(), and make_nonblocking().

Referenced by initializesock().

02203 {
02204     make_nonblocking(s);
02205     make_nolinger(s);
02206 }

static bool DesiredHimOption ( DESC d,
unsigned char  chOption 
) [static]

Determine whether we want a particular option on his side of the link to be enabled.

Parameters:
d Player connection context.
chOption Telnet Option.
Returns:
Yes if we want it enabled.

Definition at line 2797 of file bsd.cpp.

References TELNET_EOR, TELNET_NAWS, TELNET_SGA, and UNUSED_PARAMETER.

Referenced by process_input_helper().

02798 {
02799     UNUSED_PARAMETER(d);
02800 
02801     if (  TELNET_NAWS == chOption
02802        || TELNET_EOR  == chOption
02803        || TELNET_SGA  == chOption)
02804     {
02805         return true;
02806     }
02807     return false;
02808 }

static bool DesiredUsOption ( DESC d,
unsigned char  chOption 
) [static]

Determine whether we want a particular option on our side of the link to be enabled.

It doesn't make sense for NAWS to be enabled on the server side, and we only negotiate SGA on our side if we have already successfully negotiated the EOR option.

Parameters:
d Player connection context.
chOption Telnet Option.
Returns:
Yes if we want it enabled.

Definition at line 2822 of file bsd.cpp.

References OPTION_YES, TELNET_EOR, TELNET_SGA, and UsState().

Referenced by process_input_helper().

02823 {
02824     if (  TELNET_EOR  == chOption
02825        || (  TELNET_SGA == chOption
02826           && OPTION_YES == UsState(d, TELNET_EOR)))
02827     {
02828         return true;
02829     }
02830     return false;
02831 }

void DisableHim ( DESC d,
unsigned char  chOption 
)

Start the process of negotiating the disablement of an option on his side.

Whether we actually send anything across the wire to disable this depends on the negotiation state. The option could potentially already be disabled.

Parameters:
d Player connection context.
chOption Telnet Option.
Returns:
None.

Definition at line 2874 of file bsd.cpp.

References HimState(), OPTION_WANTNO_EMPTY, OPTION_WANTNO_OPPOSITE, OPTION_WANTYES_EMPTY, OPTION_WANTYES_OPPOSITE, OPTION_YES, SendDont(), and SetHimState().

02875 {
02876     switch (HimState(d, chOption))
02877     {
02878     case OPTION_YES:
02879         SetHimState(d, chOption, OPTION_WANTNO_EMPTY);
02880         SendDont(d, chOption);
02881         break;
02882 
02883     case OPTION_WANTNO_OPPOSITE:
02884         SetHimState(d, chOption, OPTION_WANTNO_EMPTY);
02885         break;
02886 
02887     case OPTION_WANTYES_EMPTY:
02888         SetHimState(d, chOption, OPTION_WANTYES_OPPOSITE);
02889         break;
02890     }
02891 }

void DisableUs ( DESC d,
unsigned char  chOption 
)

Start the process of negotiating the disablement of an option on our side.

Whether we actually send anything across the wire to disable this depends on the negotiation state. The option could potentially already be disabled.

Parameters:
d Player connection context.
chOption Telnet Option.
Returns:
None.

Definition at line 2934 of file bsd.cpp.

References HimState(), OPTION_WANTNO_EMPTY, OPTION_WANTNO_OPPOSITE, OPTION_WANTYES_EMPTY, OPTION_WANTYES_OPPOSITE, OPTION_YES, SendWont(), and SetUsState().

Referenced by SetUsState().

02935 {
02936     switch (HimState(d, chOption))
02937     {
02938     case OPTION_YES:
02939         SetUsState(d, chOption, OPTION_WANTNO_EMPTY);
02940         SendWont(d, chOption);
02941         break;
02942 
02943     case OPTION_WANTNO_OPPOSITE:
02944         SetUsState(d, chOption, OPTION_WANTNO_EMPTY);
02945         break;
02946 
02947     case OPTION_WANTYES_EMPTY:
02948         SetUsState(d, chOption, OPTION_WANTYES_OPPOSITE);
02949         break;
02950     }
02951 }

void emergency_shutdown ( void   ) 

Definition at line 3371 of file bsd.cpp.

References close_sockets().

Referenced by do_shutdown().

03372 {
03373     close_sockets(true, "Going down - Bye");
03374 }

void EnableHim ( DESC d,
unsigned char  chOption 
)

Start the process of negotiating the enablement of an option on his side.

Whether we actually send anything across the wire to enable this depends on the negotiation state. The option could potentially already be enabled.

Parameters:
d Player connection context.
chOption Telnet Option.
Returns:
None.

Definition at line 2844 of file bsd.cpp.

References HimState(), OPTION_NO, OPTION_WANTNO_EMPTY, OPTION_WANTNO_OPPOSITE, OPTION_WANTYES_EMPTY, OPTION_WANTYES_OPPOSITE, SendDo(), and SetHimState().

Referenced by TelnetSetup().

02845 {
02846     switch (HimState(d, chOption))
02847     {
02848     case OPTION_NO:
02849         SetHimState(d, chOption, OPTION_WANTYES_EMPTY);
02850         SendDo(d, chOption);
02851         break;
02852 
02853     case OPTION_WANTNO_EMPTY:
02854         SetHimState(d, chOption, OPTION_WANTNO_OPPOSITE);
02855         break;
02856 
02857     case OPTION_WANTYES_OPPOSITE:
02858         SetHimState(d, chOption, OPTION_WANTYES_EMPTY);
02859         break;
02860     }
02861 }

void EnableUs ( DESC d,
unsigned char  chOption 
)

Start the process of negotiating the enablement of an option on our side.

Whether we actually send anything across the wire to enable this depends on the negotiation state. The option could potentially already be enabled.

Parameters:
d Player connection context.
chOption Telnet Option.
Returns:
None.

Definition at line 2904 of file bsd.cpp.

References HimState(), OPTION_NO, OPTION_WANTNO_EMPTY, OPTION_WANTNO_OPPOSITE, OPTION_WANTYES_EMPTY, OPTION_WANTYES_OPPOSITE, SendWill(), and SetUsState().

Referenced by SetUsState(), and TelnetSetup().

02905 {
02906     switch (HimState(d, chOption))
02907     {
02908     case OPTION_NO:
02909         SetUsState(d, chOption, OPTION_WANTYES_EMPTY);
02910         SendWill(d, chOption);
02911         break;
02912 
02913     case OPTION_WANTNO_EMPTY:
02914         SetUsState(d, chOption, OPTION_WANTNO_OPPOSITE);
02915         break;
02916 
02917     case OPTION_WANTYES_OPPOSITE:
02918         SetUsState(d, chOption, OPTION_WANTYES_EMPTY);
02919         break;
02920     }
02921 }

static int get_slave_result ( void   )  [static]

Definition at line 806 of file bsd.cpp.

References A_LASTIP, A_LASTSITE, descriptor_data::addr, descriptor_data::address, alloc_lbuf, atr_add_raw(), CleanUpSlaveProcess(), CleanUpSlaveSocket(), descriptor_list, ENDLOG, free_lbuf, LBUF_SIZE, LOG_ALWAYS, log_text(), mudconf, descriptor_data::next, descriptor_data::player, slave_socket, SOCKET_EWOULDBLOCK, SOCKET_LAST_ERROR, STARTLOG, tprintf(), confdata::use_hostname, and descriptor_data::username.

Referenced by shovechars().

00807 {
00808     int local_port, remote_port;
00809     DESC *d;
00810 
00811     char *buf = alloc_lbuf("slave_buf");
00812 
00813     int len = read(slave_socket, buf, LBUF_SIZE-1);
00814     if (len < 0)
00815     {
00816         int iSocketError = SOCKET_LAST_ERROR;
00817         if (  iSocketError == SOCKET_EAGAIN
00818            || iSocketError == SOCKET_EWOULDBLOCK)
00819         {
00820             free_lbuf(buf);
00821             return -1;
00822         }
00823         CleanUpSlaveSocket();
00824         CleanUpSlaveProcess();
00825         free_lbuf(buf);
00826 
00827         STARTLOG(LOG_ALWAYS, "NET", "SLAVE");
00828         log_text("read() of slave result failed. Slave stopped.");
00829         ENDLOG;
00830 
00831         return -1;
00832     }
00833     else if (len == 0)
00834     {
00835         free_lbuf(buf);
00836         return -1;
00837     }
00838     buf[len] = '\0';
00839 
00840     char *token = alloc_lbuf("slave_token");
00841     char *os = alloc_lbuf("slave_os");
00842     char *userid = alloc_lbuf("slave_userid");
00843     char *host = alloc_lbuf("slave_host");
00844     char *p;
00845     if (sscanf(buf, "%s %s", host, token) != 2)
00846     {
00847         goto Done;
00848     }
00849     p = strchr(buf, '\n');
00850     *p = '\0';
00851     if (mudconf.use_hostname)
00852     {
00853         for (d = descriptor_list; d; d = d->next)
00854         {
00855             if (strcmp(d->addr, host) != 0)
00856             {
00857                 continue;
00858             }
00859 
00860             strncpy(d->addr, token, 50);
00861             d->addr[50] = '\0';
00862             if (d->player != 0)
00863             {
00864                 if (d->username[0])
00865                 {
00866                     atr_add_raw(d->player, A_LASTSITE, tprintf("%s@%s",
00867                         d->username, d->addr));
00868                 }
00869                 else
00870                 {
00871                     atr_add_raw(d->player, A_LASTSITE, d->addr);
00872                 }
00873                 atr_add_raw(d->player, A_LASTIP, inet_ntoa((d->address).sin_addr));
00874             }
00875         }
00876     }
00877 
00878     if (sscanf(p + 1, "%s %d , %d : %s : %s : %s",
00879            host,
00880            &remote_port, &local_port,
00881            token, os, userid) != 6)
00882     {
00883         goto Done;
00884     }
00885     for (d = descriptor_list; d; d = d->next)
00886     {
00887         if (ntohs((d->address).sin_port) != remote_port)
00888             continue;
00889         strncpy(d->username, userid, 10);
00890         d->username[10] = '\0';
00891         if (d->player != 0)
00892         {
00893             atr_add_raw(d->player, A_LASTSITE, tprintf("%s@%s",
00894                              d->username, d->addr));
00895         }
00896     }
00897 Done:
00898     free_lbuf(buf);
00899     free_lbuf(token);
00900     free_lbuf(os);
00901     free_lbuf(userid);
00902     free_lbuf(host);
00903     return 0;
00904 }

int HimState ( DESC d,
unsigned char  chOption 
)

Return the other side's negotiation state.

The negotiation of each optional feature of telnet can be in one of six states (defined in interface.h): OPTION_NO, OPTION_YES, OPTION_WANTNO_EMPTY, OPTION_WANTNO_OPPOSITE, OPTION_WANTYES_EMPTY, and OPTION_WANTYES_OPPOSITE.

An option is only enabled when it is in the OPTION_YES state.

Parameters:
d Player connection context.
chOption Telnet Option
Returns:
One of six states.

Definition at line 2629 of file bsd.cpp.

References descriptor_data::nvt_eor_him_state, descriptor_data::nvt_naws_him_state, descriptor_data::nvt_sga_him_state, OPTION_NO, TELNET_EOR, TELNET_NAWS, and TELNET_SGA.

Referenced by DisableHim(), DisableUs(), EnableHim(), EnableUs(), and process_input_helper().

02630 {
02631     if (TELNET_NAWS == chOption)
02632     {
02633         return d->nvt_naws_him_state;
02634     }
02635     else if (TELNET_EOR == chOption)
02636     {
02637         return d->nvt_eor_him_state;
02638     }
02639     else if (TELNET_SGA == chOption)
02640     {
02641         return d->nvt_sga_him_state;
02642     }
02643     return OPTION_NO;
02644 }

DESC * initializesock ( SOCKET  ,
struct sockaddr_in *   
) [static]

Definition at line 2210 of file bsd.cpp.

References statedata::access_list, descriptor_data::addr, descriptor_data::address, alloc_desc, confdata::cmd_quota_max, descriptor_data::command_count, config_socket(), descriptor_data::connected_at, descriptor_data::descriptor, descriptor_list, descriptor_data::doing, descriptor_data::flags, CLinearTimeAbsolute::GetUTC(), descriptor_data::hashnext, descriptor_data::height, descriptor_data::host_info, confdata::idle_timeout, descriptor_data::input_head, descriptor_data::input_lost, descriptor_data::input_size, descriptor_data::input_tail, descriptor_data::input_tot, descriptor_data::last_time, mudconf, mudstate, ndescriptors, descriptor_data::next, descriptor_data::nOption, descriptor_data::nvt_eor_him_state, descriptor_data::nvt_eor_us_state, NVT_IS_NORMAL, descriptor_data::nvt_naws_him_state, descriptor_data::nvt_naws_us_state, descriptor_data::nvt_sga_him_state, descriptor_data::nvt_sga_us_state, OPTION_NO, descriptor_data::output_head, descriptor_data::output_lost, descriptor_data::output_prefix, descriptor_data::output_size, descriptor_data::output_suffix, descriptor_data::output_tail, descriptor_data::output_tot, descriptor_data::player, descriptor_data::prev, descriptor_data::program_data, descriptor_data::quota, descriptor_data::raw_input, descriptor_data::raw_input_at, descriptor_data::raw_input_state, descriptor_data::retries_left, confdata::retry_limit, site_check(), statedata::suspect_list, descriptor_data::timeout, descriptor_data::username, and descriptor_data::width.

Referenced by new_connection().

02211 {
02212     DESC *d;
02213 
02214 #ifdef WIN32
02215     // protect adding the descriptor from the linked list from
02216     // any interference from socket shutdowns
02217     //
02218     if (platform == VER_PLATFORM_WIN32_NT)
02219     {
02220         EnterCriticalSection(&csDescriptorList);
02221     }
02222 #endif // WIN32
02223 
02224     d = alloc_desc("init_sock");
02225 
02226 #ifdef WIN32
02227     if (platform == VER_PLATFORM_WIN32_NT)
02228     {
02229         LeaveCriticalSection(&csDescriptorList);
02230     }
02231 #endif // WIN32
02232 
02233     d->descriptor = s;
02234     d->flags = 0;
02235     d->connected_at.GetUTC();
02236     d->last_time = d->connected_at;
02237     d->retries_left = mudconf.retry_limit;
02238     d->command_count = 0;
02239     d->timeout = mudconf.idle_timeout;
02240     d->host_info = site_check((*a).sin_addr, mudstate.access_list)
02241                  | site_check((*a).sin_addr, mudstate.suspect_list);
02242 
02243     // Be sure #0 isn't wizard. Shouldn't be.
02244     //
02245     d->player = 0;
02246 
02247     d->addr[0] = '\0';
02248     d->doing[0] = '\0';
02249     d->username[0] = '\0';
02250     config_socket(s);
02251     d->output_prefix = NULL;
02252     d->output_suffix = NULL;
02253     d->output_size = 0;
02254     d->output_tot = 0;
02255     d->output_lost = 0;
02256     d->output_head = NULL;
02257     d->output_tail = NULL;
02258     d->input_head = NULL;
02259     d->input_tail = NULL;
02260     d->input_size = 0;
02261     d->input_tot = 0;
02262     d->input_lost = 0;
02263     d->raw_input = NULL;
02264     d->raw_input_at = NULL;
02265     d->nOption = 0;
02266     d->raw_input_state = NVT_IS_NORMAL;
02267     d->nvt_sga_him_state = OPTION_NO;
02268     d->nvt_sga_us_state = OPTION_NO;
02269     d->nvt_eor_him_state = OPTION_NO;
02270     d->nvt_eor_us_state = OPTION_NO;
02271     d->nvt_naws_him_state = OPTION_NO;
02272     d->nvt_naws_us_state = OPTION_NO;
02273     d->height = 24;
02274     d->width = 78;
02275     d->quota = mudconf.cmd_quota_max;
02276     d->program_data = NULL;
02277     d->address = *a;
02278     strncpy(d->addr, inet_ntoa(a->sin_addr), 50);
02279     d->addr[50] = '\0';
02280 
02281 #ifdef WIN32
02282     // protect adding the descriptor from the linked list from
02283     // any interference from socket shutdowns
02284     //
02285     if (platform == VER_PLATFORM_WIN32_NT)
02286     {
02287         EnterCriticalSection (&csDescriptorList);
02288     }
02289 #endif // WIN32
02290 
02291     ndescriptors++;
02292 
02293     if (descriptor_list)
02294     {
02295         descriptor_list->prev = &d->next;
02296     }
02297     d->hashnext = NULL;
02298     d->next = descriptor_list;
02299     d->prev = &descriptor_list;
02300     descriptor_list = d;
02301 
02302 #ifdef WIN32
02303     // ok to continue now
02304     //
02305     if (platform == VER_PLATFORM_WIN32_NT)
02306     {
02307         LeaveCriticalSection (&csDescriptorList);
02308 
02309         d->OutboundOverlapped.hEvent = NULL;
02310         d->InboundOverlapped.hEvent = NULL;
02311         d->InboundOverlapped.Offset = 0;
02312         d->InboundOverlapped.OffsetHigh = 0;
02313         d->bWritePending = false;   // no write pending yet
02314         d->bConnectionShutdown = false; // not shutdown yet
02315         d->bConnectionDropped = false; // not dropped yet
02316         d->bCallProcessOutputLater = false;
02317     }
02318 #endif // WIN32
02319     return d;
02320 }

void list_system_resources ( dbref  player  ) 

Definition at line 4070 of file bsd.cpp.

References DebugTotalFiles, DebugTotalSockets, and notify.

Referenced by do_list().

04071 {
04072     char buffer[80];
04073 
04074     int nTotal = 0;
04075     notify(player, "System Resources");
04076 
04077     sprintf(buffer, "Total Open Files: %ld", DebugTotalFiles);
04078     notify(player, buffer);
04079     nTotal += DebugTotalFiles;
04080 
04081     sprintf(buffer, "Total Sockets: %ld", DebugTotalSockets);
04082     notify(player, buffer);
04083     nTotal += DebugTotalSockets;
04084 
04085 #ifdef WIN32
04086     sprintf(buffer, "Total Threads: %ld", DebugTotalThreads);
04087     notify(player, buffer);
04088     nTotal += DebugTotalThreads;
04089 
04090     sprintf(buffer, "Total Semaphores: %ld", DebugTotalSemaphores);
04091     notify(player, buffer);
04092     nTotal += DebugTotalSemaphores;
04093 #endif // WIN32
04094 
04095     sprintf(buffer, "Total Handles (sum of above): %d", nTotal);
04096     notify(player, buffer);
04097 
04098 #ifdef WIN32
04099     for (int i = 0; i < NUM_SLAVE_THREADS; i++)
04100     {
04101         sprintf(buffer, "Thread %d at line %u", i+1, SlaveThreadInfo[i].iDoing);
04102         notify(player, buffer);
04103     }
04104 #endif // WIN32
04105 }

static void log_signal ( int  iSignal  )  [static]

Definition at line 3708 of file bsd.cpp.

References ENDLOG, LOG_PROBLEMS, log_text(), SignalDesc(), and STARTLOG.

Referenced by sighandler().

03709 {
03710     STARTLOG(LOG_PROBLEMS, "SIG", "CATCH");
03711     log_text("Caught signal ");
03712     log_text(SignalDesc(iSignal));
03713     ENDLOG;
03714 }

static void log_signal_ignore ( int  iSignal  )  [static]

Definition at line 3717 of file bsd.cpp.

References ENDLOG, LOG_PROBLEMS, log_text(), SignalDesc(), and STARTLOG.

Referenced by sighandler().

03718 {
03719     STARTLOG(LOG_PROBLEMS, "SIG", "CATCH");
03720     log_text("Caught signal and ignored signal ");
03721     log_text(SignalDesc(iSignal));
03722     log_text(" because server just came up.");
03723     ENDLOG;
03724 }

void LogStatBuf ( int  stat_buf,
const char *  Name 
)

Definition at line 3726 of file bsd.cpp.

References ENDLOG, Log, LOG_ALWAYS, log_text(), SignalDesc(), STARTLOG, and CLogFile::tinyprintf().

Referenced by sighandler().

03727 {
03728     STARTLOG(LOG_ALWAYS, "NET", Name);
03729     if (WIFEXITED(stat_buf))
03730     {
03731         Log.tinyprintf("process exited unexpectedly with exit status %d.", WEXITSTATUS(stat_buf));
03732     }
03733     else if (WIFSIGNALED(stat_buf))
03734     {
03735         Log.tinyprintf("process was terminated with signal %s.", SignalDesc(WTERMSIG(stat_buf)));
03736     }
03737     else
03738     {
03739         log_text("process ended unexpectedly.");
03740     }
03741     ENDLOG;
03742 }

static void make_nolinger ( SOCKET  s  )  [static]

Definition at line 2189 of file bsd.cpp.

References IS_SOCKET_ERROR, and log_perror().

Referenced by config_socket().

02190 {
02191 #if defined(HAVE_LINGER)
02192     struct linger ling;
02193     ling.l_onoff = 0;
02194     ling.l_linger = 0;
02195     if (IS_SOCKET_ERROR(setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling))))
02196     {
02197         log_perror("NET", "FAIL", "linger", "setsockopt");
02198     }
02199 #endif // HAVE_LINGER
02200 }

int make_nonblocking ( SOCKET  s  )  [static]

Definition at line 2149 of file bsd.cpp.

References IS_SOCKET_ERROR, and log_perror().

Referenced by boot_slave(), and config_socket().

02150 {
02151 #ifdef WIN32
02152     unsigned long on = 1;
02153     if (IS_SOCKET_ERROR(ioctlsocket(s, FIONBIO, &on)))
02154     {
02155         log_perror("NET", "FAIL", "make_nonblocking", "ioctlsocket");
02156         return -1;
02157     }
02158 #else // WIN32
02159 #if defined(O_NONBLOCK)
02160     if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
02161     {
02162         log_perror("NET", "FAIL", "make_nonblocking", "fcntl");
02163         return -1;
02164     }
02165 #elif defined(FNDELAY)
02166     if (fcntl(s, F_SETFL, FNDELAY) < 0)
02167     {
02168         log_perror("NET", "FAIL", "make_nonblocking", "fcntl");
02169         return -1;
02170     }
02171 #elif defined(O_NDELAY)
02172     if (fcntl(s, F_SETFL, O_NDELAY) < 0)
02173     {
02174         log_perror("NET", "FAIL", "make_nonblocking", "fcntl");
02175         return -1;
02176     }
02177 #elif defined(FIONBIO)
02178     unsigned long on = 1;
02179     if (ioctl(s, FIONBIO, &on) < 0)
02180     {
02181         log_perror("NET", "FAIL", "make_nonblocking", "ioctl");
02182         return -1;
02183     }
02184 #endif // O_NONBLOCK, FNDELAY, O_NDELAY, FIONBIO
02185 #endif // WIN32
02186     return 0;
02187 }

static void make_socket ( PortInfo Port  )  [static]

Definition at line 907 of file bsd.cpp.

References DebugTotalSockets, ENDLINE, INVALID_HANDLE_VALUE, INVALID_SOCKET, IS_INVALID_SOCKET, IS_SOCKET_ERROR, Log, log_perror(), PortInfo::port, PortInfo::socket, SOCKET_CLOSE, SOCKET_LAST_ERROR, and CLogFile::tinyprintf().

00908 {
00909     SOCKET s;
00910     struct sockaddr_in server;
00911     int opt = 1;
00912 
00913 #ifdef WIN32
00914 
00915     // If we are running Windows NT we must create a completion port,
00916     // and start up a listening thread for new connections
00917     //
00918     if (platform == VER_PLATFORM_WIN32_NT)
00919     {
00920         int nRet;
00921 
00922         // create initial IO completion port, so threads have something to wait on
00923         //
00924         CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
00925 
00926         if (!CompletionPort)
00927         {
00928             Log.tinyprintf("Error %ld on CreateIoCompletionPort" ENDLINE,  GetLastError());
00929             WSACleanup();     // clean up
00930             exit(1);
00931         }
00932 
00933         // Initialize the critical section
00934         //
00935         if (!bDescriptorListInit)
00936         {
00937             InitializeCriticalSection(&csDescriptorList);
00938             bDescriptorListInit = true;
00939         }
00940 
00941         // Create a TCP/IP stream socket
00942         //
00943         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00944         if (s == INVALID_SOCKET)
00945         {
00946             log_perror("NET", "FAIL", NULL, "creating master socket");
00947             exit(3);
00948         }
00949         DebugTotalSockets++;
00950         if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0)
00951         {
00952             log_perror("NET", "FAIL", NULL, "setsockopt");
00953         }
00954 
00955         // Fill in the the address structure
00956         //
00957         server.sin_port = htons((unsigned short)(Port->port));
00958         server.sin_family = AF_INET;
00959         server.sin_addr.s_addr = INADDR_ANY;
00960 
00961         // bind our name to the socket
00962         //
00963         nRet = bind(s, (LPSOCKADDR) &server, sizeof server);
00964 
00965         if (nRet == SOCKET_ERROR)
00966         {
00967             Log.tinyprintf("Error %ld on Win32: bind" ENDLINE, SOCKET_LAST_ERROR);
00968             if (closesocket(s) == 0)
00969             {
00970                 DebugTotalSockets--;
00971             }
00972             s = INVALID_SOCKET;
00973             WSACleanup();     // clean up
00974             exit(1);
00975         }
00976 
00977         // Set the socket to listen
00978         //
00979         nRet = listen(s, SOMAXCONN);
00980 
00981         if (nRet)
00982         {
00983             Log.tinyprintf("Error %ld on Win32: listen" ENDLINE, SOCKET_LAST_ERROR);
00984             WSACleanup();
00985             exit(1);
00986         }
00987 
00988         // Create the MUD listening thread
00989         //
00990         if (_beginthread(MUDListenThread, 0, (void *) Port) == (unsigned)(-1))
00991         {
00992             log_perror("NET", "FAIL", "_beginthread", "setsockopt");
00993             WSACleanup();
00994             exit(1);
00995         }
00996 
00997         Port->socket = s;
00998         Log.tinyprintf("Listening (NT-style) on port %d" ENDLINE, Port->port);
00999         return;
01000     }
01001 #endif // WIN32
01002 
01003     s = socket(AF_INET, SOCK_STREAM, 0);
01004     if (IS_INVALID_SOCKET(s))
01005     {
01006         log_perror("NET", "FAIL", NULL, "creating master socket");
01007 #ifdef WIN32
01008         WSACleanup();
01009 #endif // WIN32
01010         exit(3);
01011     }
01012     DebugTotalSockets++;
01013     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0)
01014     {
01015         log_perror("NET", "FAIL", NULL, "setsockopt");
01016     }
01017     server.sin_family = AF_INET;
01018     server.sin_addr.s_addr = INADDR_ANY;
01019     server.sin_port = htons((unsigned short)(Port->port));
01020     int cc  = bind(s, (struct sockaddr *)&server, sizeof(server));
01021     if (IS_SOCKET_ERROR(cc))
01022     {
01023         log_perror("NET", "FAIL", NULL, "bind");
01024         if (SOCKET_CLOSE(s) == 0)
01025         {
01026             DebugTotalSockets--;
01027         }
01028         s = INVALID_SOCKET;
01029 #ifdef WIN32
01030         WSACleanup();
01031 #endif // WIN32
01032         exit(4);
01033     }
01034     listen(s, SOMAXCONN);
01035     Port->socket = s;
01036     Log.tinyprintf("Listening on port %d" ENDLINE, Port->port);
01037 }

DESC * new_connection ( PortInfo Port,
int *  piError 
) [static]

Definition at line 1677 of file bsd.cpp.

References statedata::access_list, alloc_lbuf, alloc_mbuf, CleanUpSlaveProcess(), CleanUpSlaveSocket(), statedata::debug_cmd, DebugTotalSockets, ENDLOG, FC_CONN_SITE, fcache_rawdump(), free_lbuf, free_mbuf, H_FORBIDDEN, initializesock(), INVALID_SOCKET, IS_INVALID_SOCKET, LOG_ALWAYS, LOG_NET, LOG_SECURITY, log_text(), mudconf, mudstate, PortInfo::port, SD_BOTH, site_check(), SiteMonSend(), slave_socket, PortInfo::socket, SOCKET_CLOSE, SOCKET_LAST_ERROR, STARTLOG, TelnetSetup(), confdata::use_hostname, and welcome_user().

Referenced by shovechars().

01678 {
01679     DESC *d;
01680     struct sockaddr_in addr;
01681 #ifdef SOCKLEN_T_DCL
01682     socklen_t addr_len;
01683 #else // SOCKLEN_T_DCL
01684     int addr_len;
01685 #endif // SOCKLEN_T_DCL
01686 #ifndef WIN32
01687     int len;
01688 #endif // !WIN32
01689 
01690     char *cmdsave = mudstate.debug_cmd;
01691     mudstate.debug_cmd = "< new_connection >";
01692     addr_len = sizeof(struct sockaddr);
01693 
01694     SOCKET newsock = accept(Port->socket, (struct sockaddr *)&addr, &addr_len);
01695 
01696     if (IS_INVALID_SOCKET(newsock))
01697     {
01698         *piSocketError = SOCKET_LAST_ERROR;
01699         return 0;
01700     }
01701 
01702     char *pBuffM2 = alloc_mbuf("new_connection.address");
01703     strcpy(pBuffM2, inet_ntoa(addr.sin_addr));
01704     unsigned short usPort = ntohs(addr.sin_port);
01705 
01706     DebugTotalSockets++;
01707     if (site_check(addr.sin_addr, mudstate.access_list) == H_FORBIDDEN)
01708     {
01709         STARTLOG(LOG_NET | LOG_SECURITY, "NET", "SITE");
01710         char *pBuffM1  = alloc_mbuf("new_connection.LOG.badsite");
01711         sprintf(pBuffM1, "[%u/%s] Connection refused.  (Remote port %d)",
01712             newsock, pBuffM2, usPort);
01713         log_text(pBuffM1);
01714         free_mbuf(pBuffM1);
01715         ENDLOG;
01716 
01717         // Report site monitor information.
01718         //
01719         SiteMonSend(newsock, pBuffM2, NULL, "Connection refused");
01720 
01721         fcache_rawdump(newsock, FC_CONN_SITE);
01722         shutdown(newsock, SD_BOTH);
01723         if (SOCKET_CLOSE(newsock) == 0)
01724         {
01725             DebugTotalSockets--;
01726         }
01727         newsock = INVALID_SOCKET;
01728         errno = 0;
01729         d = NULL;
01730     }
01731     else
01732     {
01733 #ifdef WIN32
01734         // Make slave request
01735         //
01736         // Go take control of the stack, but don't bother if it takes
01737         // longer than 5 seconds to do it.
01738         //
01739         if (  bSlaveBooted
01740            && WAIT_OBJECT_0 == WaitForSingleObject(hSlaveRequestStackSemaphore, 5000))
01741         {
01742             // We have control of the stack. Skip the request if the stack is full.
01743             //
01744             if (iSlaveRequest < SLAVE_REQUEST_STACK_SIZE)
01745             {
01746                 // There is room on the stack, so make the request.
01747                 //
01748                 SlaveRequests[iSlaveRequest].sa_in = addr;
01749                 SlaveRequests[iSlaveRequest].port_in = Port->port;
01750                 iSlaveRequest++;
01751                 ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL);
01752 
01753                 // Wake up a single slave thread. Event automatically resets itself.
01754                 //
01755                 ReleaseSemaphore(hSlaveThreadsSemaphore, 1, NULL);
01756             }
01757             else
01758             {
01759                 // No room on the stack, so skip it.
01760                 //
01761                 ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL);
01762             }
01763         }
01764 #else // WIN32
01765         // Make slave request
01766         //
01767         if (  !IS_INVALID_SOCKET(slave_socket)
01768            && mudconf.use_hostname)
01769         {
01770             char *pBuffL1 = alloc_lbuf("new_connection.write");
01771             sprintf(pBuffL1, "%s\n%s,%d,%d\n", pBuffM2, pBuffM2, usPort,
01772                 Port->port);
01773             len = strlen(pBuffL1);
01774             if (write(slave_socket, pBuffL1, len) < 0)
01775             {
01776                 CleanUpSlaveSocket();
01777                 CleanUpSlaveProcess();
01778 
01779                 STARTLOG(LOG_ALWAYS, "NET", "SLAVE");
01780                 log_text("write() of slave request failed. Slave stopped.");
01781                 ENDLOG;
01782             }
01783             free_lbuf(pBuffL1);
01784         }
01785 #endif // WIN32
01786 
01787         STARTLOG(LOG_NET, "NET", "CONN");
01788         char *pBuffM3 = alloc_mbuf("new_connection.LOG.open");
01789         sprintf(pBuffM3, "[%u/%s] Connection opened (remote port %d)", newsock,
01790             pBuffM2, usPort);
01791         log_text(pBuffM3);
01792         free_mbuf(pBuffM3);
01793         ENDLOG;
01794 
01795         d = initializesock(newsock, &addr);
01796         TelnetSetup(d);
01797 
01798         // Initalize everything before sending the sitemon info, so that we
01799         // can pass the descriptor, d.
01800         //
01801         SiteMonSend(newsock, pBuffM2, d, "Connection");
01802 
01803         welcome_user(d);
01804         mudstate.debug_cmd = cmdsave;
01805     }
01806     free_mbuf(pBuffM2);
01807     mudstate.debug_cmd = cmdsave;
01808     *piSocketError = SOCKET_LAST_ERROR;
01809     return d;
01810 }

bool process_input ( DESC  )  [static]

Definition at line 3309 of file bsd.cpp.

References statedata::debug_cmd, descriptor_data::descriptor, IS_SOCKET_ERROR, LBUF_SIZE, mudstate, process_input_helper(), SOCKET_EINTR, SOCKET_EWOULDBLOCK, SOCKET_LAST_ERROR, and SOCKET_READ.

Referenced by shovechars().

03310 {
03311     char *cmdsave = mudstate.debug_cmd;
03312     mudstate.debug_cmd = "< process_input >";
03313 
03314     char buf[LBUF_SIZE];
03315     int got = SOCKET_READ(d->descriptor, buf, sizeof(buf), 0);
03316     if (IS_SOCKET_ERROR(got) || got == 0)
03317     {
03318         int iSocketError = SOCKET_LAST_ERROR;
03319         mudstate.debug_cmd = cmdsave;
03320         if (  IS_SOCKET_ERROR(got)
03321            && (  iSocketError == SOCKET_EWOULDBLOCK
03322 #ifdef SOCKET_EAGAIN
03323               || iSocketError == SOCKET_EAGAIN
03324 #endif // SOCKET_EAGAIN
03325               || iSocketError == SOCKET_EINTR))
03326         {
03327             return true;
03328         }
03329         return false;
03330     }
03331     process_input_helper(d, buf, got);
03332     mudstate.debug_cmd = cmdsave;
03333     return true;
03334 }

static void process_input_helper ( DESC d,
char *  pBytes,
int  nBytes 
) [static]

Parse raw data from network connection into command lines and Telnet indications.

Once input has been received from a particular socket, it is given to this function for initial parsing. While most clients do line editing on their side, a raw telnet client is still capable of sending backspace (BS) and Delete (DEL) to the server, so we perform basic editing on our side.

TinyMUX only allows printable characters through, imposes a maximum line length, and breaks lines at CRLF.

Parameters:
d Player connection on which the input arrived.
pBytes Point to received bytes.
nBytes Number of received bytes in above buffer.
Returns:
None.

Definition at line 2993 of file bsd.cpp.

References alloc_lbuf, descriptor_data::aOption, cmd_block::cmd, DesiredHimOption(), DesiredUsOption(), free_lbuf, descriptor_data::height, HimState(), descriptor_data::input_lost, descriptor_data::input_size, descriptor_data::input_tot, LBUF_SIZE, mux_isprint, descriptor_data::nOption, NVT_DEL, NVT_IS_HAVE_IAC, NVT_IS_HAVE_IAC_DO, NVT_IS_HAVE_IAC_DONT, NVT_IS_HAVE_IAC_SB, NVT_IS_HAVE_IAC_SB_IAC, NVT_IS_HAVE_IAC_WILL, NVT_IS_HAVE_IAC_WONT, NVT_IS_NORMAL, OPTION_NO, OPTION_WANTNO_EMPTY, OPTION_WANTNO_OPPOSITE, OPTION_WANTYES_EMPTY, OPTION_WANTYES_OPPOSITE, OPTION_YES, queue_string(), descriptor_data::raw_input, descriptor_data::raw_input_at, descriptor_data::raw_input_state, save_command(), SBUF_SIZE, SendDo(), SendDont(), SendWill(), SendWont(), SetHimState(), SetUsState(), TELNET_NAWS, UsState(), and descriptor_data::width.

Referenced by process_input().

02994 {
02995     if (!d->raw_input)
02996     {
02997         d->raw_input = (CBLK *) alloc_lbuf("process_input.raw");
02998         d->raw_input_at = d->raw_input->cmd;
02999     }
03000 
03001     int nInputBytes = 0;
03002     int nLostBytes  = 0;
03003 
03004     char *p    = d->raw_input_at;
03005     char *pend = d->raw_input->cmd + (LBUF_SIZE - sizeof(CBLKHDR) - 1);
03006 
03007     unsigned char *q    = d->aOption + d->nOption;
03008     unsigned char *qend = d->aOption + SBUF_SIZE - 1;
03009 
03010     int n = nBytes;
03011     while (n--)
03012     {
03013         unsigned char ch = (unsigned char)*pBytes;
03014         int iAction = nvt_input_action_table[d->raw_input_state][nvt_input_xlat_table[ch]];
03015         switch (iAction)
03016         {
03017         case 1:
03018             // Action 1 - Accept CHR(X).
03019             //
03020             if (mux_isprint(ch))
03021             {
03022                 if (p < pend)
03023                 {
03024                     *p++ = ch;
03025                     nInputBytes++;
03026                 }
03027                 else
03028                 {
03029                     nLostBytes++;
03030                 }
03031             }
03032             d->raw_input_state = NVT_IS_NORMAL;
03033             break;
03034 
03035         case 0:
03036             // Action 0 - Nothing.
03037             //
03038             break;
03039 
03040         case 2:
03041             // Action 2 - Erase Character.
03042             //
03043             if (NVT_DEL == ch)
03044             {
03045                 queue_string(d, "\b \b");
03046             }
03047             else
03048             {
03049                 queue_string(d, " \b");
03050             }
03051 
03052             if (p > d->raw_input->cmd)
03053             {
03054                 // The character we took back.
03055                 //
03056                 nInputBytes -= 1;
03057                 p--;
03058             }
03059             d->raw_input_state = NVT_IS_NORMAL;
03060             break;
03061 
03062         case 3:
03063             // Action  3 - Accept Line.
03064             //
03065             *p = '\0';
03066             if (d->raw_input->cmd < p)
03067             {
03068                 save_command(d, d->raw_input);
03069                 d->raw_input = (CBLK *) alloc_lbuf("process_input.raw");
03070 
03071                 p = d->raw_input_at = d->raw_input->cmd;
03072                 pend = d->raw_input->cmd + (LBUF_SIZE - sizeof(CBLKHDR) - 1);
03073             }
03074             break;
03075 
03076         case 4:
03077             // Action 4 - Transition to the Normal state.
03078             //
03079             d->raw_input_state = NVT_IS_NORMAL;
03080             break;
03081 
03082         case 5:
03083             // Action  5 - Transition to Have_IAC state.
03084             //
03085             d->raw_input_state = NVT_IS_HAVE_IAC;
03086             break;
03087 
03088         case 6:
03089             // Action 6 - Transition to the Have_IAC_WILL state.
03090             //
03091             d->raw_input_state = NVT_IS_HAVE_IAC_WILL;
03092             break;
03093 
03094         case 7:
03095             // Action  7 - Transition to the Have_IAC_DONT state.
03096             //
03097             d->raw_input_state = NVT_IS_HAVE_IAC_DONT;
03098             break;
03099 
03100         case 8:
03101             // Action  8 - Transition to the Have_IAC_DO state.
03102             //
03103             d->raw_input_state = NVT_IS_HAVE_IAC_DO;
03104             break;
03105 
03106         case 9:
03107             // Action  9 - Transition to the Have_IAC_WONT state.
03108             //
03109             d->raw_input_state = NVT_IS_HAVE_IAC_WONT;
03110             break;
03111 
03112         case 10:
03113             // Action 10 - Transition to the Have_IAC_SB state.
03114             //
03115             q = d->aOption;
03116             d->raw_input_state = NVT_IS_HAVE_IAC_SB;
03117             break;
03118 
03119         case 11:
03120             // Action 11 - Transition to the Have_IAC_SB_IAC state.
03121             //
03122             d->raw_input_state = NVT_IS_HAVE_IAC_SB_IAC;
03123             break;
03124 
03125         case 12:
03126             // Action 12 - Respond to IAC AYT and return to the Normal state.
03127             //
03128             queue_string(d, "\r\n[Yes]\r\n");
03129             d->raw_input_state = NVT_IS_NORMAL;
03130             break;
03131 
03132         case 13:
03133             // Action 13 - Respond to IAC WILL X
03134             //
03135             switch (HimState(d, ch))
03136             {
03137             case OPTION_NO:
03138                 if (DesiredHimOption(d, ch))
03139                 {
03140                     SetHimState(d, ch, OPTION_YES);
03141                     SendDo(d, ch);
03142                 }
03143                 else
03144                 {
03145                     SendDont(d, ch);
03146                 }
03147                 break;
03148 
03149             case OPTION_WANTNO_EMPTY:
03150                 SetHimState(d, ch, OPTION_NO);
03151                 break;
03152 
03153             case OPTION_WANTYES_OPPOSITE:
03154                 SetHimState(d, ch, OPTION_WANTNO_EMPTY);
03155                 SendDont(d, ch);
03156                 break;
03157 
03158             default:
03159                 SetHimState(d, ch, OPTION_YES);
03160                 break;
03161             }
03162             d->raw_input_state = NVT_IS_NORMAL;
03163             break;
03164 
03165         case 14:
03166             // Action 14 - Respond to IAC DONT X
03167             //
03168             switch (UsState(d, ch))
03169             {
03170             case OPTION_YES:
03171                 SetUsState(d, ch, OPTION_NO);
03172                 SendWont(d, ch);
03173                 break;
03174 
03175             case OPTION_WANTNO_OPPOSITE:
03176                 SetUsState(d, ch, OPTION_WANTYES_EMPTY);
03177                 SendWill(d, ch);
03178                 break;
03179 
03180             default:
03181                 SetUsState(d, ch, OPTION_NO);
03182                 break;
03183             }
03184             d->raw_input_state = NVT_IS_NORMAL;
03185             break;
03186 
03187         case 15:
03188             // Action 15 - Respond to IAC DO X
03189             //
03190             switch (UsState(d, ch))
03191             {
03192             case OPTION_NO:
03193                 if (DesiredUsOption(d, ch))
03194                 {
03195                     SetUsState(d, ch, OPTION_YES);
03196                     SendWill(d, ch);
03197                 }
03198                 else
03199                 {
03200                     SendWont(d, ch);
03201                 }
03202                 break;
03203 
03204             case OPTION_WANTNO_EMPTY:
03205                 SetUsState(d, ch, OPTION_NO);
03206                 break;
03207 
03208             case OPTION_WANTYES_OPPOSITE:
03209                 SetUsState(d, ch, OPTION_WANTNO_EMPTY);
03210                 SendWont(d, ch);
03211                 break;
03212 
03213             default:
03214                 SetUsState(d, ch, OPTION_YES);
03215                 break;
03216             }
03217             d->raw_input_state = NVT_IS_NORMAL;
03218             break;
03219 
03220         case 16:
03221             // Action 16 - Respond to IAC WONT X
03222             //
03223             // Ignore.
03224             //
03225             switch (HimState(d, ch))
03226             {
03227             case OPTION_NO:
03228                 break;
03229 
03230             case OPTION_YES:
03231                 SetHimState(d, ch, OPTION_NO);
03232                 SendDont(d, ch);
03233                 break;
03234 
03235             case OPTION_WANTNO_OPPOSITE:
03236                 SetHimState(d, ch, OPTION_WANTYES_EMPTY);
03237                 SendDo(d, ch);
03238                 break;
03239 
03240             default:
03241                 SetHimState(d, ch, OPTION_NO);
03242                 break;
03243             }
03244             d->raw_input_state = NVT_IS_NORMAL;
03245             break;
03246 
03247         case 17:
03248             // Action 17 - Accept CHR(X) for Sub-Option (and transition to Have_IAC_SB state).
03249             //
03250             d->raw_input_state = NVT_IS_HAVE_IAC_SB;
03251             if (  d->aOption <= q
03252                && q < qend)
03253             {
03254                 *q++ = ch;
03255             }
03256             break;
03257 
03258         case 18:
03259             // Action 18 - Accept Completed Sub-option and transition to Normal state.
03260             //
03261             if (  d->aOption < q
03262                && q < qend)
03263             {
03264                 size_t m = q - d->aOption;
03265                 switch (d->aOption[0])
03266                 {
03267                 case TELNET_NAWS:
03268                     if (m == 5)
03269                     {
03270                         d->width  = (d->aOption[1] << 8 ) | d->aOption[2];
03271                         d->height = (d->aOption[3] << 8 ) | d->aOption[4];
03272                     }
03273                     break;
03274                 }
03275             }
03276             q = d->aOption;
03277             d->raw_input_state = NVT_IS_NORMAL;
03278             break;
03279         }
03280         pBytes++;
03281     }
03282 
03283     if (  d->raw_input->cmd < p
03284        && p <= pend)
03285     {
03286         d->raw_input_at = p;
03287     }
03288     else
03289     {
03290         free_lbuf(d->raw_input);
03291         d->raw_input = NULL;
03292         d->raw_input_at = NULL;
03293     }
03294 
03295     if ( d->aOption <= q
03296        && q < qend)
03297     {
03298         d->nOption = q - d->aOption;
03299     }
03300     else
03301     {
03302         d->nOption = 0;
03303     }
03304     d->input_tot  += nBytes;
03305     d->input_size += nInputBytes;
03306     d->input_lost += nLostBytes;
03307 }

void process_output ( void *  dvoid,
int  bHandleShutdown 
)

Definition at line 2493 of file bsd.cpp.

References statedata::debug_cmd, descriptor_data::descriptor, text_block::hdr, IS_SOCKET_ERROR, MEMFREE, mudstate, text_block_hdr::nchars, text_block_hdr::nxt, descriptor_data::output_head, descriptor_data::output_size, descriptor_data::output_tail, R_SOCKDIED, shutdownsock(), SOCKET_EWOULDBLOCK, SOCKET_LAST_ERROR, SOCKET_WRITE, and text_block_hdr::start.

Referenced by main(), queue_write_LEN(), raw_broadcast(), shovechars(), shutdownsock(), and SiteMonSend().

02494 {
02495     DESC *d = (DESC *)dvoid;
02496 
02497     char *cmdsave = mudstate.debug_cmd;
02498     mudstate.debug_cmd = "< process_output >";
02499 
02500     TBLOCK *tb = d->output_head;
02501     while (tb != NULL)
02502     {
02503         while (tb->hdr.nchars > 0)
02504         {
02505             int cnt = SOCKET_WRITE(d->descriptor, tb->hdr.start, tb->hdr.nchars, 0);
02506             if (IS_SOCKET_ERROR(cnt))
02507             {
02508                 int iSocketError = SOCKET_LAST_ERROR;
02509                 mudstate.debug_cmd = cmdsave;
02510                 if (  iSocketError != SOCKET_EWOULDBLOCK
02511 #ifdef SOCKET_EAGAIN
02512                    && iSocketError != SOCKET_EAGAIN
02513 #endif // SOCKET_EAGAIN
02514                    && bHandleShutdown)
02515                 {
02516                     shutdownsock(d, R_SOCKDIED);
02517                 }
02518                 return;
02519             }
02520             d->output_size -= cnt;
02521             tb->hdr.nchars -= cnt;
02522             tb->hdr.start += cnt;
02523         }
02524         TBLOCK *save = tb;
02525         tb = tb->hdr.nxt;
02526         MEMFREE(save);
02527         save = NULL;
02528         d->output_head = tb;
02529         if (tb == NULL)
02530         {
02531             d->output_tail = NULL;
02532         }
02533     }
02534 
02535     mudstate.debug_cmd = cmdsave;
02536 }

static void SendDo ( DESC d,
unsigned char  chOption 
) [static]

Transmit a Telnet DO sequence for the given option.

Parameters:
d Player connection context.
chOption Telnet Option.
Returns:
None.

Definition at line 2768 of file bsd.cpp.

References NVT_DO, NVT_IAC, and queue_write_LEN().

Referenced by EnableHim(), and process_input_helper().

02769 {
02770     char aDo[3]   = { NVT_IAC, NVT_DO,   0 };
02771     aDo[2] = chOption;
02772     queue_write_LEN(d, aDo, sizeof(aDo));
02773 }

static void SendDont ( DESC d,
unsigned char  chOption 
) [static]

Transmit a Telnet DONT sequence for the given option.

Parameters:
d Player connection context.
chOption Telnet Option.
Returns:
None.

Definition at line 2754 of file bsd.cpp.

References NVT_DONT, NVT_IAC, and queue_write_LEN().

Referenced by DisableHim(), and process_input_helper().

02755 {
02756     char aDont[3] = { NVT_IAC, NVT_DONT, 0 };
02757     aDont[2] = chOption;
02758     queue_write_LEN(d, aDont, sizeof(aDont));
02759 }

static void SendWill ( DESC d,
unsigned char  chOption 
) [static]

Transmit a Telnet WILL sequence for the given option.

Parameters:
d Player connection context.
chOption Telnet Option.
Returns:
None.

Definition at line 2740 of file bsd.cpp.

References NVT_IAC, NVT_WILL, and queue_write_LEN().

Referenced by EnableUs(), and process_input_helper().

02741 {
02742     char aWill[3] = { NVT_IAC, NVT_WILL, 0 };
02743     aWill[2] = chOption;
02744     queue_write_LEN(d, aWill, sizeof(aWill));
02745 }

static void SendWont ( DESC d,
unsigned char  chOption 
) [static]

Transmit a Telnet WONT sequence for the given option.

Parameters:
d Player connection context.
chOption Telnet Option.
Returns:
None.

Definition at line 2782 of file bsd.cpp.

References NVT_IAC, NVT_WONT, and queue_write_LEN().

Referenced by DisableUs(), and process_input_helper().

02783 {
02784     char aWont[3] = { NVT_IAC, NVT_WONT, 0 };
02785     aWont[2] = chOption;
02786     queue_write_LEN(d, aWont, sizeof(aWont));
02787 }

void set_signals ( void   ) 

Definition at line 4015 of file bsd.cpp.

References CAST_SIGNAL_FUNC, and sighandler().

Referenced by main().

04016 {
04017 #ifndef WIN32
04018     sigset_t sigs;
04019 
04020     // We have to reset our signal mask, because of the possibility
04021     // that we triggered a restart on a SIGUSR1. If we did so, then
04022     // the signal became blocked, and stays blocked, since control
04023     // never returns to the caller; i.e., further attempts to send
04024     // a SIGUSR1 would fail.
04025     //
04026 #undef sigfillset
04027 #undef sigprocmask
04028     sigfillset(&sigs);
04029     sigprocmask(SIG_UNBLOCK, &sigs, NULL);
04030 #endif // !WIN32
04031 
04032     signal(SIGINT,  CAST_SIGNAL_FUNC sighandler);
04033     signal(SIGTERM, CAST_SIGNAL_FUNC sighandler);
04034     signal(SIGILL,  CAST_SIGNAL_FUNC sighandler);
04035     signal(SIGSEGV, CAST_SIGNAL_FUNC sighandler);
04036     signal(SIGABRT, CAST_SIGNAL_FUNC sighandler);
04037     signal(SIGFPE,  SIG_IGN);
04038 
04039 #ifndef WIN32
04040     signal(SIGCHLD, CAST_SIGNAL_FUNC sighandler);
04041     signal(SIGHUP,  CAST_SIGNAL_FUNC sighandler);
04042     signal(SIGQUIT, CAST_SIGNAL_FUNC sighandler);
04043     signal(SIGPIPE, SIG_IGN);
04044     signal(SIGUSR1, CAST_SIGNAL_FUNC sighandler);
04045     signal(SIGUSR2, CAST_SIGNAL_FUNC sighandler);
04046     signal(SIGTRAP, CAST_SIGNAL_FUNC sighandler);
04047     signal(SIGILL,  CAST_SIGNAL_FUNC sighandler);
04048 #ifdef HAVE_SETITIMER
04049     signal(SIGPROF,  CAST_SIGNAL_FUNC sighandler);
04050 #endif
04051 
04052 #ifdef SIGXCPU
04053     signal(SIGXCPU, CAST_SIGNAL_FUNC sighandler);
04054 #endif // SIGXCPU
04055 #ifdef SIGFSZ
04056     signal(SIGXFSZ, CAST_SIGNAL_FUNC sighandler);
04057 #endif // SIGFSZ
04058 #ifdef SIGEMT
04059     signal(SIGEMT, CAST_SIGNAL_FUNC sighandler);
04060 #endif // SIGEMT
04061 #ifdef SIGBUS
04062     signal(SIGBUS, CAST_SIGNAL_FUNC sighandler);
04063 #endif // SIGBUS
04064 #ifdef SIGSYS
04065     signal(SIGSYS, CAST_SIGNAL_FUNC sighandler);
04066 #endif // SIGSYS
04067 #endif // !WIN32
04068 }

static void SetHimState ( DESC d,
unsigned char  chOption,
int  iHimState 
) [static]

Change the other side's negotiation state.

Parameters:
d Player connection context.
chOption Telnet Option
iHimState One of the six option negotiation states.
Returns:
None.

Definition at line 2685 of file bsd.cpp.

References descriptor_data::nvt_eor_him_state, descriptor_data::nvt_naws_him_state, descriptor_data::nvt_sga_him_state, TELNET_EOR, TELNET_NAWS, and TELNET_SGA.

Referenced by DisableHim(), EnableHim(), and process_input_helper().

02686 {
02687     if (TELNET_NAWS == chOption)
02688     {
02689         d->nvt_naws_him_state = iHimState;
02690     }
02691     else if (TELNET_EOR == chOption)
02692     {
02693         d->nvt_eor_him_state = iHimState;
02694     }
02695     else if (TELNET_SGA == chOption)
02696     {
02697         d->nvt_sga_him_state = iHimState;
02698     }
02699 }

void SetupPorts ( int *  pnPorts,
PortInfo  aPorts[],
IntArray pia 
)

Definition at line 1039 of file bsd.cpp.

References DebugTotalSockets, INVALID_SOCKET, tag_int_array::n, tag_int_array::pi, PortInfo::port, PortInfo::socket, and SOCKET_CLOSE.

Referenced by main().

01040 {
01041     // Any existing open port which does not appear in the requested set
01042     // should be closed.
01043     //
01044     int i, j, k;
01045     bool bFound;
01046     for (i = 0; i < *pnPorts; i++)
01047     {
01048         bFound = false;
01049         for (j = 0; j < pia->n; j++)
01050         {
01051             if (aPorts[i].port == pia->pi[j])
01052             {
01053                 bFound = true;
01054                 break;
01055             }
01056         }
01057         if (!bFound)
01058         {
01059             if (SOCKET_CLOSE(aPorts[i].socket) == 0)
01060             {
01061                 DebugTotalSockets--;
01062                 (*pnPorts)--;
01063                 k = *pnPorts;
01064                 if (i != k)
01065                 {
01066                     aPorts[i] = aPorts[k];
01067                 }
01068                 aPorts[k].port = 0;
01069                 aPorts[k].socket = INVALID_SOCKET;
01070             }
01071         }
01072     }
01073 
01074     // Any requested port which does not appear in the existing open set
01075     // of ports should be opened.
01076     //
01077     for (j = 0; j < pia->n; j++)
01078     {
01079         bFound = false;
01080         for (i = 0; i < *pnPorts; i++)
01081         {
01082             if (aPorts[i].port == pia->pi[j])
01083             {
01084                 bFound = true;
01085                 break;
01086             }
01087         }
01088         if (!bFound)
01089         {
01090             k = *pnPorts;
01091             (*pnPorts)++;
01092             aPorts[k].port = pia->pi[j];
01093             make_socket(aPorts+k);
01094         }
01095     }
01096 
01097 #ifndef WIN32
01098     for (i = 0; i < *pnPorts; i++)
01099     {
01100         if (maxd <= aPorts[i].socket)
01101         {
01102             maxd = aPorts[i].socket + 1;
01103         }
01104     }
01105 #endif
01106 }

static void SetUsState ( DESC d,
unsigned char  chOption,
int  iUsState 
) [static]

Change our side's negotiation state.

Parameters:
d Player connection context.
chOption Telnet Option.
iHimState One of the six option negotiation states.
Returns:
None.

Definition at line 2709 of file bsd.cpp.

References DisableUs(), EnableUs(), descriptor_data::nvt_eor_us_state, descriptor_data::nvt_naws_us_state, descriptor_data::nvt_sga_us_state, OPTION_NO, OPTION_YES, TELNET_EOR, TELNET_NAWS, and TELNET_SGA.

Referenced by DisableUs(), EnableUs(), and process_input_helper().

02710 {
02711     if (TELNET_NAWS == chOption)
02712     {
02713         d->nvt_naws_us_state = iUsState;
02714     }
02715     else if (TELNET_EOR == chOption)
02716     {
02717         d->nvt_eor_us_state = iUsState;
02718         if (OPTION_YES == iUsState)
02719         {
02720             EnableUs(d, TELNET_SGA);
02721         }
02722         else if (OPTION_NO == iUsState)
02723         {
02724             DisableUs(d, TELNET_SGA);
02725         }
02726     }
02727     else if (TELNET_SGA == chOption)
02728     {
02729         d->nvt_sga_us_state = iUsState;
02730     }
02731 }

void shovechars ( int  nPorts,
PortInfo  aPorts[] 
)

Definition at line 1417 of file bsd.cpp.

References boot_slave(), CheckInput, CheckOutput, d1, DARK, db, statedata::debug_cmd, DESC_ITER_ALL, DESC_ITER_PLAYER, DESC_SAFEITER_ALL, descriptor_data::descriptor, DS_AUTODARK, ENDLOG, FLAG_WORD1, descriptor_data::flags, object::fs, get_slave_result(), CLinearTimeAbsolute::GetUTC(), GOD, IS_INVALID_SOCKET, IS_SOCKET_ERROR, log_number(), log_perror(), LOG_PROBLEMS, log_text(), maxd, mudstate, ndescriptors, new_connection(), process_input(), process_output(), R_SOCKDIED, CScheduler::RunTasks(), scheduler, statedata::shutdown_flag, shutdownsock(), slave_socket, SOCKET_EBADF, SOCKET_EINTR, SOCKET_LAST_ERROR, STARTLOG, time_30m, update_quotas(), ValidSocket(), CScheduler::WhenNext(), and flagset::word.

Referenced by main().

01418 {
01419     fd_set input_set, output_set;
01420     int found;
01421     DESC *d, *dnext, *newd;
01422     unsigned int avail_descriptors;
01423     int maxfds;
01424     int i;
01425 
01426 #define CheckInput(x)     FD_ISSET(x, &input_set)
01427 #define CheckOutput(x)    FD_ISSET(x, &output_set)
01428 
01429     mudstate.debug_cmd = "< shovechars >";
01430 
01431     CLinearTimeAbsolute ltaLastSlice;
01432     ltaLastSlice.GetUTC();
01433 
01434 #ifdef HAVE_GETDTABLESIZE
01435     maxfds = getdtablesize();
01436 #else // HAVE_GETDTABLESIZE
01437     maxfds = sysconf(_SC_OPEN_MAX);
01438 #endif // HAVE_GETDTABLESIZE
01439 
01440     avail_descriptors = maxfds - 7;
01441 
01442     while (mudstate.shutdown_flag == 0)
01443     {
01444         CLinearTimeAbsolute ltaCurrent;
01445         ltaCurrent.GetUTC();
01446         update_quotas(ltaLastSlice, ltaCurrent);
01447 
01448         // Check the scheduler.
01449         //
01450         scheduler.RunTasks(ltaCurrent);
01451         CLinearTimeAbsolute ltaWakeUp;
01452         if (scheduler.WhenNext(&ltaWakeUp))
01453         {
01454             if (ltaWakeUp < ltaCurrent)
01455             {
01456                 ltaWakeUp = ltaCurrent;
01457             }
01458         }
01459         else
01460         {
01461             CLinearTimeDelta ltd = time_30m;
01462             ltaWakeUp = ltaCurrent + ltd;
01463         }
01464 
01465         if (mudstate.shutdown_flag)
01466         {
01467             break;
01468         }
01469 
01470         FD_ZERO(&input_set);
01471         FD_ZERO(&output_set);
01472 
01473         // Listen for new connections if there are free descriptors.
01474         //
01475         if (ndescriptors < avail_descriptors)
01476         {
01477             for (i = 0; i < nPorts; i++)
01478             {
01479                 FD_SET(aPorts[i].socket, &input_set);
01480             }
01481         }
01482 
01483         // Listen for replies from the slave socket.
01484         //
01485         if (!IS_INVALID_SOCKET(slave_socket))
01486         {
01487             FD_SET(slave_socket, &input_set);
01488         }
01489 
01490 #ifdef QUERY_SLAVE
01491         // Listen for replies from the sqlslave socket.
01492         //
01493         if (!IS_INVALID_SOCKET(sqlslave_socket))
01494         {
01495             FD_SET(sqlslave_socket, &input_set);
01496         }
01497 #endif // QUERY_SLAVE
01498 
01499         // Mark sockets that we want to test for change in status.
01500         //
01501         DESC_ITER_ALL(d)
01502         {
01503             if (!d->input_head)
01504             {
01505                 FD_SET(d->descriptor, &input_set);
01506             }
01507             if (d->output_head)
01508             {
01509                 FD_SET(d->descriptor, &output_set);
01510             }
01511         }
01512 
01513         // Wait for something to happen.
01514         //
01515         struct timeval timeout;
01516         CLinearTimeDelta ltdTimeout = ltaWakeUp - ltaCurrent;
01517         ltdTimeout.ReturnTimeValueStruct(&timeout);
01518         found = select(maxd, &input_set, &output_set, (fd_set *) NULL,
01519                    &timeout);
01520 
01521         if (IS_SOCKET_ERROR(found))
01522         {
01523             int iSocketError = SOCKET_LAST_ERROR;
01524             if (iSocketError == SOCKET_EBADF)
01525             {
01526                 // This one is bad, as it results in a spiral of
01527                 // doom, unless we can figure out what the bad file
01528                 // descriptor is and get rid of it.
01529                 //
01530                 log_perror("NET", "FAIL", "checking for activity", "select");
01531 
01532                 // Search for a bad socket amoungst the players.
01533                 //
01534                 DESC_ITER_ALL(d)
01535                 {
01536                     if (!ValidSocket(d->descriptor))
01537                     {
01538                         STARTLOG(LOG_PROBLEMS, "ERR", "EBADF");
01539                         log_text("Bad descriptor ");
01540                         log_number(d->descriptor);
01541                         ENDLOG;
01542                         shutdownsock(d, R_SOCKDIED);
01543                     }
01544                 }
01545                 if (  !IS_INVALID_SOCKET(slave_socket)
01546                    && !ValidSocket(slave_socket))
01547                 {
01548                     // Try to restart the slave, since it presumably
01549                     // died.
01550                     //
01551                     STARTLOG(LOG_PROBLEMS, "ERR", "EBADF");
01552                     log_text("Bad slave descriptor ");
01553                     log_number(slave_socket);
01554                     ENDLOG;
01555                     boot_slave(GOD, GOD, GOD, 0);
01556                 }
01557 
01558 #ifdef QUERY_SLAVE
01559                 if (  !IS_INVALID_SOCKET(sqlslave_socket)
01560                    && !ValidSocket(sqlslave_socket))
01561                 {
01562                     CleanUpSQLSlaveSocket();
01563                 }
01564 #endif // QUERY_SLAVE
01565 
01566                 for (i = 0; i < nPorts; i++)
01567                 {
01568                     if (!ValidSocket(aPorts[i].socket))
01569                     {
01570                         // That's it. Game over.
01571                         //
01572                         STARTLOG(LOG_PROBLEMS, "ERR", "EBADF");
01573                         log_text("Bad game port descriptor ");
01574                         log_number(aPorts[i].socket);
01575                         ENDLOG;
01576                         return;
01577                     }
01578                 }
01579             }
01580             else if (iSocketError != SOCKET_EINTR)
01581             {
01582                 log_perror("NET", "FAIL", "checking for activity", "select");
01583             }
01584             continue;
01585         }
01586 
01587         // Get usernames and hostnames.
01588         //
01589         if (  !IS_INVALID_SOCKET(slave_socket)
01590            && CheckInput(slave_socket))
01591         {
01592             while (get_slave_result() == 0)
01593             {
01594                 ; // Nothing.
01595             }
01596         }
01597 
01598 #ifdef QUERY_SLAVE
01599         // Get result sets from sqlslave.
01600         //
01601         if (  !IS_INVALID_SOCKET(sqlslave_socket)
01602            && CheckInput(sqlslave_socket))
01603         {
01604             while (get_sqlslave_result() == 0)
01605             {
01606                 ; // Nothing.
01607             }
01608         }
01609 #endif // QUERY_SLAVE
01610 
01611         // Check for new connection requests.
01612         //
01613         for (i = 0; i < nPorts; i++)
01614         {
01615             if (CheckInput(aPorts[i].socket))
01616             {
01617                 int iSocketError;
01618                 newd = new_connection(aPorts+i, &iSocketError);
01619                 if (!newd)
01620                 {
01621                     if (  iSocketError
01622                        && iSocketError != SOCKET_EINTR)
01623                     {
01624                         log_perror("NET", "FAIL", NULL, "new_connection");
01625                     }
01626                 }
01627                 else if (maxd <= newd->descriptor)
01628                 {
01629                     maxd = newd->descriptor + 1;
01630                 }
01631             }
01632         }
01633 
01634         // Check for activity on user sockets.
01635         //
01636         DESC_SAFEITER_ALL(d, dnext)
01637         {
01638             // Process input from sockets with pending input.
01639             //
01640             if (CheckInput(d->descriptor))
01641             {
01642                 // Undo autodark
01643                 //
01644                 if (d->flags & DS_AUTODARK)
01645                 {
01646                     // Clear the DS_AUTODARK on every related session.
01647                     //
01648                     DESC *d1;
01649                     DESC_ITER_PLAYER(d->player, d1)
01650                     {
01651                         d1->flags &= ~DS_AUTODARK;
01652                     }
01653                     db[d->player].fs.word[FLAG_WORD1] &= ~DARK;
01654                 }
01655 
01656                 // Process received data.
01657                 //
01658                 if (!process_input(d))
01659                 {
01660                     shutdownsock(d, R_SOCKDIED);
01661                     continue;
01662                 }
01663             }
01664 
01665             // Process output for sockets with pending output.
01666             //
01667             if (CheckOutput(d->descriptor))
01668             {
01669                 process_output(d, true);
01670             }
01671         }
01672     }
01673 }

void shutdownsock ( DESC d,
int  reason 
)

Definition at line 1843 of file bsd.cpp.

References A_PROGCMD, A_REASON, statedata::access_list, descriptor_data::addr, descriptor_data::address, alloc_lbuf, alloc_mbuf, announce_disconnect(), atr_add_raw(), atr_clr(), CIF_LASTCONNECT, CIF_LONGESTCONNECT, CIF_NUMCONNECTS, CIF_TOTALTIME, clearstrings(), descriptor_data::command_count, descriptor_data::connected_at, db, decode_flags(), DESC_ITER_PLAYER, descriptor_data::descriptor, DS_CONNECTED, ENDLOG, FC_QUIT, fcache_dump(), fetch_ConnectionInfoFields(), find_oldest(), descriptor_data::flags, free_lbuf, free_mbuf, free_sbuf, CLinearTimeAbsolute::GetUTC(), GOD, H_FORBIDDEN, Location, LOG_ACCOUNTING, LOG_LOGIN, log_name(), LOG_NET, LOG_SECURITY, log_text(), MAX_GLOBAL_REGS, MEMFREE, mudstate, Name, Pennies(), descriptor_data::player, process_output(), descriptor_data::program_data, put_ConnectionInfoFields(), R_LOGOUT, R_QUIT, CLinearTimeDelta::ReturnSeconds(), site_check(), SiteMonSend(), STARTLOG, and prog_data::wait_regs.

Referenced by boot_by_port(), boot_off(), check_connect(), check_idle(), close_sockets(), do_logged_out_internal(), failconn(), load_restart_db(), process_output(), and shovechars().

01844 {
01845     char *buff, *buff2;
01846     int i, num;
01847     DESC *dtemp;
01848 
01849     if (  (reason == R_LOGOUT)
01850        && (site_check((d->address).sin_addr, mudstate.access_list) == H_FORBIDDEN))
01851     {
01852         reason = R_QUIT;
01853     }
01854 
01855     CLinearTimeAbsolute ltaNow;
01856     ltaNow.GetUTC();
01857 
01858     if (d->flags & DS_CONNECTED)
01859     {
01860         // Added by D.Piper (del@doofer.org) 1997 & 2000-APR
01861         //
01862 
01863         // Reason: attribute (disconnect reason)
01864         //
01865         atr_add_raw(d->player, A_REASON, (char *)disc_messages[reason]);
01866 
01867         // Update the A_CONNINFO attribute.
01868         //
01869         long anFields[4];
01870         fetch_ConnectionInfoFields(d->player, anFields);
01871 
01872         // One of the active sessions is going away. It doesn't matter which
01873         // one.
01874         //
01875         anFields[CIF_NUMCONNECTS]++;
01876 
01877         // What are the two longest sessions?
01878         //
01879         DESC *dOldest[2];
01880         find_oldest(d->player, dOldest);
01881 
01882         CLinearTimeDelta ltdFull;
01883         ltdFull = ltaNow - dOldest[0]->connected_at;
01884         long tFull = ltdFull.ReturnSeconds();
01885         if (dOldest[0] == d)
01886         {
01887             // We are dropping the oldest connection.
01888             //
01889             CLinearTimeDelta ltdPart;
01890             if (dOldest[1])
01891             {
01892                 // There is another (more recently made) connection.
01893                 //
01894                 ltdPart = dOldest[1]->connected_at - dOldest[0]->connected_at;
01895             }
01896             else
01897             {
01898                 // There is only one connection.
01899                 //
01900                 ltdPart = ltdFull;
01901             }
01902             long tPart = ltdPart.ReturnSeconds();
01903 
01904             anFields[CIF_TOTALTIME] += tPart;
01905             if (anFields[CIF_LONGESTCONNECT] < tFull)
01906             {
01907                 anFields[CIF_LONGESTCONNECT] = tFull;
01908             }
01909         }
01910         anFields[CIF_LASTCONNECT] = tFull;
01911 
01912         put_ConnectionInfoFields(d->player, anFields, ltaNow);
01913 
01914         // If we are doing a LOGOUT, keep the connection open so that the
01915         // player can connect to a different character. Otherwise, we
01916         // do the normal disconnect stuff.
01917         //
01918         if (reason == R_LOGOUT)
01919         {
01920             STARTLOG(LOG_NET | LOG_LOGIN, "NET", "LOGO")
01921             buff = alloc_mbuf("shutdownsock.LOG.logout");
01922             sprintf(buff, "[%u/%s] Logout by ", d->descriptor, d->addr);
01923             log_text(buff);
01924             log_name(d->player);
01925             sprintf(buff, " <Reason: %s>", disc_reasons[reason]);
01926             log_text(buff);
01927             free_mbuf(buff);
01928             ENDLOG;
01929         }
01930         else
01931         {
01932             fcache_dump(d, FC_QUIT);
01933             STARTLOG(LOG_NET | LOG_LOGIN, "NET", "DISC")
01934             buff = alloc_mbuf("shutdownsock.LOG.disconn");
01935             sprintf(buff, "[%u/%s] Logout by ", d->descriptor, d->addr);
01936             log_text(buff);
01937             log_name(d->player);
01938             sprintf(buff, " <Reason: %s>", disc_reasons[reason]);
01939             log_text(buff);
01940             free_mbuf(buff);
01941             ENDLOG;
01942             SiteMonSend(d->descriptor, d->addr, d, "Disconnection");
01943         }
01944 
01945         // If requested, write an accounting record of the form:
01946         // Plyr# Flags Cmds ConnTime Loc Money [Site] <DiscRsn> Name
01947         //
01948         STARTLOG(LOG_ACCOUNTING, "DIS", "ACCT");
01949         CLinearTimeDelta ltd = ltaNow - d->connected_at;
01950         int Seconds = ltd.ReturnSeconds();
01951         buff = alloc_lbuf("shutdownsock.LOG.accnt");
01952         buff2 = decode_flags(GOD, &(db[d->player].fs));
01953         sprintf(buff, "%d %s %d %d %d %d [%s] <%s> %s", d->player, buff2, d->command_count,
01954                 Seconds, Location(d->player), Pennies(d->player), d->addr, disc_reasons[reason],
01955                 Name(d->player));
01956         log_text(buff);
01957         free_lbuf(buff);
01958         free_sbuf(buff2);
01959         ENDLOG;
01960         announce_disconnect(d->player, d, disc_messages[reason]);
01961     }
01962     else
01963     {
01964         if (reason == R_LOGOUT)
01965         {
01966             reason = R_QUIT;
01967         }
01968         STARTLOG(LOG_SECURITY | LOG_NET, "NET", "DISC");
01969         buff = alloc_mbuf("shutdownsock.LOG.neverconn");
01970         sprintf(buff, "[%u/%s] Connection closed, never connected. <Reason: %s>", d->descriptor, d->addr, disc_reasons[reason]);
01971         log_text(buff);
01972         free_mbuf(buff);
01973         ENDLOG;
01974         SiteMonSend(d->descriptor, d->addr, d, "N/C Connection Closed");
01975     }
01976 
01977     process_output(d, false);
01978     clearstrings(d);
01979 
01980     d->flags &= ~DS_CONNECTED;
01981 
01982     // Is this desc still in interactive mode?
01983     //
01984     if (d->program_data != NULL)
01985     {
01986         num = 0;
01987         DESC_ITER_PLAYER(d->player, dtemp) num++;
01988 
01989         if (num == 0)
01990         {
01991             for (i = 0; i < MAX_GLOBAL_REGS; i++)
01992             {
01993                 if (d->program_data->wait_regs[i])
01994                 {
01995                     free_lbuf(d->program_data->wait_regs[i]);
01996                     d->program_data->wait_regs[i] = NULL;
01997                 }
01998             }
01999             MEMFREE(d->program_data);
02000             atr_clr(d->player, A_PROGCMD);
02001         }
02002         d->program_data = NULL;
02003     }
02004     if (reason == R_LOGOUT)
02005     {
02006         d->connected_at.GetUTC();
02007         d->retries_left = mudconf.retry_limit;
02008         d->command_count = 0;
02009         d->timeout = mudconf.idle_timeout;
02010         d->player = 0;
02011         d->doing[0] = '\0';
02012         d->quota = mudconf.cmd_quota_max;
02013         d->last_time = d->connected_at;
02014         d->host_info = site_check((d->address).sin_addr, mudstate.access_list)
02015                      | site_check((d->address).sin_addr, mudstate.suspect_list);
02016         d->input_tot = d->input_size;
02017         d->output_tot = 0;
02018         welcome_user(d);
02019     }
02020     else
02021     {
02022         // Cancel any scheduled processing on this descriptor.
02023         //
02024         scheduler.CancelTask(Task_ProcessCommand, d, 0);
02025 
02026 #ifdef WIN32
02027         if (platform == VER_PLATFORM_WIN32_NT)
02028         {
02029             // Don't close down the socket twice.
02030             //
02031             if (!d->bConnectionShutdown)
02032             {
02033                 // Make sure we don't try to initiate or process any
02034                 // outstanding IOs
02035                 //
02036                 d->bConnectionShutdown = true;
02037 
02038                 // Protect removing the descriptor from our linked list from
02039                 // any interference from the listening thread.
02040                 //
02041                 EnterCriticalSection(&csDescriptorList);
02042                 *d->prev = d->next;
02043                 if (d->next)
02044                 {
02045                     d->next->prev = d->prev;
02046                 }
02047                 LeaveCriticalSection(&csDescriptorList);
02048 
02049                 // This descriptor may hang around awhile, clear out the links.
02050                 //
02051                 d->next = 0;
02052                 d->prev = 0;
02053 
02054                 // Close the connection in 5 seconds.
02055                 //
02056                 scheduler.DeferTask(ltaNow + FACTOR_100NS_PER_SECOND*5,
02057                     PRIORITY_SYSTEM, Task_DeferredClose, d, 0);
02058             }
02059             return;
02060         }
02061 #endif
02062 
02063         shutdown(d->descriptor, SD_BOTH);
02064         if (SOCKET_CLOSE(d->descriptor) == 0)
02065         {
02066             DebugTotalSockets--;
02067         }
02068         d->descriptor = INVALID_SOCKET;
02069 
02070         *d->prev = d->next;
02071         if (d->next)
02072         {
02073             d->next->prev = d->prev;
02074         }
02075 
02076         // This descriptor may hang around awhile, clear out the links.
02077         //
02078         d->next = 0;
02079         d->prev = 0;
02080 
02081         // If we don't have queued IOs, then we can free these, now.
02082         //
02083         freeqs(d);
02084         free_desc(d);
02085         ndescriptors--;
02086     }
02087 }

static RETSIGTYPE DCL_CDECL sighandler ( int  sig  )  [static]

Definition at line 3745 of file bsd.cpp.

References al_store(), statedata::bCanRestart, CScheduler::CancelTask(), CAST_SIGNAL_FUNC, check_panicking(), CleanUpSlaveProcess(), CleanUpSlaveSocket(), CLOSE, confdata::config_file, CScheduler::DeferTask(), dispatch_DatabaseDump(), do_restart(), statedata::dump_counter, dump_database_internal(), DUMP_I_RESTART, DUMP_I_SIGNAL, dump_restart_db(), statedata::dumped, statedata::dumper, statedata::dumping, ENDLOG, CLogFile::Flush(), confdata::fork_dump, CLinearTimeAbsolute::GetUTC(), GOD, local_dump_complete_signal(), local_presync_database_sigsegv(), Log, LOG_PROBLEMS, log_signal(), log_signal_ignore(), LogStatBuf(), confdata::mud_name, mudconf, mudstate, MuxAlarm, statedata::panicking, pcache_sync(), confdata::pid_file, PRIORITY_SYSTEM, raw_broadcast(), report(), SA_EXIT, scheduler, statedata::shutdown_flag, confdata::sig_action, CMuxAlarm::Signal(), SignalDesc(), slave_pid, STARTLOG, SYNC, CLogFile::tinyprintf(), and unset_signals().

Referenced by set_signals().

03746 {
03747 #ifndef WIN32
03748     int stat_buf;
03749     pid_t child;
03750 #endif // !WIN32
03751 
03752     switch (sig)
03753     {
03754 #ifndef WIN32
03755     case SIGUSR1:
03756         if (mudstate.bCanRestart)
03757         {
03758             log_signal(sig);
03759             do_restart(GOD, GOD, GOD, 0);
03760         }
03761         else
03762         {
03763             log_signal_ignore(sig);
03764         }
03765         break;
03766 
03767     case SIGUSR2:
03768 
03769         // Drop a flatfile.
03770         //
03771         log_signal(sig);
03772         raw_broadcast(0, "Caught signal %s requesting a flatfile @dump. Please wait.", SignalDesc(sig));
03773         dump_database_internal(DUMP_I_SIGNAL);
03774         break;
03775 
03776     case SIGCHLD:
03777 
03778         // Change in child status.
03779         //
03780 #ifndef SIGNAL_SIGCHLD_BRAINDAMAGE
03781         signal(SIGCHLD, CAST_SIGNAL_FUNC sighandler);
03782 #endif // !SIGNAL_SIGCHLD_BRAINDAMAGE
03783 
03784         while ((child = waitpid(0, &stat_buf, WNOHANG)) > 0)
03785         {
03786             if (  WIFEXITED(stat_buf)
03787                || WIFSIGNALED(stat_buf))
03788             {
03789                 if (child == slave_pid)
03790                 {
03791                     // The reverse-DNS slave process ended unexpectedly.
03792                     //
03793                     CleanUpSlaveSocket();
03794                     slave_pid = 0;
03795 
03796                     LogStatBuf(stat_buf, "SLAVE");
03797 
03798                     continue;
03799                 }
03800 #ifdef QUERY_SLAVE
03801                 else if (child == sqlslave_pid)
03802                 {
03803                     // The SQL slave process ended unexpectedly.
03804                     //
03805                     CleanUpSQLSlaveSocket();
03806                     sqlslave_pid = 0;
03807 
03808                     LogStatBuf(stat_buf, "QUERY");
03809 
03810                     continue;
03811                 }
03812 #endif // QUERY_SLAVE
03813                 else if (  mudconf.fork_dump
03814                         && mudstate.dumping)
03815                 {
03816                     mudstate.dumped = child;
03817                     if (mudstate.dumper == mudstate.dumped)
03818                     {
03819                         // The dumping process finished.
03820                         //
03821                         mudstate.dumper  = 0;
03822                         mudstate.dumped  = 0;
03823                     }
03824                     else
03825                     {
03826                         // The dumping process finished before we could
03827                         // obtain its process id from fork().
03828                         //
03829                     }
03830                     mudstate.dumping = false;
03831                     local_dump_complete_signal();
03832 
03833                     continue;
03834                 }
03835             }
03836 
03837             log_signal(sig);
03838             LogStatBuf(stat_buf, "UKNWN");
03839 
03840             STARTLOG(LOG_PROBLEMS, "SIG", "DEBUG");
03841 #ifdef QUERY_SLAVE
03842             Log.tinyprintf("mudstate.dumper=%d, child=%d, slave_pid=%d, sqlslave_pid=%d" ENDLINE,
03843                 mudstate.dumper, child, slave_pid, sqlslave_pid);
03844 #else
03845             Log.tinyprintf("mudstate.dumper=%d, child=%d, slave_pid=%d" ENDLINE,
03846                 mudstate.dumper, child, slave_pid);
03847 #endif // QUERY_SLAVE
03848             ENDLOG;
03849         }
03850         break;
03851 
03852     case SIGHUP:
03853 
03854         // Perform a database dump.
03855         //
03856         log_signal(sig);
03857         extern void dispatch_DatabaseDump(void *pUnused, int iUnused);
03858         scheduler.CancelTask(dispatch_DatabaseDump, 0, 0);
03859         mudstate.dump_counter.GetUTC();
03860         scheduler.DeferTask(mudstate.dump_counter, PRIORITY_SYSTEM, dispatch_DatabaseDump, 0, 0);
03861         break;
03862 
03863 #ifdef HAVE_SETITIMER
03864     case SIGPROF:
03865 
03866         // Softcode is running longer than is reasonable.  Apply the brakes.
03867         //
03868         log_signal(sig);
03869         MuxAlarm.Signal();
03870         break;
03871 #endif
03872 
03873 #endif // !WIN32
03874 
03875     case SIGINT:
03876 
03877         // Log + ignore
03878         //
03879         log_signal(sig);
03880         break;
03881 
03882 #ifndef WIN32
03883     case SIGQUIT:
03884 #endif // !WIN32
03885     case SIGTERM:
03886 #ifdef SIGXCPU
03887     case SIGXCPU:
03888 #endif // SIGXCPU
03889         // Time for a normal and short-winded shutdown.
03890         //
03891         check_panicking(sig);
03892         log_signal(sig);
03893         raw_broadcast(0, "GAME: Caught signal %s, exiting.", SignalDesc(sig));
03894         mudstate.shutdown_flag = true;
03895         break;
03896 
03897     case SIGILL:
03898     case SIGFPE:
03899     case SIGSEGV:
03900 #ifndef WIN32
03901     case SIGTRAP:
03902 #ifdef SIGXFSZ
03903     case SIGXFSZ:
03904 #endif // SIGXFSZ
03905 #ifdef SIGEMT
03906     case SIGEMT:
03907 #endif // SIGEMT
03908 #ifdef SIGBUS
03909     case SIGBUS:
03910 #endif // SIGBUS
03911 #ifdef SIGSYS
03912     case SIGSYS:
03913 #endif // SIGSYS
03914 #endif // !WIN32
03915 
03916         // Panic save + restart.
03917         //
03918         Log.Flush();
03919         check_panicking(sig);
03920         log_signal(sig);
03921         report();
03922 
03923         local_presync_database_sigsegv();
03924 #ifndef MEMORY_BASED
03925         al_store();
03926 #endif
03927         pcache_sync();
03928         SYNC;
03929 
03930         if (  mudconf.sig_action != SA_EXIT
03931            && mudstate.bCanRestart)
03932         {
03933             raw_broadcast
03934             (  0,
03935                "GAME: Fatal signal %s caught, restarting.",
03936                SignalDesc(sig)
03937             );
03938 
03939             // There is no older DB. It's a fiction. Our only choice is
03940             // between unamed attributes and named ones. We go with what we
03941             // got.
03942             //
03943             dump_database_internal(DUMP_I_RESTART);
03944             SYNC;
03945             CLOSE;
03946 #ifdef WIN32
03947             unset_signals();
03948             signal(sig, SIG_DFL);
03949             WSACleanup();
03950             exit(12345678);
03951 #else // WIN32
03952             CleanUpSlaveSocket();
03953             CleanUpSlaveProcess();
03954 
03955             // Try our best to dump a core first
03956             //
03957             if (!fork())
03958             {
03959                 // We are the broken parent. Die.
03960                 //
03961                 unset_signals();
03962                 exit(1);
03963             }
03964 
03965             // We are the reproduced child with a slightly better chance.
03966             //
03967             dump_restart_db();
03968 #ifdef GAME_DOOFERMUX
03969             execl("bin/netmux", mudconf.mud_name, "-c", mudconf.config_file, "-p", mudconf.pid_file, NULL);
03970 #else // GAME_DOOFERMUX
03971             execl("bin/netmux", "netmux", "-c", mudconf.config_file, "-p", mudconf.pid_file, NULL);
03972 #endif // GAME_DOOFERMUX
03973             break;
03974 #endif // WIN32
03975         }
03976         else
03977         {
03978 #ifdef WIN32
03979             WSACleanup();
03980 #endif // WIN32
03981 
03982             unset_signals();
03983             signal(sig, SIG_DFL);
03984             exit(1);
03985         }
03986         break;
03987 
03988     case SIGABRT:
03989 
03990         // Coredump.
03991         //
03992         check_panicking(sig);
03993         log_signal(sig);
03994         report();
03995 
03996 #ifdef WIN32
03997         WSACleanup();
03998 #endif // WIN32
03999 
04000         unset_signals();
04001         signal(sig, SIG_DFL);
04002         exit(1);
04003     }
04004     signal(sig, CAST_SIGNAL_FUNC sighandler);
04005     mudstate.panicking = 0;
04006 }

static char* SignalDesc ( int  iSignal  )  [static]

Definition at line 3693 of file bsd.cpp.

References LBUF_SIZE, safe_chr, safe_str, and signames.

Referenced by log_signal(), log_signal_ignore(), LogStatBuf(), and sighandler().

03694 {
03695     static char buff[LBUF_SIZE];
03696     char *bufc = buff;
03697     safe_str(signames[iSignal].pShortName, buff, &bufc);
03698     if (signames[iSignal].pLongName)
03699     {
03700         safe_str(" (", buff, &bufc);
03701         safe_str(signames[iSignal].pLongName, buff, &bufc);
03702         safe_chr(')', buff, &bufc);
03703     }
03704     *bufc = '\0';
03705     return buff;
03706 }

void SiteMonSend ( int  ,
const char *  ,
DESC ,
const char *   
) [static]

Definition at line 4599 of file bsd.cpp.

References DESC_ITER_CONN, H_NOSITEMON, H_SUSPECT, descriptor_data::host_info, IS_INVALID_SOCKET, descriptor_data::player, process_output(), queue_string(), queue_write_LEN(), SiteMon, and tprintf().

Referenced by new_connection(), and shutdownsock().

04600 {
04601     // Don't do sitemon for blocked sites.
04602     //
04603     if (  d != NULL
04604        && (d->host_info & H_NOSITEMON))
04605     {
04606         return;
04607     }
04608 
04609     // Build the msg.
04610     //
04611     char *sendMsg;
04612     bool bSuspect = (d != NULL) && (d->host_info & H_SUSPECT);
04613     if (IS_INVALID_SOCKET(port))
04614     {
04615         sendMsg = tprintf("SITEMON: [UNKNOWN] %s from %s.%s", msg, address,
04616             bSuspect ? " (SUSPECT)": "");
04617     }
04618     else
04619     {
04620         sendMsg = tprintf("SITEMON: [%d] %s from %s.%s", port, msg,
04621             address, bSuspect ? " (SUSPECT)": "");
04622     }
04623 
04624     DESC *nd;
04625     DESC_ITER_CONN(nd)
04626     {
04627         if (SiteMon(nd->player))
04628         {
04629             queue_string(nd, sendMsg);
04630             queue_write_LEN(nd, "\r\n", 2);
04631             process_output(nd, false);
04632         }
04633     }
04634 }

void TelnetSetup ( DESC d  )  [static]

Begin initial telnet negotiations on a socket.

The two sides of the connection may not agree on the following set of options, and keep in mind that the successful negotiation of a particular option may cause the negotiation of another option.

Without this function, we are only react to client requests.

Parameters:
d Player connection on which the input arrived.
Returns:
None.

Definition at line 2965 of file bsd.cpp.

References EnableHim(), EnableUs(), TELNET_EOR, TELNET_NAWS, and TELNET_SGA.

Referenced by new_connection().

02966 {
02967     // Attempt negotation of EOR so we can use that, and if that succeeds,
02968     // code elsewhere will attempt the negotation of SGA for our side as well.
02969     //
02970     EnableUs(d, TELNET_EOR);
02971     EnableHim(d, TELNET_EOR);
02972     EnableHim(d, TELNET_SGA);
02973     EnableHim(d, TELNET_NAWS);
02974 }

static void unset_signals ( void   )  [static]

Definition at line 3400 of file bsd.cpp.

Referenced by sighandler().

03401 {
03402     int i;
03403 
03404     for (i = 0; i < NSIG; i++)
03405     {
03406         signal(i, SIG_DFL);
03407     }
03408 }

int UsState ( DESC d,
unsigned char  chOption 
)

Return our side's negotiation state.

The negotiation of each optional feature of telnet can be in one of six states (defined in interface.h): OPTION_NO, OPTION_YES, OPTION_WANTNO_EMPTY, OPTION_WANTNO_OPPOSITE, OPTION_WANTYES_EMPTY, and OPTION_WANTYES_OPPOSITE.

An option is only enabled when it is in the OPTION_YES state.

Parameters:
d Player connection context.
chOption Telnet Option
Returns:
One of six states.

Definition at line 2660 of file bsd.cpp.

References descriptor_data::nvt_eor_us_state, descriptor_data::nvt_naws_us_state, descriptor_data::nvt_sga_us_state, OPTION_NO, TELNET_EOR, TELNET_NAWS, and TELNET_SGA.

Referenced by DesiredUsOption(), do_prog(), handle_prog(), and process_input_helper().

02661 {
02662     if (TELNET_NAWS == chOption)
02663     {
02664         return d->nvt_naws_us_state;
02665     }
02666     else if (TELNET_EOR == chOption)
02667     {
02668         return d->nvt_eor_us_state;
02669     }
02670     else if (TELNET_SGA == chOption)
02671     {
02672         return d->nvt_sga_us_state;
02673     }
02674     return OPTION_NO;
02675 }

bool ValidSocket ( SOCKET  s  ) 

Definition at line 1407 of file bsd.cpp.

Referenced by shovechars().

01408 {
01409     struct stat fstatbuf;
01410     if (fstat(s, &fstatbuf) < 0)
01411     {
01412         return false;
01413     }
01414     return true;
01415 }


Variable Documentation

PortInfo aMainGamePorts[MAX_LISTEN_PORTS]

Definition at line 32 of file bsd.cpp.

Referenced by close_sockets(), dump_restart_db(), load_restart_db(), and main().

const SIGNALTYPE aSigTypes[]

Definition at line 3426 of file bsd.cpp.

Referenced by BuildSignalNamesTable().

DESC* descriptor_list = NULL

Definition at line 36 of file bsd.cpp.

Referenced by get_slave_result(), initializesock(), and load_restart_db().

const char* disc_messages[] [static]

Initial value:

{
    "Unknown",
    "Quit",
    "Timeout",
    "Boot",
    "Netfailure",
    "Shutdown",
    "BadLogin",
    "NoLogins",
    "Logout"
}

Definition at line 1830 of file bsd.cpp.

const char* disc_reasons[] [static]

Initial value:

{
    "Unspecified",
    "Quit",
    "Inactivity Timeout",
    "Booted",
    "Remote Close or Net Failure",
    "Game Shutdown",
    "Login Retry Limit",
    "Logins Disabled",
    "Logout (Connection Not Dropped)",
    "Too Many Connected Players"
}

Definition at line 1814 of file bsd.cpp.

pid_t game_pid

Definition at line 52 of file bsd.cpp.

Referenced by check_panicking(), list_process(), main(), and write_pidfile().

int maxd = 0

Definition at line 49 of file bsd.cpp.

Referenced by boot_slave(), load_restart_db(), and shovechars().

unsigned int ndescriptors = 0

Definition at line 35 of file bsd.cpp.

Referenced by initializesock(), load_restart_db(), and shovechars().

int nMainGamePorts = 0

Definition at line 33 of file bsd.cpp.

Referenced by close_sockets(), dump_restart_db(), load_restart_db(), and main().

const int nvt_input_action_table[8][14] [static]

Initial value:

{

    {   1,   2,   3,   0,   1,   1,   1,   1,   1,   1,   1,   1,   1,   5  }, 
    {   4,   4,   4,   4,   4,   4,  12,   2,  10,   6,   7,   8,   9,   1  }, 
    {  13,  13,  13,  13,  13,  13,  13,  13,  13,  13,  13,  13,  13,   4  }, 
    {  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,  14,   4  }, 
    {  15,  15,  15,  15,  15,  15,  15,  15,  15,  15,  15,  15,  15,   4  }, 
    {  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,  16,   4  }, 
    {  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  17,  11  }, 
    {   0,   0,   0,   0,  18,   0,   0,   0,   0,   0,   0,   0,   0,  17  }, 
}
Table to map current telnet parsing state state and input to specific actions and state changes.

Action 0 - Nothing. Action 1 - Accept CHR(X) (and transition to Normal state). Action 2 - Erase Character. Action 3 - Accept Line. Action 4 - Transition to the Normal state. Action 5 - Transition to Have_IAC state. Action 6 - Transition to the Have_IAC_WILL state. Action 7 - Transition to the Have_IAC_DONT state. Action 8 - Transition to the Have_IAC_DO state. Action 9 - Transition to the Have_IAC_WONT state. Action 10 - Transition to the Have_IAC_SB state. Action 11 - Transition to the Have_IAC_SB_IAC state. Action 12 - Respond to IAC AYT and return to the Normal state. Action 13 - Respond to IAC WILL X Action 14 - Respond to IAC DONT X Action 15 - Respond to IAC DO X Action 16 - Respond to IAC WONT X Action 17 - Accept CHR(X) for Sub-Option (and transition to Have_IAC_SB state). Action 18 - Accept Completed Sub-option and transition to Normal state.

Definition at line 2602 of file bsd.cpp.

const unsigned char nvt_input_xlat_table[256] [static]

Initial value:

{


    0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  2,  0,  0,  3,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  

    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  
    4,  5,  5,  5,  5,  5,  6,  7,  5,  5,  8,  9, 10, 11, 12, 13   
}
Table to quickly classify characters recieved from the wire with their Telnet meaning.

The use of this table reduces the size of the state table.

Class 0 - Any byte. Class 5 - BRK (0xF3) Class 10 - WONT (0xFC) Class 1 - BS (0x08) Class 5 - IP (0xF4) Class 11 - DO (0xFD) Class 2 - LF (0x0A) Class 5 - AO (0xF5) Class 12 - DONT (0xFE) Class 3 - CR (0x0D) Class 6 - AYT (0xF6) Class 13 - IAC (0xFF) Class 1 - DEL (0x7F) Class 7 - EC (0xF7) Class 5 - EOR (0xEF) Class 5 - EL (0xF8) Class 4 - SE (0xF0) Class 5 - GA (0xF9) Class 5 - NOP (0xF1) Class 8 - SB (0xFA) Class 5 - DM (0xF2) Class 9 - WILL (0xFB)

Definition at line 2555 of file bsd.cpp.

NAMETAB sigactions_nametab[]

Initial value:

{
    {"exit",        3,  0,  SA_EXIT},
    {"default",     1,  0,  SA_DFLT},
    { NULL,         0,  0,  0}
}

Definition at line 4008 of file bsd.cpp.

MUX_SIGNAMES signames[NSIG] [static]

Definition at line 3624 of file bsd.cpp.

Referenced by BuildSignalNamesTable(), and SignalDesc().

pid_t slave_pid = 0

Definition at line 50 of file bsd.cpp.

Referenced by boot_slave(), CleanUpSlaveProcess(), and sighandler().

int slave_socket = INVALID_SOCKET

Definition at line 51 of file bsd.cpp.

Referenced by boot_slave(), CleanUpSlaveSocket(), get_slave_result(), new_connection(), and shovechars().


Generated on Mon May 28 04:40:12 2007 for MUX by  doxygen 1.4.7