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 }