mux/src/bsd.cpp

Go to the documentation of this file.
00001 
00008 #include "copyright.h"
00009 #include "autoconf.h"
00010 #include "config.h"
00011 #include "externs.h"
00012 
00013 #ifndef WIN32
00014 #include <sys/file.h>
00015 #include <sys/ioctl.h>
00016 #include <sys/stat.h>
00017 #include <sys/wait.h>
00018 #endif // !WIN32
00019 
00020 #include <signal.h>
00021 
00022 #include "attrs.h"
00023 #include "command.h"
00024 #include "file_c.h"
00025 #include "slave.h"
00026 
00027 #ifdef SOLARIS
00028 extern const int _sys_nsig;
00029 #define NSIG _sys_nsig
00030 #endif // SOLARIS
00031 
00032 PortInfo aMainGamePorts[MAX_LISTEN_PORTS];
00033 int      nMainGamePorts = 0;
00034 
00035 unsigned int ndescriptors = 0;
00036 DESC *descriptor_list = NULL;
00037 
00038 static void TelnetSetup(DESC *d);
00039 static void SiteMonSend(int, const char *, DESC *, const char *);
00040 static DESC *initializesock(SOCKET, struct sockaddr_in *);
00041 static DESC *new_connection(PortInfo *Port, int *piError);
00042 static bool process_input(DESC *);
00043 static int make_nonblocking(SOCKET s);
00044 
00045 #ifdef WIN32
00046 static bool bDescriptorListInit = false;
00047 int game_pid;
00048 #else // WIN32
00049 int maxd = 0;
00050 pid_t slave_pid = 0;
00051 int slave_socket = INVALID_SOCKET;
00052 pid_t game_pid;
00053 #ifdef QUERY_SLAVE
00054 pid_t sqlslave_pid = 0;
00055 int sqlslave_socket = INVALID_SOCKET;
00056 #endif // QUERY_SLAVE
00057 #endif // WIN32
00058 
00059 #ifdef WIN32
00060 
00061 // First version of Windows NT TCP/IP routines written by Nick Gammon
00062 // <nick@gammon.com.au>, and were throughly reviewed, re-written and debugged
00063 // by Stephen Dennis <brazilofmux@gmail.com>.
00064 //
00065 HANDLE hGameProcess = INVALID_HANDLE_VALUE;
00066 FCANCELIO *fpCancelIo = NULL;
00067 FGETPROCESSTIMES *fpGetProcessTimes = NULL;
00068 HANDLE CompletionPort;    // IOs are queued up on this port
00069 DWORD platform;   // which version of Windows are we using?
00070 static OVERLAPPED lpo_aborted; // special to indicate a player has finished TCP IOs
00071 static OVERLAPPED lpo_aborted_final; // Finally free the descriptor.
00072 static OVERLAPPED lpo_shutdown; // special to indicate a player should do a shutdown
00073 static OVERLAPPED lpo_welcome; // special to indicate a player has -just- connected.
00074 static OVERLAPPED lpo_wakeup;  // special to indicate that the loop should wakeup and return.
00075 CRITICAL_SECTION csDescriptorList;      // for thread synchronization
00076 static void __cdecl MUDListenThread(void * pVoid);  // the listening thread
00077 static void ProcessWindowsTCP(DWORD dwTimeout);  // handle NT-style IOs
00078 
00079 typedef struct
00080 {
00081     int                port_in;
00082     struct sockaddr_in sa_in;
00083 } SLAVE_REQUEST;
00084 
00085 static HANDLE hSlaveRequestStackSemaphore;
00086 #define SLAVE_REQUEST_STACK_SIZE 50
00087 static SLAVE_REQUEST SlaveRequests[SLAVE_REQUEST_STACK_SIZE];
00088 static int iSlaveRequest = 0;
00089 #define MAX_STRING 514
00090 typedef struct
00091 {
00092     char host[MAX_STRING];
00093     char token[MAX_STRING];
00094     char ident[MAX_STRING];
00095 } SLAVE_RESULT;
00096 
00097 static HANDLE hSlaveResultStackSemaphore;
00098 #define SLAVE_RESULT_STACK_SIZE 50
00099 static SLAVE_RESULT SlaveResults[SLAVE_RESULT_STACK_SIZE];
00100 static volatile int iSlaveResult = 0;
00101 
00102 #define NUM_SLAVE_THREADS 5
00103 typedef struct tagSlaveThreadsInfo
00104 {
00105     DWORD iDoing;
00106     DWORD iError;
00107     DWORD hThreadId;
00108 } SLAVETHREADINFO;
00109 static SLAVETHREADINFO SlaveThreadInfo[NUM_SLAVE_THREADS];
00110 static HANDLE hSlaveThreadsSemaphore;
00111 
00112 static DWORD WINAPI SlaveProc(LPVOID lpParameter)
00113 {
00114     SLAVE_REQUEST req;
00115     unsigned long addr;
00116     struct hostent *hp;
00117     DWORD iSlave = (DWORD)lpParameter;
00118 
00119     if (NUM_SLAVE_THREADS <= iSlave) return 1;
00120 
00121     SlaveThreadInfo[iSlave].iDoing = __LINE__;
00122     for (;;)
00123     {
00124         // Go to sleep until there's something useful to do.
00125         //
00126         SlaveThreadInfo[iSlave].iDoing = __LINE__;
00127         DWORD dwReason = WaitForSingleObject(hSlaveThreadsSemaphore,
00128             30000UL*NUM_SLAVE_THREADS);
00129         switch (dwReason)
00130         {
00131         case WAIT_TIMEOUT:
00132         case WAIT_OBJECT_0:
00133 
00134             // Either the main game thread rang, or 60 seconds has past,
00135             // and it's probably a good idea to check the stack anyway.
00136             //
00137             break;
00138 
00139         default:
00140 
00141             // Either the main game thread has terminated, in which case
00142             // we want to, too, or the function itself has failed, in which
00143             // case: calling it again won't do much good.
00144             //
00145             SlaveThreadInfo[iSlave].iError = __LINE__;
00146             return 1;
00147         }
00148 
00149         SlaveThreadInfo[iSlave].iDoing = __LINE__;
00150         for (;;)
00151         {
00152             // Go take the request off the stack, but not if it takes more
00153             // than 5 seconds to do it. Go back to sleep if we time out. The
00154             // request can wait: either another thread will pick it up, or
00155             // we'll wakeup in 60 seconds anyway.
00156             //
00157             SlaveThreadInfo[iSlave].iDoing = __LINE__;
00158             if (WAIT_OBJECT_0 != WaitForSingleObject(hSlaveRequestStackSemaphore, 5000))
00159             {
00160                 SlaveThreadInfo[iSlave].iError = __LINE__;
00161                 break;
00162             }
00163 
00164             SlaveThreadInfo[iSlave].iDoing = __LINE__;
00165 
00166             // We have control of the stack.
00167             //
00168             if (iSlaveRequest <= 0)
00169             {
00170                 // The stack is empty. Release control and go back to sleep.
00171                 //
00172                 SlaveThreadInfo[iSlave].iDoing = __LINE__;
00173                 ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL);
00174                 SlaveThreadInfo[iSlave].iDoing = __LINE__;
00175                 break;
00176             }
00177 
00178             // Remove the request from the stack.
00179             //
00180             iSlaveRequest--;
00181             req = SlaveRequests[iSlaveRequest];
00182 
00183             SlaveThreadInfo[iSlave].iDoing = __LINE__;
00184             ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL);
00185             SlaveThreadInfo[iSlave].iDoing = __LINE__;
00186 
00187             // Ok, we have complete control of this address, now, so let's
00188             // do the host/ident thing.
00189             //
00190 
00191             // Take note of what time it is.
00192             //
00193 #define IDENT_PROTOCOL_TIMEOUT 5*60 // 5 minutes expressed in seconds.
00194             CLinearTimeAbsolute ltaTimeoutOrigin;
00195             ltaTimeoutOrigin.GetUTC();
00196             CLinearTimeDelta ltdTimeout;
00197             ltdTimeout.SetSeconds(IDENT_PROTOCOL_TIMEOUT);
00198             CLinearTimeAbsolute ltaTimeoutForward(ltaTimeoutOrigin, ltdTimeout);
00199             ltdTimeout.SetSeconds(-IDENT_PROTOCOL_TIMEOUT);
00200             CLinearTimeAbsolute ltaTimeoutBackward(ltaTimeoutOrigin, ltdTimeout);
00201 
00202             addr = req.sa_in.sin_addr.S_un.S_addr;
00203             hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
00204 
00205             if (  hp
00206                && strlen(hp->h_name) < MAX_STRING)
00207             {
00208                 SlaveThreadInfo[iSlave].iDoing = __LINE__;
00209 
00210                 char host[MAX_STRING];
00211                 char token[MAX_STRING];
00212                 char szIdent[MAX_STRING];
00213                 struct sockaddr_in sin;
00214                 memset(&sin, 0, sizeof(sin));
00215                 SOCKET s;
00216 
00217                 // We have a host name.
00218                 //
00219                 strcpy(host, inet_ntoa(req.sa_in.sin_addr));
00220                 strcpy(token, hp->h_name);
00221 
00222                 // Setup ident port.
00223                 //
00224                 sin.sin_family = hp->h_addrtype;
00225                 memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
00226                 sin.sin_port = htons(113);
00227 
00228                 szIdent[0] = 0;
00229                 s = socket(hp->h_addrtype, SOCK_STREAM, 0);
00230                 SlaveThreadInfo[iSlave].iDoing = __LINE__;
00231                 if (s != INVALID_SOCKET)
00232                 {
00233                     SlaveThreadInfo[iSlave].iDoing = __LINE__;
00234 
00235                     DebugTotalSockets++;
00236                     if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR)
00237                     {
00238                         SlaveThreadInfo[iSlave].iDoing = __LINE__;
00239                         shutdown(s, SD_BOTH);
00240                         SlaveThreadInfo[iSlave].iDoing = __LINE__;
00241                         if (closesocket(s) == 0)
00242                         {
00243                             DebugTotalSockets--;
00244                         }
00245                         s = INVALID_SOCKET;
00246                     }
00247                     else
00248                     {
00249                         int TurnOn = 1;
00250                         setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&TurnOn, sizeof(TurnOn));
00251 
00252                         SlaveThreadInfo[iSlave].iDoing = __LINE__;
00253                         char szPortPair[128];
00254                         sprintf(szPortPair, "%d, %d\r\n",
00255                             ntohs(req.sa_in.sin_port), req.port_in);
00256                         SlaveThreadInfo[iSlave].iDoing = __LINE__;
00257                         int nPortPair = strlen(szPortPair);
00258 
00259                         CLinearTimeAbsolute ltaCurrent;
00260                         ltaCurrent.GetUTC();
00261                         if (  ltaTimeoutBackward < ltaCurrent
00262                            &&  ltaCurrent < ltaTimeoutForward
00263                            && send(s, szPortPair, nPortPair, 0) != SOCKET_ERROR)
00264                         {
00265                             SlaveThreadInfo[iSlave].iDoing = __LINE__;
00266                             int nIdent = 0;
00267                             int cc;
00268 
00269                             char szIdentBuffer[MAX_STRING];
00270                             szIdentBuffer[0] = 0;
00271                             bool bAllDone = false;
00272 
00273                             ltaCurrent.GetUTC();
00274                             while (  !bAllDone
00275                                   && nIdent < sizeof(szIdent)-1
00276                                   && ltaTimeoutBackward < ltaCurrent
00277                                   && ltaCurrent < ltaTimeoutForward
00278                                   && (cc = recv(s, szIdentBuffer, sizeof(szIdentBuffer)-1, 0)) != SOCKET_ERROR
00279                                   && cc != 0)
00280                             {
00281                                 SlaveThreadInfo[iSlave].iDoing = __LINE__;
00282 
00283                                 int nIdentBuffer = cc;
00284                                 szIdentBuffer[nIdentBuffer] = 0;
00285 
00286                                 char *p = szIdentBuffer;
00287                                 for (; nIdent < sizeof(szIdent)-1;)
00288                                 {
00289                                     if (  *p == '\0'
00290                                        || *p == '\r'
00291                                        || *p == '\n')
00292                                     {
00293                                         bAllDone = true;
00294                                         break;
00295                                     }
00296                                     if (mux_isprint(*p))
00297                                     {
00298                                         szIdent[nIdent++] = *p;
00299                                     }
00300                                     p++;
00301                                 }
00302                                 szIdent[nIdent] = '\0';
00303 
00304                                 ltaCurrent.GetUTC();
00305                             }
00306                         }
00307                         SlaveThreadInfo[iSlave].iDoing = __LINE__;
00308                         shutdown(s, SD_BOTH);
00309                         SlaveThreadInfo[iSlave].iDoing = __LINE__;
00310                         if (closesocket(s) == 0)
00311                         {
00312                             DebugTotalSockets--;
00313                         }
00314                         s = INVALID_SOCKET;
00315                     }
00316                 }
00317 
00318                 SlaveThreadInfo[iSlave].iDoing = __LINE__;
00319                 if (WAIT_OBJECT_0 == WaitForSingleObject(hSlaveResultStackSemaphore, INFINITE))
00320                 {
00321                     SlaveThreadInfo[iSlave].iDoing = __LINE__;
00322                     if (iSlaveResult < SLAVE_RESULT_STACK_SIZE)
00323                     {
00324                         SlaveThreadInfo[iSlave].iDoing = __LINE__;
00325                         strcpy(SlaveResults[iSlaveResult].host, host);
00326                         strcpy(SlaveResults[iSlaveResult].token, token);
00327                         strcpy(SlaveResults[iSlaveResult].ident, szIdent);
00328                         iSlaveResult++;
00329                     }
00330                     else
00331                     {
00332                         // The result stack is full, so we just toss
00333                         // the info and act like it never happened.
00334                         //
00335                         SlaveThreadInfo[iSlave].iError = __LINE__;
00336                     }
00337                     SlaveThreadInfo[iSlave].iDoing = __LINE__;
00338                     ReleaseSemaphore(hSlaveResultStackSemaphore, 1, NULL);
00339                     SlaveThreadInfo[iSlave].iDoing = __LINE__;
00340                 }
00341                 else
00342                 {
00343                     // The main game thread terminated or the function itself failed,
00344                     // There isn't much left to do except terminate ourselves.
00345                     //
00346                     SlaveThreadInfo[iSlave].iError = __LINE__;
00347                     return 1;
00348                 }
00349             }
00350         }
00351     }
00352     //SlaveThreadInfo[iSlave].iDoing = __LINE__;
00353     //return 1;
00354 }
00355 
00356 static bool bSlaveBooted = false;
00357 void boot_slave(dbref executor, dbref caller, dbref enactor, int)
00358 {
00359     UNUSED_PARAMETER(executor);
00360     UNUSED_PARAMETER(caller);
00361     UNUSED_PARAMETER(enactor);
00362 
00363     int iSlave;
00364 
00365     if (bSlaveBooted) return;
00366 
00367     hSlaveThreadsSemaphore = CreateSemaphore(NULL, 0, NUM_SLAVE_THREADS, NULL);
00368     hSlaveRequestStackSemaphore = CreateSemaphore(NULL, 1, 1, NULL);
00369     hSlaveResultStackSemaphore = CreateSemaphore(NULL, 1, 1, NULL);
00370     DebugTotalSemaphores += 3;
00371     for (iSlave = 0; iSlave < NUM_SLAVE_THREADS; iSlave++)
00372     {
00373         SlaveThreadInfo[iSlave].iDoing = 0;
00374         SlaveThreadInfo[iSlave].iError = 0;
00375         CreateThread(NULL, 0, SlaveProc, (LPVOID)iSlave, 0, &SlaveThreadInfo[iSlave].hThreadId);
00376         DebugTotalThreads++;
00377     }
00378     bSlaveBooted = true;
00379 }
00380 
00381 
00382 static int get_slave_result(void)
00383 {
00384     char host[MAX_STRING];
00385     char token[MAX_STRING];
00386     char ident[MAX_STRING];
00387     char os[MAX_STRING];
00388     char userid[MAX_STRING];
00389     DESC *d;
00390     int local_port, remote_port;
00391 
00392     // Go take the result off the stack, but not if it takes more
00393     // than 5 seconds to do it. Skip it if we time out.
00394     //
00395     if (WAIT_OBJECT_0 != WaitForSingleObject(hSlaveResultStackSemaphore, 5000))
00396     {
00397         return 1;
00398     }
00399 
00400     // We have control of the stack. Go back to sleep if the stack is empty.
00401     //
00402     if (iSlaveResult <= 0)
00403     {
00404         ReleaseSemaphore(hSlaveResultStackSemaphore, 1, NULL);
00405         return 1;
00406     }
00407     iSlaveResult--;
00408     strcpy(host, SlaveResults[iSlaveResult].host);
00409     strcpy(token, SlaveResults[iSlaveResult].token);
00410     strcpy(ident, SlaveResults[iSlaveResult].ident);
00411     ReleaseSemaphore(hSlaveResultStackSemaphore, 1, NULL);
00412 
00413     // At this point, we have a host name on our own stack.
00414     //
00415     if (!mudconf.use_hostname)
00416     {
00417         return 1;
00418     }
00419     for (d = descriptor_list; d; d = d->next)
00420     {
00421         if (strcmp(d->addr, host))
00422         {
00423             continue;
00424         }
00425 
00426         strncpy(d->addr, token, 50);
00427         d->addr[50] = '\0';
00428         if (d->player != 0)
00429         {
00430             if (d->username[0])
00431             {
00432                 atr_add_raw(d->player, A_LASTSITE, tprintf("%s@%s", d->username, d->addr));
00433             }
00434             else
00435             {
00436                 atr_add_raw(d->player, A_LASTSITE, d->addr);
00437             }
00438             atr_add_raw(d->player, A_LASTIP, inet_ntoa((d->address).sin_addr));
00439         }
00440     }
00441 
00442     if (sscanf(ident, "%d , %d : %s : %s : %s", &remote_port, &local_port, token, os, userid) != 5)
00443     {
00444         return 1;
00445     }
00446     for (d = descriptor_list; d; d = d->next)
00447     {
00448         if (ntohs((d->address).sin_port) != remote_port)
00449         {
00450             continue;
00451         }
00452 
00453         strncpy(d->username, userid, 10);
00454         d->username[10] = '\0';
00455         if (d->player != 0)
00456         {
00457             atr_add_raw(d->player, A_LASTSITE, tprintf("%s@%s", d->username, d->addr));
00458         }
00459     }
00460     return 1;
00461 }
00462 
00463 #else // WIN32
00464 
00465 void CleanUpSlaveSocket(void)
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 }
00477 
00478 void CleanUpSlaveProcess(void)
00479 {
00480     if (slave_pid > 0)
00481     {
00482         kill(slave_pid, SIGKILL);
00483         waitpid(slave_pid, NULL, 0);
00484     }
00485     slave_pid = 0;
00486 }
00487 
00488 #ifdef QUERY_SLAVE
00489 void CleanUpSQLSlaveSocket(void)
00490 {
00491     if (!IS_INVALID_SOCKET(sqlslave_socket))
00492     {
00493         shutdown(sqlslave_socket, SD_BOTH);
00494         if (close(sqlslave_socket) == 0)
00495         {
00496             DebugTotalSockets--;
00497         }
00498         sqlslave_socket = INVALID_SOCKET;
00499     }
00500 }
00501 
00502 void CleanUpSQLSlaveProcess(void)
00503 {
00504     if (sqlslave_pid > 0)
00505     {
00506         kill(sqlslave_pid, SIGKILL);
00507         waitpid(sqlslave_pid, NULL, 0);
00508     }
00509     sqlslave_pid = 0;
00510 }
00511 
00524 void boot_sqlslave(dbref executor, dbref caller, dbref enactor, int)
00525 {
00526     char *pFailedFunc = 0;
00527     int sv[2];
00528     int i;
00529     int maxfds;
00530 
00531 #ifdef HAVE_GETDTABLESIZE
00532     maxfds = getdtablesize();
00533 #else // HAVE_GETDTABLESIZE
00534     maxfds = sysconf(_SC_OPEN_MAX);
00535 #endif // HAVE_GETDTABLESIZE
00536 
00537     CleanUpSQLSlaveSocket();
00538     CleanUpSQLSlaveProcess();
00539 
00540     if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0)
00541     {
00542         pFailedFunc = "socketpair() error: ";
00543         goto failure;
00544     }
00545 
00546     // Set to nonblocking.
00547     //
00548     if (make_nonblocking(sv[0]) < 0)
00549     {
00550         pFailedFunc = "make_nonblocking() error: ";
00551         close(sv[0]);
00552         close(sv[1]);
00553         goto failure;
00554     }
00555 
00556     sqlslave_pid = fork();
00557     switch (sqlslave_pid)
00558     {
00559     case -1:
00560 
00561         pFailedFunc = "fork() error: ";
00562         close(sv[0]);
00563         close(sv[1]);
00564         goto failure;
00565 
00566     case 0:
00567 
00568         // If we don't clear this alarm, the child will eventually receive a
00569         // SIG_PROF.
00570         //
00571         MuxAlarm.Clear();
00572 
00573         // Child.  The following calls to dup2() assume only the minimal
00574         // dup2() functionality.  That is, the destination descriptor is
00575         // always available for it, and sv[1] is never that descriptor.
00576         // It is likely that the standard defined behavior of dup2()
00577         // would handle the job by itself more directly, but a little
00578         // extra code is low-cost insurance.
00579         //
00580         close(sv[0]);
00581         if (sv[1] != 0)
00582         {
00583             close(0);
00584             if (dup2(sv[1], 0) == -1)
00585             {
00586                 _exit(1);
00587             }
00588         }
00589         if (sv[1] != 1)
00590         {
00591             close(1);
00592             if (dup2(sv[1], 1) == -1)
00593             {
00594                 _exit(1);
00595             }
00596         }
00597         for (i = 3; i < maxfds; i++)
00598         {
00599             close(i);
00600         }
00601         execlp("bin/sqlslave", "sqlslave", NULL);
00602         _exit(1);
00603     }
00604     close(sv[1]);
00605 
00606     sqlslave_socket = sv[0];
00607     DebugTotalSockets++;
00608     if (make_nonblocking(sqlslave_socket) < 0)
00609     {
00610         pFailedFunc = "make_nonblocking() error: ";
00611         CleanUpSQLSlaveSocket();
00612         goto failure;
00613     }
00614     if (maxd <= sqlslave_socket)
00615     {
00616         maxd = sqlslave_socket + 1;
00617     }
00618 
00619     STARTLOG(LOG_ALWAYS, "NET", "QUERY");
00620     log_text("SQL slave started on fd ");
00621     log_number(sqlslave_socket);
00622     ENDLOG;
00623 
00624     write(sqlslave_socket, "PING", 4);
00625     return;
00626 
00627 failure:
00628 
00629     CleanUpSQLSlaveProcess();
00630     STARTLOG(LOG_ALWAYS, "NET", "SQL");
00631     log_text(pFailedFunc);
00632     log_number(errno);
00633     ENDLOG;
00634 }
00635 #endif // QUERY_SLAVE
00636 
00649 void boot_slave(dbref executor, dbref caller, dbref enactor, int)
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 }
00757 
00758 #ifdef QUERY_SLAVE
00759 
00767 static int get_sqlslave_result(void)
00768 {
00769     char buf[LBUF_SIZE];
00770 
00771     int len = read(sqlslave_socket, buf, sizeof(buf)-1);
00772     if (len < 0)
00773     {
00774         int iSocketError = SOCKET_LAST_ERROR;
00775         if (  iSocketError == SOCKET_EAGAIN
00776            || iSocketError == SOCKET_EWOULDBLOCK)
00777         {
00778             return -1;
00779         }
00780         CleanUpSQLSlaveSocket();
00781         CleanUpSQLSlaveProcess();
00782 
00783         STARTLOG(LOG_ALWAYS, "NET", "QUERY");
00784         log_text("read() of query slave failed. Query Slave stopped.");
00785         ENDLOG;
00786 
00787         return -1;
00788     }
00789     else if (len == 0)
00790     {
00791         return -1;
00792     }
00793     buf[len] = '\0';
00794 
00795     STARTLOG(LOG_ALWAYS, "NET", "QUERY");
00796     log_text(buf);
00797     ENDLOG;
00798 
00799     return 0;
00800 }
00801 
00802 #endif // QUERY_SLAVE
00803 
00804 // Get a result from the slave
00805 //
00806 static int get_slave_result(void)
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 }
00905 #endif // WIN32
00906 
00907 static void make_socket(PortInfo *Port)
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 }
01038 
01039 void SetupPorts(int *pnPorts, PortInfo aPorts[], IntArray *pia)
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 }
01107 
01108 #ifdef WIN32
01109 // Private version of FD_ISSET:
01110 //
01111 // The following routine is only used on Win9x. Ordinarily, FD_ISSET
01112 // maps to a __WSAFDIsSet call, however, the Intel compiler encounters
01113 // an internal error at link time when some of the higher-order
01114 // optimizations are requested (-Qipo). Including this function is a
01115 // workaround.
01116 //
01117 DCL_INLINE bool FD_ISSET_priv(SOCKET fd, fd_set *set)
01118 {
01119     unsigned int i;
01120     for (i = 0; i < set->fd_count; i++)
01121     {
01122         if (set->fd_array[i] == fd)
01123         {
01124             return true;
01125         }
01126     }
01127     return false;
01128 }
01129 
01130 void shovechars9x(int nPorts, PortInfo aPorts[])
01131 {
01132     fd_set input_set, output_set;
01133     int found;
01134     DESC *d, *dnext, *newd;
01135 
01136 #define CheckInput(x)   FD_ISSET_priv(x, &input_set)
01137 #define CheckOutput(x)  FD_ISSET_priv(x, &output_set)
01138 
01139     mudstate.debug_cmd = "< shovechars >";
01140 
01141     CLinearTimeAbsolute ltaLastSlice;
01142     ltaLastSlice.GetUTC();
01143 
01144     while (mudstate.shutdown_flag == 0)
01145     {
01146         CLinearTimeAbsolute ltaCurrent;
01147         ltaCurrent.GetUTC();
01148         update_quotas(ltaLastSlice, ltaCurrent);
01149 
01150         // Before processing a possible QUIT command, be sure to give the slave
01151         // a chance to report it's findings.
01152         //
01153         if (iSlaveResult) get_slave_result();
01154 
01155         // Check the scheduler. Run a little ahead into the future so that
01156         // we tend to sleep longer.
01157         //
01158         scheduler.RunTasks(ltaCurrent);
01159         CLinearTimeAbsolute ltaWakeUp;
01160         if (!scheduler.WhenNext(&ltaWakeUp))
01161         {
01162             CLinearTimeDelta ltd = time_30m;
01163             ltaWakeUp = ltaCurrent + ltd;
01164         }
01165         else if (ltaWakeUp < ltaCurrent)
01166         {
01167             ltaWakeUp = ltaCurrent;
01168         }
01169 
01170         if (mudstate.shutdown_flag)
01171         {
01172             break;
01173         }
01174 
01175         FD_ZERO(&input_set);
01176         FD_ZERO(&output_set);
01177 
01178         // Listen for new connections.
01179         //
01180         int i;
01181         for (i = 0; i < nPorts; i++)
01182         {
01183             FD_SET(aPorts[i].socket, &input_set);
01184         }
01185 
01186         // Mark sockets that we want to test for change in status.
01187         //
01188         DESC_ITER_ALL(d)
01189         {
01190             if (!d->input_head)
01191                 FD_SET(d->descriptor, &input_set);
01192             if (d->output_head)
01193                 FD_SET(d->descriptor, &output_set);
01194         }
01195 
01196         // Wait for something to happen
01197         //
01198         struct timeval timeout;
01199         CLinearTimeDelta ltdTimeout = ltaWakeUp - ltaCurrent;
01200         ltdTimeout.ReturnTimeValueStruct(&timeout);
01201         found = select(0, &input_set, &output_set, (fd_set *) NULL, &timeout);
01202 
01203         switch (found)
01204         {
01205         case SOCKET_ERROR:
01206             {
01207                 STARTLOG(LOG_NET, "NET", "CONN");
01208                 log_text("shovechars: Socket error.");
01209                 ENDLOG;
01210             }
01211 
01212         case 0:
01213             continue;
01214         }
01215 
01216         // Check for new connection requests.
01217         //
01218         for (i = 0; i < nPorts; i++)
01219         {
01220             if (CheckInput(aPorts[i].socket))
01221             {
01222                 int iSocketError;
01223                 newd = new_connection(aPorts+i, &iSocketError);
01224                 if (!newd)
01225                 {
01226                     if (  iSocketError
01227                        && iSocketError != SOCKET_EINTR)
01228                     {
01229                         log_perror("NET", "FAIL", NULL, "new_connection");
01230                     }
01231                 }
01232             }
01233         }
01234 
01235         // Check for activity on user sockets
01236         //
01237         DESC_SAFEITER_ALL(d, dnext)
01238         {
01239             // Process input from sockets with pending input
01240             //
01241             if (CheckInput(d->descriptor))
01242             {
01243                 // Undo autodark
01244                 //
01245                 if (d->flags & DS_AUTODARK)
01246                 {
01247                     // Clear the DS_AUTODARK on every related session.
01248                     //
01249                     DESC *d1;
01250                     DESC_ITER_PLAYER(d->player, d1)
01251                     {
01252                         d1->flags &= ~DS_AUTODARK;
01253                     }
01254                     db[d->player].fs.word[FLAG_WORD1] &= ~DARK;
01255                 }
01256 
01257                 // Process received data
01258                 //
01259                 if (!process_input(d))
01260                 {
01261                     shutdownsock(d, R_SOCKDIED);
01262                     continue;
01263                 }
01264             }
01265 
01266             // Process output for sockets with pending output
01267             //
01268             if (CheckOutput(d->descriptor))
01269             {
01270                 process_output9x(d, true);
01271             }
01272         }
01273     }
01274 }
01275 
01276 static LRESULT WINAPI mux_WindowProc
01277 (
01278     HWND   hWin,
01279     UINT   msg,
01280     WPARAM wParam,
01281     LPARAM lParam
01282 )
01283 {
01284     switch (msg)
01285     {
01286     case WM_CLOSE:
01287         mudstate.shutdown_flag = true;
01288         PostQueuedCompletionStatus(CompletionPort, 0, 0, &lpo_wakeup);
01289         return 0;
01290 
01291     case WM_DESTROY:
01292         PostQuitMessage(0);
01293         return 0;
01294     }
01295 
01296     return DefWindowProc(hWin, msg, wParam, lParam);
01297 }
01298 
01299 const char szApp[] = "MUX2";
01300 
01301 static DWORD WINAPI ListenForCloseProc(LPVOID lpParameter)
01302 {
01303     UNUSED_PARAMETER(lpParameter);
01304 
01305     WNDCLASS wc;
01306 
01307     wc.style         = CS_HREDRAW | CS_VREDRAW;
01308     wc.lpfnWndProc   = mux_WindowProc;
01309     wc.cbClsExtra    = 0;
01310     wc.cbWndExtra    = 0;
01311     wc.hInstance     = 0;
01312     wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
01313     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
01314     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
01315     wc.lpszMenuName  = NULL;
01316     wc.lpszClassName = szApp;
01317 
01318     RegisterClass(&wc);
01319 
01320     HWND hWnd = CreateWindow(szApp, szApp, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
01321         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, 0, NULL);
01322 
01323     ShowWindow(hWnd, SW_HIDE);
01324     UpdateWindow(hWnd);
01325 
01326     MSG msg;
01327     while (GetMessage(&msg, NULL, 0, 0))
01328     {
01329         DispatchMessage(&msg);
01330     }
01331     mudstate.shutdown_flag = true;
01332     PostQueuedCompletionStatus(CompletionPort, 0, 0, &lpo_wakeup);
01333     return 1;
01334 }
01335 
01336 void shovecharsNT(int nPorts, PortInfo aPorts[])
01337 {
01338     UNUSED_PARAMETER(nPorts);
01339     UNUSED_PARAMETER(aPorts);
01340 
01341     mudstate.debug_cmd = "< shovechars >";
01342 
01343     CreateThread(NULL, 0, ListenForCloseProc, NULL, 0, NULL);
01344 
01345     CLinearTimeAbsolute ltaLastSlice;
01346     ltaLastSlice.GetUTC();
01347 
01348     for (;;)
01349     {
01350         CLinearTimeAbsolute ltaCurrent;
01351         ltaCurrent.GetUTC();
01352         update_quotas(ltaLastSlice, ltaCurrent);
01353 
01354         // Before processing a possible QUIT command, be sure to give the slave
01355         // a chance to report it's findings.
01356         //
01357         if (iSlaveResult) get_slave_result();
01358 
01359         // Check the scheduler. Run a little ahead into the future so that
01360         // we tend to sleep longer.
01361         //
01362         scheduler.RunTasks(ltaCurrent);
01363         CLinearTimeAbsolute ltaWakeUp;
01364         if (!scheduler.WhenNext(&ltaWakeUp))
01365         {
01366             CLinearTimeDelta ltd = time_30m;
01367             ltaWakeUp = ltaCurrent + ltd;
01368         }
01369         else if (ltaWakeUp < ltaCurrent)
01370         {
01371             ltaWakeUp = ltaCurrent;
01372         }
01373 
01374         // The following gets Asyncronous writes to the sockets going
01375         // if they are not already going. Doing it this way is better
01376         // than:
01377         //
01378         //   1) starting an asyncronous write after a single addition
01379         //      to the socket's output queue,
01380         //
01381         //   2) scheduling a task to do it (because we would need to
01382         //      either maintain the task's uniqueness in the
01383         //      scheduler's queue, or endure many redudant calls to
01384         //      process_output for the same descriptor.
01385         //
01386         DESC *d, *dnext;
01387         DESC_SAFEITER_ALL(d, dnext)
01388         {
01389             if (d->bCallProcessOutputLater)
01390             {
01391                 d->bCallProcessOutputLater = false;
01392                 process_outputNT(d, false);
01393             }
01394         }
01395 
01396         if (mudstate.shutdown_flag)
01397             break;
01398 
01399         CLinearTimeDelta ltdTimeOut = ltaWakeUp - ltaCurrent;
01400         unsigned int iTimeout = ltdTimeOut.ReturnMilliseconds();
01401         ProcessWindowsTCP(iTimeout);
01402     }