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
00062
00063
00064
00065 HANDLE hGameProcess = INVALID_HANDLE_VALUE;
00066 FCANCELIO *fpCancelIo = NULL;
00067 FGETPROCESSTIMES *fpGetProcessTimes = NULL;
00068 HANDLE CompletionPort;
00069 DWORD platform;
00070 static OVERLAPPED lpo_aborted;
00071 static OVERLAPPED lpo_aborted_final;
00072 static OVERLAPPED lpo_shutdown;
00073 static OVERLAPPED lpo_welcome;
00074 static OVERLAPPED lpo_wakeup;
00075 CRITICAL_SECTION csDescriptorList;
00076 static void __cdecl MUDListenThread(void * pVoid);
00077 static void ProcessWindowsTCP(DWORD dwTimeout);
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
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
00135
00136
00137 break;
00138
00139 default:
00140
00141
00142
00143
00144
00145 SlaveThreadInfo[iSlave].iError = __LINE__;
00146 return 1;
00147 }
00148
00149 SlaveThreadInfo[iSlave].iDoing = __LINE__;
00150 for (;;)
00151 {
00152
00153
00154
00155
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
00167
00168 if (iSlaveRequest <= 0)
00169 {
00170
00171
00172 SlaveThreadInfo[iSlave].iDoing = __LINE__;
00173 ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL);
00174 SlaveThreadInfo[iSlave].iDoing = __LINE__;
00175 break;
00176 }
00177
00178
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
00188
00189
00190
00191
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
00218
00219 strcpy(host, inet_ntoa(req.sa_in.sin_addr));
00220 strcpy(token, hp->h_name);
00221
00222
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
00333
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
00344
00345
00346 SlaveThreadInfo[iSlave].iError = __LINE__;
00347 return 1;
00348 }
00349 }
00350 }
00351 }
00352
00353
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
00393
00394
00395 if (WAIT_OBJECT_0 != WaitForSingleObject(hSlaveResultStackSemaphore, 5000))
00396 {
00397 return 1;
00398 }
00399
00400
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
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
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
00569
00570
00571 MuxAlarm.Clear();
00572
00573
00574
00575
00576
00577
00578
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
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
00693
00694
00695 MuxAlarm.Clear();
00696
00697
00698
00699
00700
00701
00702
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
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
00916
00917
00918 if (platform == VER_PLATFORM_WIN32_NT)
00919 {
00920 int nRet;
00921
00922
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();
00930 exit(1);
00931 }
00932
00933
00934
00935 if (!bDescriptorListInit)
00936 {
00937 InitializeCriticalSection(&csDescriptorList);
00938 bDescriptorListInit = true;
00939 }
00940
00941
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
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
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();
00974 exit(1);
00975 }
00976
00977
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
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
01042
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
01075
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
01110
01111
01112
01113
01114
01115
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
01151
01152
01153 if (iSlaveResult) get_slave_result();
01154
01155
01156
01157
01158 scheduler.RunTasks(ltaCurrent);
01159 CLinearTimeAbsolute ltaWakeUp;
01160 if (!scheduler.WhenNext(<aWakeUp))
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
01179
01180 int i;
01181 for (i = 0; i < nPorts; i++)
01182 {
01183 FD_SET(aPorts[i].socket, &input_set);
01184 }
01185
01186
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
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
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
01236
01237 DESC_SAFEITER_ALL(d, dnext)
01238 {
01239
01240
01241 if (CheckInput(d->descriptor))
01242 {
01243
01244
01245 if (d->flags & DS_AUTODARK)
01246 {
01247
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
01258
01259 if (!process_input(d))
01260 {
01261 shutdownsock(d, R_SOCKDIED);
01262 continue;
01263 }
01264 }
01265
01266
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
01355
01356
01357 if (iSlaveResult) get_slave_result();
01358
01359
01360
01361
01362 scheduler.RunTasks(ltaCurrent);
01363 CLinearTimeAbsolute ltaWakeUp;
01364 if (!scheduler.WhenNext(<aWakeUp))
01365 {
01366 CLinearTimeDelta ltd = time_30m;
01367 ltaWakeUp = ltaCurrent + ltd;
01368 }
01369 else if (ltaWakeUp < ltaCurrent)
01370 {
01371 ltaWakeUp = ltaCurrent;
01372 }
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
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 }
01403 }
01404
01405 #else // WIN32
01406
01407 bool ValidSocket(SOCKET s)
01408 {
01409 struct stat fstatbuf;
01410 if (fstat(s, &fstatbuf) < 0)
01411 {
01412 return false;
01413 }
01414 return true;
01415 }
01416
01417 void shovechars(int nPorts, PortInfo aPorts[])
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
01449
01450 scheduler.RunTasks(ltaCurrent);
01451 CLinearTimeAbsolute ltaWakeUp;
01452 if (scheduler.WhenNext(<aWakeUp))
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
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
01484
01485 if (!IS_INVALID_SOCKET(slave_socket))
01486 {
01487 FD_SET(slave_socket, &input_set);
01488 }
01489
01490 #ifdef QUERY_SLAVE
01491
01492
01493 if (!IS_INVALID_SOCKET(sqlslave_socket))
01494 {
01495 FD_SET(sqlslave_socket, &input_set);
01496 }
01497 #endif // QUERY_SLAVE
01498
01499
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
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
01527
01528
01529
01530 log_perror("NET", "FAIL", "checking for activity", "select");
01531
01532
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
01549
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
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
01588
01589 if ( !IS_INVALID_SOCKET(slave_socket)
01590 && CheckInput(slave_socket))
01591 {
01592 while (get_slave_result() == 0)
01593 {
01594 ;
01595 }
01596 }
01597
01598 #ifdef QUERY_SLAVE
01599
01600
01601 if ( !IS_INVALID_SOCKET(sqlslave_socket)
01602 && CheckInput(sqlslave_socket))
01603 {
01604 while (get_sqlslave_result() == 0)
01605 {
01606 ;
01607 }
01608 }
01609 #endif // QUERY_SLAVE
01610
01611
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
01635
01636 DESC_SAFEITER_ALL(d, dnext)
01637 {
01638
01639
01640 if (CheckInput(d->descriptor))
01641 {
01642
01643
01644 if (d->flags & DS_AUTODARK)
01645 {
01646
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
01657
01658 if (!process_input(d))
01659 {
01660 shutdownsock(d, R_SOCKDIED);
01661 continue;
01662 }
01663 }
01664
01665
01666
01667 if (CheckOutput(d->descriptor))
01668 {
01669 process_output(d, true);
01670 }
01671 }
01672 }
01673 }
01674
01675 #endif // WIN32
01676
01677 DESC *new_connection(PortInfo *Port, int *piSocketError)
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
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
01735
01736
01737
01738
01739 if ( bSlaveBooted
01740 && WAIT_OBJECT_0 == WaitForSingleObject(hSlaveRequestStackSemaphore, 5000))
01741 {
01742
01743
01744 if (iSlaveRequest < SLAVE_REQUEST_STACK_SIZE)
01745 {
01746
01747
01748 SlaveRequests[iSlaveRequest].sa_in = addr;
01749 SlaveRequests[iSlaveRequest].port_in = Port->port;
01750 iSlaveRequest++;
01751 ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL);
01752
01753
01754
01755 ReleaseSemaphore(hSlaveThreadsSemaphore, 1, NULL);
01756 }
01757 else
01758 {
01759
01760
01761 ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL);
01762 }
01763 }
01764 #else // WIN32
01765
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
01799
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 }
01811
01812
01813
01814 static const char *disc_reasons[] =
01815 {
01816 "Unspecified",
01817 "Quit",
01818 "Inactivity Timeout",
01819 "Booted",
01820 "Remote Close or Net Failure",
01821 "Game Shutdown",
01822 "Login Retry Limit",
01823 "Logins Disabled",
01824 "Logout (Connection Not Dropped)",
01825 "Too Many Connected Players"
01826 };
01827
01828
01829
01830 static const char *disc_messages[] =
01831 {
01832 "Unknown",
01833 "Quit",
01834 "Timeout",
01835 "Boot",
01836 "Netfailure",
01837 "Shutdown",
01838 "BadLogin",
01839 "NoLogins",
01840 "Logout"
01841 };
01842
01843 void shutdownsock(DESC *d, int reason)
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
01861
01862
01863
01864
01865 atr_add_raw(d->player, A_REASON, (char *)disc_messages[reason]);
01866
01867
01868
01869 long anFields[4];
01870 fetch_ConnectionInfoFields(d->player, anFields);
01871
01872
01873
01874
01875 anFields[CIF_NUMCONNECTS]++;
01876
01877
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
01888
01889 CLinearTimeDelta ltdPart;
01890 if (dOldest[1])
01891 {
01892
01893
01894 ltdPart = dOldest[1]->connected_at - dOldest[0]->connected_at;
01895 }
01896 else
01897 {
01898
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
01915
01916
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
01946
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
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
02023
02024 scheduler.CancelTask(Task_ProcessCommand, d, 0);
02025
02026 #ifdef WIN32
02027 if (platform == VER_PLATFORM_WIN32_NT)
02028 {
02029
02030
02031 if (!d->bConnectionShutdown)
02032 {
02033
02034
02035
02036 d->bConnectionShutdown = true;
02037
02038
02039
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
02050
02051 d->next = 0;
02052 d->prev = 0;
02053
02054
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
02077
02078 d->next = 0;
02079 d->prev = 0;
02080
02081
02082
02083 freeqs(d);
02084 free_desc(d);
02085 ndescriptors--;
02086 }
02087 }
02088
02089 #ifdef WIN32
02090 static void shutdownsock_brief(DESC *d)
02091 {
02092
02093
02094 if (d->bConnectionShutdown)
02095 {
02096 return;
02097 }
02098
02099
02100
02101 d->bConnectionShutdown = true;
02102 d->bConnectionDropped = true;
02103
02104
02105
02106
02107 if (!fpCancelIo((HANDLE) d->descriptor))
02108 {
02109 Log.tinyprintf("Error %ld on CancelIo" ENDLINE, GetLastError());
02110 }
02111
02112 shutdown(d->descriptor, SD_BOTH);
02113 if (closesocket(d->descriptor) == 0)
02114 {
02115 DebugTotalSockets--;
02116 }
02117 d->descriptor = INVALID_SOCKET;
02118
02119
02120
02121
02122 EnterCriticalSection(&csDescriptorList);
02123
02124 *d->prev = d->next;
02125 if (d->next)
02126 {
02127 d->next->prev = d->prev;
02128 }
02129
02130 d->next = 0;
02131 d->prev = 0;
02132
02133
02134 LeaveCriticalSection(&csDescriptorList);
02135
02136
02137
02138
02139
02140
02141 if (!PostQueuedCompletionStatus(CompletionPort, 0, (DWORD) d, &lpo_aborted))
02142 {
02143 Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in shutdownsock" ENDLINE, GetLastError());
02144 }
02145
02146 }
02147 #endif // WIN32
02148
02149 int make_nonblocking(SOCKET s)
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 }
02188
02189 static void make_nolinger(SOCKET s)
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 }
02201
02202 static void config_socket(SOCKET s)
02203 {
02204 make_nonblocking(s);
02205 make_nolinger(s);
02206 }
02207
02208
02209
02210 DESC *initializesock(SOCKET s, struct sockaddr_in *a)
02211 {
02212 DESC *d;
02213
02214 #ifdef WIN32
02215
02216
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
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
02283
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
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;
02314 d->bConnectionShutdown = false;
02315 d->bConnectionDropped = false;
02316 d->bCallProcessOutputLater = false;
02317 }
02318 #endif // WIN32
02319 return d;
02320 }
02321
02322 #ifdef WIN32
02323 FTASK *process_output = 0;
02324
02325 void process_output9x(void *dvoid, int bHandleShutdown)
02326 {
02327 DESC *d = (DESC *)dvoid;
02328 int cnt;
02329
02330 char *cmdsave = mudstate.debug_cmd;
02331 mudstate.debug_cmd = "< process_output >";
02332
02333 TBLOCK *tb = d->output_head;
02334
02335 while (tb != NULL)
02336 {
02337 while (tb->hdr.nchars > 0)
02338 {
02339 cnt = SOCKET_WRITE(d->descriptor, tb->hdr.start, tb->hdr.nchars, 0);
02340 if (IS_SOCKET_ERROR(cnt))
02341 {
02342 int iSocketError = SOCKET_LAST_ERROR;
02343 if ( iSocketError != SOCKET_EWOULDBLOCK
02344 #ifdef SOCKET_EAGAIN
02345 && iSocketError != SOCKET_EAGAIN
02346 #endif
02347 && bHandleShutdown)
02348 {
02349 shutdownsock(d, R_SOCKDIED);
02350 }
02351 mudstate.debug_cmd = cmdsave;
02352 return;
02353 }
02354 d->output_size -= cnt;
02355 tb->hdr.nchars -= cnt;
02356 tb->hdr.start += cnt;
02357 }
02358 TBLOCK *save = tb;
02359 tb = tb->hdr.nxt;
02360 MEMFREE(save);
02361 save = NULL;
02362 d->output_head = tb;
02363 if (tb == NULL)
02364 {
02365 d->output_tail = NULL;
02366 }
02367 }
02368 mudstate.debug_cmd = cmdsave;
02369 }
02370
02371 static int AsyncSend(DESC *d, char *buf, int len)
02372 {
02373 DWORD nBytes;
02374
02375
02376
02377 if (len <= SIZEOF_OVERLAPPED_BUFFERS)
02378 {
02379
02380
02381 nBytes = len;
02382 }
02383 else
02384 {
02385
02386
02387 nBytes = SIZEOF_OVERLAPPED_BUFFERS;
02388 }
02389 memcpy(d->output_buffer, buf, nBytes);
02390
02391 d->OutboundOverlapped.Offset = 0;
02392 d->OutboundOverlapped.OffsetHigh = 0;
02393
02394 BOOL bResult = WriteFile((HANDLE) d->descriptor, d->output_buffer, nBytes, NULL, &d->OutboundOverlapped);
02395
02396 d->bWritePending = false;
02397
02398 if (!bResult)
02399 {
02400 DWORD dwLastError = GetLastError();
02401 if (dwLastError == ERROR_IO_PENDING)
02402 {
02403 d->bWritePending = true;
02404 }
02405 else
02406 {
02407 if (!(d->bConnectionDropped))
02408 {
02409
02410
02411 d->bConnectionDropped = true;
02412 Log.tinyprintf("AsyncSend(%d) failed with error %ld. Requesting port shutdown." ENDLINE, d->descriptor, dwLastError);
02413 if (!PostQueuedCompletionStatus(CompletionPort, 0, (DWORD) d, &lpo_shutdown))
02414 {
02415 Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in AsyncSend" ENDLINE, GetLastError());
02416 }
02417 }
02418 return 0;
02419 }
02420 }
02421 return nBytes;
02422 }
02423
02424 void process_outputNT(void *dvoid, int bHandleShutdown)
02425 {
02426 UNUSED_PARAMETER(bHandleShutdown);
02427
02428 DESC *d = (DESC *)dvoid;
02429
02430
02431
02432 if (d->bConnectionDropped || d->bWritePending)
02433 {
02434 return;
02435 }
02436
02437 char *cmdsave = mudstate.debug_cmd;
02438 mudstate.debug_cmd = "< process_output >";
02439
02440 TBLOCK *tb = d->output_head;
02441 TBLOCK *save;
02442 int cnt;
02443
02444 if (tb != NULL)
02445 {
02446 while (tb->hdr.nchars == 0)
02447 {
02448 save = tb;
02449 tb = tb->hdr.nxt;
02450 MEMFREE(save);
02451 save = NULL;
02452 d->output_head = tb;
02453 if (tb == NULL)
02454 {
02455 d->output_tail = NULL;
02456 break;
02457 }
02458 }
02459
02460 if (tb != NULL)
02461 {
02462 if (tb->hdr.nchars > 0)
02463 {
02464 cnt = AsyncSend(d, tb->hdr.start, tb->hdr.nchars);
02465 if (cnt <= 0)
02466 {
02467 mudstate.debug_cmd = cmdsave;
02468 return;
02469 }
02470 d->output_size -= cnt;
02471 tb->hdr.nchars -= cnt;
02472 tb->hdr.start += cnt;
02473 }
02474 if (tb->hdr.nchars <= 0)
02475 {
02476 save = tb;
02477 tb = tb->hdr.nxt;
02478 MEMFREE(save);
02479 save = NULL;
02480 d->output_head = tb;
02481 if (tb == NULL)
02482 {
02483 d->output_tail = NULL;
02484 }
02485 }
02486 }
02487 }
02488 mudstate.debug_cmd = cmdsave;
02489 }
02490
02491 #else // WIN32
02492
02493 void process_output(void *dvoid, int bHandleShutdown)
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
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 }
02537 #endif // WIN32
02538
02555 static const unsigned char nvt_input_xlat_table[256] =
02556 {
02557
02558
02559 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 3, 0, 0,
02560 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02561 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02562 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02563 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02564 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02565 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02566 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
02567
02568 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02569 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02570 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02571 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02572 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02573 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
02574 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
02575 4, 5, 5, 5, 5, 5, 6, 7, 5, 5, 8, 9, 10, 11, 12, 13
02576 };
02577
02602 static const int nvt_input_action_table[8][14] =
02603 {
02604
02605 { 1, 2, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5 },
02606 { 4, 4, 4, 4, 4, 4, 12, 2, 10, 6, 7, 8, 9, 1 },
02607 { 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 4 },
02608 { 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 4 },
02609 { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4 },
02610 { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 4 },
02611 { 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 11 },
02612 { 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 17 },
02613 };
02614
02629 int HimState(DESC *d, unsigned char chOption)
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 }
02645
02660 int UsState(DESC *d, unsigned char chOption)
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 }
02676
02685 static void SetHimState(DESC *d, unsigned char chOption, int iHimState)
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 }
02700
02709 static void SetUsState(DESC *d, unsigned char chOption, int iUsState)
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 }
02732
02740 static void SendWill(DESC *d, unsigned char chOption)
02741 {
02742 char aWill[3] = { NVT_IAC, NVT_WILL, 0 };
02743 aWill[2] = chOption;
02744 queue_write_LEN(d, aWill, sizeof(aWill));
02745 }
02746
02754 static void SendDont(DESC *d, unsigned char chOption)
02755 {
02756 char aDont[3] = { NVT_IAC, NVT_DONT, 0 };
02757 aDont[2] = chOption;
02758 queue_write_LEN(d, aDont, sizeof(aDont));
02759 }
02760
02768 static void SendDo(DESC *d, unsigned char chOption)
02769 {
02770 char aDo[3] = { NVT_IAC, NVT_DO, 0 };
02771 aDo[2] = chOption;
02772 queue_write_LEN(d, aDo, sizeof(aDo));
02773 }
02774
02782 static void SendWont(DESC *d, unsigned char chOption)
02783 {
02784 char aWont[3] = { NVT_IAC, NVT_WONT, 0 };
02785 aWont[2] = chOption;
02786 queue_write_LEN(d, aWont, sizeof(aWont));
02787 }
02788
02797 static bool DesiredHimOption(DESC *d, unsigned char chOption)
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 }
02809
02822 static bool DesiredUsOption(DESC *d, unsigned char chOption)
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 }
02832
02844 void EnableHim(DESC *d, unsigned char chOption)
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 }
02862
02874 void DisableHim(DESC *d, unsigned char chOption)
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 }
02892
02904 void EnableUs(DESC *d, unsigned char chOption)
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 }
02922
02934 void DisableUs(DESC *d, unsigned char chOption)
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 }
02952
02965 void TelnetSetup(DESC *d)
02966 {
02967
02968
02969
02970 EnableUs(d, TELNET_EOR);
02971 EnableHim(d, TELNET_EOR);
02972 EnableHim(d, TELNET_SGA);
02973 EnableHim(d, TELNET_NAWS);
02974 }
02975
02993 static void process_input_helper(DESC *d, char *pBytes, int nBytes)
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
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
03037
03038 break;
03039
03040 case 2:
03041
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
03055
03056 nInputBytes -= 1;
03057 p--;
03058 }
03059 d->raw_input_state = NVT_IS_NORMAL;
03060 break;
03061
03062 case 3:
03063
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
03078
03079 d->raw_input_state = NVT_IS_NORMAL;
03080 break;
03081
03082 case 5:
03083
03084
03085 d->raw_input_state = NVT_IS_HAVE_IAC;
03086 break;
03087
03088 case 6:
03089
03090
03091 d->raw_input_state = NVT_IS_HAVE_IAC_WILL;
03092 break;
03093
03094 case 7:
03095
03096
03097 d->raw_input_state = NVT_IS_HAVE_IAC_DONT;
03098 break;
03099
03100 case 8:
03101
03102
03103 d->raw_input_state = NVT_IS_HAVE_IAC_DO;
03104 break;
03105
03106 case 9:
03107
03108
03109 d->raw_input_state = NVT_IS_HAVE_IAC_WONT;
03110 break;
03111
03112 case 10:
03113
03114
03115 q = d->aOption;
03116 d->raw_input_state = NVT_IS_HAVE_IAC_SB;
03117 break;
03118
03119 case 11:
03120
03121
03122 d->raw_input_state = NVT_IS_HAVE_IAC_SB_IAC;
03123 break;
03124
03125 case 12:
03126
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
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
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
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
03222
03223
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
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
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 }
03308
03309 bool process_input(DESC *d)
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
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 }
03335
03336 void close_sockets(bool emergency, char *message)
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 }
03370
03371 void emergency_shutdown(void)
03372 {
03373 close_sockets(true, "Going down - Bye");
03374 }
03375
03376
03377
03378
03379
03380 static void check_panicking(int sig)
03381 {
03382
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 }
03399
03400 static void unset_signals(void)
03401 {
03402 int i;
03403
03404 for (i = 0; i < NSIG; i++)
03405 {
03406 signal(i, SIG_DFL);
03407 }
03408 }
03409
03410 #ifdef _SGI_SOURCE
03411 #define CAST_SIGNAL_FUNC (SIG_PF)
03412 #else // _SGI_SOURCE
03413 #define CAST_SIGNAL_FUNC
03414 #endif // _SGI_SOURCE
03415
03416
03417
03418
03419
03420 typedef struct
03421 {
03422 int iSignal;
03423 const char *szSignal;
03424 } SIGNALTYPE, *PSIGNALTYPE;
03425
03426 const SIGNALTYPE aSigTypes[] =
03427 {
03428 #ifdef SIGHUP
03429
03430
03431 { SIGHUP, "SIGHUP"},
03432 #endif // SIGHUP
03433 #ifdef SIGINT
03434
03435
03436 { SIGINT, "SIGINT"},
03437 #endif // SIGINT
03438 #ifdef SIGQUIT
03439
03440
03441 { SIGQUIT, "SIGQUIT"},
03442 #endif // SIGQUIT
03443 #ifdef SIGILL
03444
03445
03446 { SIGILL, "SIGILL"},
03447 #endif // SIGILL
03448 #ifdef SIGTRAP
03449
03450
03451 { SIGTRAP, "SIGTRAP"},
03452 #endif // SIGTRAP
03453 #if defined(SIGABRT)
03454
03455
03456 { SIGABRT, "SIGABRT"},
03457 #elif defined(SIGIOT)
03458 #define SIGABRT SIGIOT
03459
03460
03461 { SIGIOT, "SIGIOT"},
03462 #endif // SIGABRT
03463 #ifdef SIGEMT
03464 { SIGEMT, "SIGEMT"},
03465 #endif // SIGEMT
03466 #ifdef SIGFPE
03467
03468
03469 { SIGFPE, "SIGFPE"},
03470 #endif // SIGFPE
03471 #ifdef SIGKILL
03472
03473
03474 { SIGKILL, "SIGKILL"},
03475 #endif // SIGKILL
03476 #ifdef SIGSEGV
03477
03478
03479 { SIGSEGV, "SIGSEGV"},
03480 #endif // SIGSEGV
03481 #ifdef SIGPIPE
03482
03483
03484 { SIGPIPE, "SIGPIPE"},
03485 #endif // SIGPIPE
03486 #ifdef SIGALRM
03487
03488
03489 { SIGALRM, "SIGALRM"},
03490 #endif // SIGALRM
03491 #ifdef SIGTERM
03492
03493
03494 { SIGTERM, "SIGTERM"},
03495 #endif // SIGTERM
03496 #ifdef SIGBREAK
03497
03498
03499 { SIGBREAK, "SIGBREAK"},
03500 #endif // SIGBREAK
03501 #ifdef SIGUSR1
03502
03503
03504 { SIGUSR1, "SIGUSR1"},
03505 #endif // SIGUSR1
03506 #ifdef SIGUSR2
03507
03508
03509 { SIGUSR2, "SIGUSR2"},
03510 #endif // SIGUSR2
03511 #if defined(SIGCHLD)
03512
03513
03514 { SIGCHLD, "SIGCHLD"},
03515 #elif defined(SIGCLD)
03516 #define SIGCHLD SIGCLD
03517
03518
03519 { SIGCLD, "SIGCLD"},
03520 #endif // SIGCHLD
03521 #ifdef SIGCONT
03522
03523
03524 { SIGCONT, "SIGCONT"},
03525 #endif // SIGCONT
03526 #ifdef SIGSTOP
03527
03528
03529 { SIGSTOP, "SIGSTOP"},
03530 #endif // SIGSTOP
03531 #ifdef SIGTSTP
03532
03533
03534 { SIGTSTP, "SIGTSTP"},
03535 #endif // SIGTSTP
03536 #ifdef SIGTTIN
03537
03538
03539 { SIGTTIN, "SIGTTIN"},
03540 #endif // SIGTTIN
03541 #ifdef SIGTTOU
03542
03543
03544 { SIGTTOU, "SIGTTOU"},
03545 #endif // SIGTTOU
03546 #ifdef SIGBUS
03547
03548
03549 { SIGBUS, "SIGBUS"},
03550 #endif // SIGBUS
03551 #ifdef SIGPROF
03552
03553
03554 { SIGPROF, "SIGPROF"},
03555 #endif // SIGPROF
03556 #ifdef SIGSYS
03557
03558
03559 { SIGSYS, "SIGSYS"},
03560 #endif // SIGSYS
03561 #ifdef SIGURG
03562
03563
03564 { SIGURG, "SIGURG"},
03565 #endif // SIGURG
03566 #ifdef SIGVTALRM
03567
03568
03569 { SIGVTALRM, "SIGVTALRM"},
03570 #endif // SIGVTALRM
03571 #ifdef SIGXCPU
03572
03573
03574 { SIGXCPU, "SIGXCPU"},
03575 #endif // SIGXCPU
03576 #ifdef SIGXFSZ
03577
03578
03579 { SIGXFSZ, "SIGXFSZ"},
03580 #endif // SIGXFSZ
03581 #ifdef SIGSTKFLT
03582
03583
03584 { SIGSTKFLT, "SIGSTKFLT"},
03585 #endif // SIGSTKFLT
03586 #if defined(SIGIO)
03587
03588
03589 { SIGIO, "SIGIO"},
03590 #elif defined(SIGPOLL)
03591 #define SIGIO SIGPOLL
03592
03593
03594 { SIGPOLL, "SIGPOLL"},
03595 #endif // SIGIO
03596 #ifdef SIGLOST
03597 { SIGLOST, "SIGLOST"},
03598 #endif // SIGLOST
03599 #if defined(SIGPWR)
03600
03601
03602 { SIGPWR, "SIGPWR"},
03603 #elif defined(SIGINFO)
03604 #define SIGPWR SIGINFO
03605
03606
03607 { SIGINFO, "SIGINFO"},
03608 #endif // SIGPWR
03609 #ifdef SIGWINCH
03610
03611
03612 { SIGWINCH, "SIGWINCH"},
03613 #endif // SIGWINCH
03614 { 0, "SIGZERO" },
03615 { -1, NULL }
03616 };
03617
03618 typedef struct
03619 {
03620 const char *pShortName;
03621 const char *pLongName;
03622 } MUX_SIGNAMES;
03623
03624 static MUX_SIGNAMES signames[NSIG];
03625
03626 #if defined(HAVE_SYS_SIGNAME)
03627 #define SysSigNames sys_signame
03628 #elif defined(SYS_SIGLIST_DECLARED)
03629 #define SysSigNames sys_siglist
03630 #endif // HAVE_SYS_SIGNAME
03631
03632 void BuildSignalNamesTable(void)
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
03687
03688 tsn->pShortName = StringClone(tprintf("SIG%03d", i));
03689 }
03690 }
03691 }
03692
03693 static char *SignalDesc(int iSignal)
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 }
03707
03708 static void log_signal(int iSignal)
03709 {
03710 STARTLOG(LOG_PROBLEMS, "SIG", "CATCH");
03711 log_text("Caught signal ");
03712 log_text(SignalDesc(iSignal));
03713 ENDLOG;
03714 }
03715
03716 #ifndef WIN32
03717 static void log_signal_ignore(int iSignal)
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 }
03725
03726 void LogStatBuf(int stat_buf, const char *Name)
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 }
03743 #endif
03744
03745 static RETSIGTYPE DCL_CDECL sighandler(int sig)
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
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
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
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
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
03820
03821 mudstate.dumper = 0;
03822 mudstate.dumped = 0;
03823 }
03824 else
03825 {
03826
03827
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
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
03867
03868 log_signal(sig);
03869 MuxAlarm.Signal();
03870 break;
03871 #endif
03872
03873 #endif // !WIN32
03874
03875 case SIGINT:
03876
03877
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
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
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
03940
03941
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
03956
03957 if (!fork())
03958 {
03959
03960
03961 unset_signals();
03962 exit(1);
03963 }
03964
03965
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
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 }
04007
04008 NAMETAB sigactions_nametab[] =
04009 {
04010 {"exit", 3, 0, SA_EXIT},
04011 {"default", 1, 0, SA_DFLT},
04012 { NULL, 0, 0, 0}
04013 };
04014
04015 void set_signals(void)
04016 {
04017 #ifndef WIN32
04018 sigset_t sigs;
04019
04020
04021
04022
04023
04024
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 }
04069
04070 void list_system_resources(dbref player)
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 }
04106
04107 #ifdef WIN32
04108
04109
04110
04111
04112
04113 void __cdecl MUDListenThread(void * pVoid)
04114 {
04115 PortInfo *Port = (PortInfo *)pVoid;
04116
04117 SOCKADDR_IN SockAddr;
04118 int nLen;
04119 BOOL b;
04120
04121 struct descriptor_data * d;
04122
04123 Log.tinyprintf("Starting NT-style listening on port %d" ENDLINE, Port->port);
04124
04125
04126
04127
04128 for (;;)
04129 {
04130
04131
04132
04133 nLen = sizeof(SOCKADDR_IN);
04134 SOCKET socketClient = accept(Port->socket, (LPSOCKADDR) &SockAddr,
04135 &nLen);
04136
04137 if (socketClient == INVALID_SOCKET)
04138 {
04139
04140
04141
04142 break;
04143 }
04144
04145 DebugTotalSockets++;
04146 if (site_check(SockAddr.sin_addr, mudstate.access_list) == H_FORBIDDEN)
04147 {
04148 STARTLOG(LOG_NET | LOG_SECURITY, "NET", "SITE");
04149 Log.tinyprintf("[%d/%s] Connection refused. (Remote port %d)",
04150 socketClient, inet_ntoa(SockAddr.sin_addr), ntohs(SockAddr.sin_port));
04151 ENDLOG;
04152
04153
04154
04155
04156
04157
04158
04159
04160 shutdown(socketClient, SD_BOTH);
04161 if (closesocket(socketClient) == 0)
04162 {
04163 DebugTotalSockets--;
04164 }
04165 continue;
04166 }
04167
04168
04169
04170
04171
04172
04173 if (bSlaveBooted && (WAIT_OBJECT_0 == WaitForSingleObject(hSlaveRequestStackSemaphore, 5000)))
04174 {
04175
04176
04177 if (iSlaveRequest < SLAVE_REQUEST_STACK_SIZE)
04178 {
04179
04180
04181 SlaveRequests[iSlaveRequest].sa_in = SockAddr;
04182 SlaveRequests[iSlaveRequest].port_in = mudconf.ports.pi[0];
04183 iSlaveRequest++;
04184 ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL);
04185
04186
04187
04188 ReleaseSemaphore(hSlaveThreadsSemaphore, 1, NULL);
04189 }
04190 else
04191 {
04192
04193
04194 ReleaseSemaphore(hSlaveRequestStackSemaphore, 1, NULL);
04195 }
04196 }
04197 d = initializesock(socketClient, &SockAddr);
04198
04199
04200
04201 CompletionPort = CreateIoCompletionPort((HANDLE)socketClient, CompletionPort, (DWORD) d, 1);
04202
04203 if (!CompletionPort)
04204 {
04205 Log.tinyprintf("Error %ld on CreateIoCompletionPort for socket %ld" ENDLINE, GetLastError(), socketClient);
04206 shutdownsock_brief(d);
04207 continue;
04208 }
04209
04210 TelnetSetup(d);
04211
04212 if (!PostQueuedCompletionStatus(CompletionPort, 0, (DWORD) d, &lpo_welcome))
04213 {
04214 Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (read)" ENDLINE, GetLastError());
04215 shutdownsock_brief(d);
04216 continue;
04217 }
04218
04219
04220
04221 b = ReadFile((HANDLE) socketClient, d->input_buffer, sizeof(d->input_buffer), NULL, &d->InboundOverlapped);
04222
04223 if (!b && GetLastError() != ERROR_IO_PENDING)
04224 {
04225
04226
04227 d->bConnectionDropped = true;
04228 Log.tinyprintf("ProcessWindowsTCP(%d) cannot queue read request with error %ld. Requesting port shutdown." ENDLINE, d->descriptor, GetLastError());
04229 if (!PostQueuedCompletionStatus(CompletionPort, 0, (DWORD) d, &lpo_shutdown))
04230 {
04231 Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (initial read)" ENDLINE, GetLastError());
04232 }
04233 }
04234 }
04235 Log.tinyprintf("End of NT-style listening on port %d" ENDLINE, Port->port);
04236 }
04237
04238
04239 void Task_FreeDescriptor(void *arg_voidptr, int arg_Integer)
04240 {
04241 UNUSED_PARAMETER(arg_Integer);
04242
04243 DESC *d = (DESC *)arg_voidptr;
04244 if (d)
04245 {
04246 EnterCriticalSection(&csDescriptorList);
04247 ndescriptors--;
04248 freeqs(d);
04249 free_desc(d);
04250 LeaveCriticalSection(&csDescriptorList);
04251 }
04252 }
04253
04254 void Task_DeferredClose(void *arg_voidptr, int arg_Integer)
04255 {
04256 UNUSED_PARAMETER(arg_Integer);
04257
04258 DESC *d = (DESC *)arg_voidptr;
04259 if (d)
04260 {
04261 d->bConnectionDropped = true;
04262
04263
04264
04265 if (!fpCancelIo((HANDLE) d->descriptor))
04266 {
04267 Log.tinyprintf("Error %ld on CancelIo" ENDLINE, GetLastError());
04268 }
04269
04270 shutdown(d->descriptor, SD_BOTH);
04271 if (SOCKET_CLOSE(d->descriptor) == 0)
04272 {
04273 DebugTotalSockets--;
04274 }
04275 d->descriptor = INVALID_SOCKET;
04276
04277
04278
04279
04280
04281
04282 if (!PostQueuedCompletionStatus(CompletionPort, 0, (DWORD) d, &lpo_aborted))
04283 {
04284 Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in shutdownsock" ENDLINE, GetLastError());
04285 }
04286 }
04287 }
04288
04289
04290
04291
04292
04293
04294
04295
04296
04297
04298
04299
04300
04301
04302
04303
04304
04305
04306
04307
04308
04309
04310 void ProcessWindowsTCP(DWORD dwTimeout)
04311 {
04312 LPOVERLAPPED lpo;
04313 DWORD nbytes;
04314 DESC *d;
04315
04316 for ( ; ; dwTimeout = 0)
04317 {
04318
04319
04320 BOOL b = GetQueuedCompletionStatus(CompletionPort, &nbytes, (LPDWORD) &d, &lpo, dwTimeout);
04321
04322 if (!b)
04323 {
04324 DWORD dwLastError = GetLastError();
04325
04326
04327
04328 switch (dwLastError)
04329 {
04330 case WAIT_TIMEOUT:
04331
04332 return;
04333
04334 case ERROR_OPERATION_ABORTED:
04335
04336 continue;
04337
04338 default:
04339 if (!(d->bConnectionDropped))
04340 {
04341
04342
04343 d->bConnectionDropped = true;
04344
04345
04346
04347 Log.tinyprintf("ProcessWindowsTCP(%d) failed IO with error %ld. Requesting port shutdown." ENDLINE, d->descriptor, dwLastError);
04348 if (!PostQueuedCompletionStatus(CompletionPort, 0, (DWORD) d, &lpo_shutdown))
04349 {
04350 Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (write)" ENDLINE, GetLastError());
04351 }
04352 }
04353 }
04354 }
04355 else if (lpo == &d->OutboundOverlapped && !d->bConnectionDropped)
04356 {
04357
04358
04359
04360
04361 TBLOCK *tp;
04362 DWORD nBytes;
04363
04364 bool bNothingToWrite;
04365 do
04366 {
04367 bNothingToWrite = true;
04368 tp = d->output_head;
04369 if (tp == NULL)
04370 {
04371 d->bWritePending = false;
04372 break;
04373 }
04374 bNothingToWrite = true;
04375
04376
04377
04378 if (tp->hdr.nchars <= SIZEOF_OVERLAPPED_BUFFERS)
04379 {
04380
04381
04382 nBytes = tp->hdr.nchars;
04383 memcpy(d->output_buffer, tp->hdr.start, nBytes);
04384 TBLOCK *save = tp;
04385 tp = tp->hdr.nxt;
04386 MEMFREE(save);
04387 save = NULL;
04388 d->output_head = tp;
04389 if (tp == NULL)
04390 {
04391
04392 d->output_tail = NULL;
04393 }
04394 else
04395 {
04396
04397 }
04398 }
04399 else
04400 {
04401
04402
04403 nBytes = SIZEOF_OVERLAPPED_BUFFERS;
04404 memcpy(d->output_buffer, tp->hdr.start, nBytes);
04405 tp->hdr.nchars -= nBytes;
04406 tp->hdr.start += nBytes;
04407
04408 }
04409 d->output_size -= nBytes;
04410
04411 d->OutboundOverlapped.Offset = 0;
04412 d->OutboundOverlapped.OffsetHigh = 0;
04413
04414
04415
04416
04417
04418
04419
04420
04421
04422
04423 DWORD nWritten;
04424 b = WriteFile((HANDLE) d->descriptor, d->output_buffer,
04425 nBytes, &nWritten, &d->OutboundOverlapped);
04426
04427 } while (b);
04428
04429 if (bNothingToWrite)
04430 {
04431 if (d->bConnectionShutdown)
04432 {
04433 scheduler.CancelTask(Task_DeferredClose, d, 0);
04434 scheduler.DeferImmediateTask(PRIORITY_SYSTEM, Task_DeferredClose, d, 0);
04435 }
04436 continue;
04437 }
04438
04439 d->bWritePending = true;
04440 DWORD dwLastError = GetLastError();
04441 if (dwLastError != ERROR_IO_PENDING)
04442 {
04443
04444
04445 d->bWritePending = false;
04446 d->bConnectionDropped = true;
04447 Log.tinyprintf("ProcessWindowsTCP(%d) cannot queue write request with error %ld. Requesting port shutdown." ENDLINE, d->descriptor, dwLastError);
04448 if (!PostQueuedCompletionStatus(CompletionPort, 0, (DWORD) d, &lpo_shutdown))
04449 {
04450 Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (write)" ENDLINE, GetLastError());
04451 }
04452 }
04453 }
04454 else if (lpo == &d->InboundOverlapped && !d->bConnectionDropped)
04455 {
04456
04457
04458
04459 if (nbytes == 0)
04460 {
04461
04462
04463
04464
04465
04466 d->bConnectionDropped = true;
04467 Log.tinyprintf("ProcessWindowsTCP(%d) zero-length read. Requesting port shutdown." ENDLINE, d->descriptor);
04468 if (!PostQueuedCompletionStatus(CompletionPort, 0, (DWORD) d, &lpo_shutdown))
04469 {
04470 Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (read)" ENDLINE, GetLastError());
04471 }
04472 continue;
04473 }
04474
04475 d->last_time.GetUTC();
04476
04477
04478
04479 if (d->flags & DS_AUTODARK)
04480 {
04481
04482
04483 DESC *d1;
04484 DESC_ITER_PLAYER(d->player, d1)
04485 {
04486 d1->flags &= ~DS_AUTODARK;
04487 }
04488 db[d->player].fs.word[FLAG_WORD1] &= ~DARK;
04489 }
04490
04491
04492
04493 process_input_helper(d, d->input_buffer, nbytes);
04494
04495
04496
04497 b = ReadFile((HANDLE) d->descriptor, d->input_buffer, sizeof(d->input_buffer), &nbytes, &d->InboundOverlapped);
04498
04499
04500
04501
04502
04503
04504 if (!b)
04505 {
04506
04507
04508 DWORD dwLastError = GetLastError();
04509 if (dwLastError != ERROR_IO_PENDING)
04510 {
04511
04512
04513 d->bConnectionDropped = true;
04514 Log.tinyprintf("ProcessWindowsTCP(%d) cannot queue read request with error %ld. Requesting port shutdown." ENDLINE, d->descriptor, dwLastError);
04515 if (!PostQueuedCompletionStatus(CompletionPort, 0, (DWORD) d, &lpo_shutdown))
04516 {
04517 Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (read)" ENDLINE, GetLastError());
04518 }
04519 }
04520 }
04521 }
04522 else if (lpo == &lpo_welcome)
04523 {
04524 char *buff = alloc_mbuf("ProcessWindowsTCP.Premature");
04525 strcpy(buff, inet_ntoa(d->address.sin_addr));
04526
04527
04528
04529
04530
04531 bool bInvalidSocket = IS_INVALID_SOCKET(d->descriptor);
04532
04533
04534
04535 STARTLOG(LOG_NET | LOG_LOGIN, "NET", "CONN");
04536 Log.tinyprintf("[%s/%s] Connection opened (remote port %d)",
04537 bInvalidSocket ? "UNKNOWN" : mux_ltoa_t(d->descriptor), buff,
04538 ntohs(d->address.sin_port));
04539 ENDLOG;
04540
04541 SiteMonSend(d->descriptor, buff, d, "Connection");
04542
04543 if (bInvalidSocket)
04544 {
04545
04546
04547 STARTLOG(LOG_NET | LOG_LOGIN, "NET", "DISC");
04548 Log.tinyprintf("[UNKNOWN/%s] Connection closed prematurely (remote port %d)",
04549 buff, ntohs(d->address.sin_port));
04550 ENDLOG;
04551
04552 SiteMonSend(d->descriptor, buff, d, "Connection closed prematurely");
04553 }
04554 else
04555 {
04556
04557
04558 welcome_user(d);
04559 }
04560 free_mbuf(buff);
04561 }
04562 else if (lpo == &lpo_shutdown)
04563 {
04564
04565
04566
04567 shutdownsock(d, R_SOCKDIED);
04568 }
04569 else if (lpo == &lpo_aborted)
04570 {
04571
04572
04573
04574
04575 if (!PostQueuedCompletionStatus(CompletionPort, 0, (DWORD) d, &lpo_aborted_final))
04576 {
04577 Log.tinyprintf("Error %ld on PostQueuedCompletionStatus in ProcessWindowsTCP (aborted)" ENDLINE, GetLastError());
04578 }
04579 }
04580 else if (lpo == &lpo_aborted_final)
04581 {
04582
04583
04584
04585
04586
04587 scheduler.DeferImmediateTask(PRIORITY_SYSTEM, Task_FreeDescriptor, d, 0);
04588 }
04589 else if (lpo == &lpo_wakeup)
04590 {
04591
04592
04593 }
04594 }
04595 }
04596
04597 #endif // WIN32
04598
04599 void SiteMonSend(int port, const char *address, DESC *d, const char *msg)
04600 {
04601
04602
04603 if ( d != NULL
04604 && (d->host_info & H_NOSITEMON))
04605 {
04606 return;
04607 }
04608
04609
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 }