00001
00002
00003
00004
00005 #include "copyright.h"
00006 #include "config.h"
00007
00008 #include <sys/types.h>
00009 #include <sys/stat.h>
00010 #include <unistd.h>
00011 #include <sys/file.h>
00012 #include <sys/ioctl.h>
00013 #include <sys/wait.h>
00014 #include <signal.h>
00015 #include <errno.h>
00016
00017 #include "mudconf.h"
00018 #include "db.h"
00019 #include "file_c.h"
00020 #include "externs.h"
00021 #include "interface.h"
00022 #include "flags.h"
00023 #include "powers.h"
00024 #include "alloc.h"
00025 #include "command.h"
00026 #include "attrs.h"
00027 #include "rbtree.h"
00028 #include <errno.h>
00029 #include "logcache.h"
00030
00031 #include "debug.h"
00032
00033 #if SQL_SUPPORT
00034 #include "sqlchild.h"
00035 #endif
00036
00037 struct event listen_sock_ev;
00038 #ifdef IPV6_SUPPORT
00039 struct event listen6_sock_ev;
00040 #endif
00041
00042 int mux_bound_socket = -1;
00043 #ifdef IPV6_SUPPORT
00044 int mux_bound_socket6 = -1;
00045 #endif
00046 int ndescriptors = 0;
00047
00048 DESC *descriptor_list = NULL;
00049
00050 void mux_release_socket();
00051 void make_nonblocking(int s);
00052 void accept_new_connection(int, short, void *);
00053 DESC *initializesock(int, struct sockaddr_storage *, int);
00054 DESC *new_connection(int);
00055 int process_input(DESC *);
00056
00057 int desc_cmp(void *vleft, void *vright, void *token)
00058 {
00059 dbref left = (dbref) vleft;
00060 dbref right = (dbref) vright;
00061
00062 return (left - right);
00063 }
00064
00065 void desc_addhash(DESC * d)
00066 {
00067 DESC *hdesc;
00068
00069 bind_descriptor(d);
00070
00071 hdesc = (DESC *) rb_find(mudstate.desctree, (void *) d->player);
00072
00073
00074
00075
00076
00077
00078
00079
00080 d->hashnext = hdesc;
00081 rb_insert(mudstate.desctree, (void *) d->player, d);
00082 }
00083
00084 void desc_delhash(DESC * d)
00085 {
00086 char buffer2[4096];
00087 DESC *hdesc = NULL;
00088 char buffer[4096];
00089
00090 hdesc = (DESC *) rb_find(mudstate.desctree, (void *) d->player);
00091
00092
00093
00094 if(!hdesc) {
00095 snprintf(buffer, 4096,
00096 "desc_delhash: unable to find player(%d)'s descriptors from hashtable.\n",
00097 d->player);
00098 log_text(buffer);
00099 release_descriptor(d);
00100 return;
00101 }
00102
00103
00104
00105
00106 if(hdesc == d && hdesc->hashnext) {
00107
00108 rb_insert(mudstate.desctree, (void *) d->player, d->hashnext);
00109 d->hashnext = NULL;
00110 release_descriptor(d);
00111 return;
00112 } else if(hdesc == d) {
00113
00114 rb_delete(mudstate.desctree, (void *) d->player);
00115 release_descriptor(d);
00116 return;
00117 }
00118
00119 while(hdesc->hashnext != NULL) {
00120 if(hdesc->hashnext == d) {
00121 hdesc->hashnext = d->hashnext;
00122 break;
00123 }
00124 hdesc = hdesc->hashnext;
00125 }
00126 d->hashnext = NULL;
00127 release_descriptor(d);
00128 return;
00129 }
00130
00131 void bind_descriptor(DESC *d) {
00132 d->refcount++;
00133
00134 }
00135
00136 void release_descriptor(DESC *d) {
00137 d->refcount--;
00138
00139 if(d->refcount == 0) {
00140 dprintk("%p destructing", d);
00141 freeqs(d);
00142
00143 if(d->program_data != NULL) {
00144 int num = 0;
00145 DESC *dtemp;
00146 DESC_ITER_PLAYER(d->player, dtemp) num++;
00147
00148 if(num == 0) {
00149 for(int i = 0; i < MAX_GLOBAL_REGS; i++) {
00150 free_lbuf(d->program_data->wait_regs[i]);
00151 }
00152 free(d->program_data);
00153 }
00154 }
00155 clearstrings(d);
00156 if(d->descriptor) {
00157 fsync(d->descriptor);
00158 event_del(&d->sock_ev);
00159 shutdown(d->descriptor, 2);
00160 close(d->descriptor);
00161 }
00162 d->descriptor = 0;
00163 if(d->sock_buff)
00164 bufferevent_free(d->sock_buff);
00165 d->sock_buff = NULL;
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188 if (d->prev)
00189 d->prev->next = d->next;
00190 else
00191 descriptor_list = d->next;
00192 if (d->next)
00193 d->next->prev = d->prev;
00194
00195 ndescriptors--;
00196 free(d);
00197 }
00198 }
00199
00200 void shutdown_services()
00201 {
00202 dnschild_destruct();
00203 flush_sockets();
00204 #ifdef SQL_SUPPORT
00205 sqlchild_destruct();
00206 #endif
00207 #ifdef ARBITRARY_LOGFILES
00208 logcache_destruct();
00209 #endif
00210 event_loopexit(NULL);
00211 }
00212
00213 int bind_mux_socket(int port)
00214 {
00215 int s, opt;
00216 struct sockaddr_in server;
00217
00218 s = socket(AF_INET, SOCK_STREAM, 0);
00219 if(s < 0) {
00220 log_perror("NET", "FAIL", NULL, "creating master socket");
00221 exit(3);
00222 }
00223 opt = 1;
00224 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt,
00225 sizeof(opt)) < 0) {
00226 log_perror("NET", "FAIL", NULL, "setsockopt");
00227 }
00228
00229 if(fcntl(s, F_SETFD, FD_CLOEXEC) < 0) {
00230 log_perror("LOGCACHE", "FAIL", NULL,
00231 "fcntl(fd, F_SETFD, FD_CLOEXEC)");
00232 close(s);
00233 abort();
00234 }
00235 server.sin_family = AF_INET;
00236 server.sin_addr.s_addr = INADDR_ANY;
00237 server.sin_port = htons(port);
00238 if(bind(s, (struct sockaddr *) &server, sizeof(server))) {
00239 log_perror("NET", "FAIL", NULL, "bind");
00240 close(s);
00241 exit(4);
00242 }
00243 dprintk("connection socket raised and bound, %d", s);
00244 listen(s, 25);
00245 return s;
00246 }
00247
00248 void mux_release_socket()
00249 {
00250 dprintk("releasing mux main socket.");
00251 event_del(&listen_sock_ev);
00252 close(mux_bound_socket);
00253 mux_bound_socket = -1;
00254 #ifdef IPV6_SUPPORT
00255 event_del(&listen6_sock_ev);
00256 close(mux_bound_socket6);
00257 mux_bound_socket6 = -1;
00258 #endif
00259 }
00260
00261 int eradicate_broken_fd(int fd)
00262 {
00263 struct stat statbuf;
00264 DESC *d, *dtemp;
00265
00266 DESC_SAFEITER_ALL(d, dtemp) {
00267 if((fd && d->descriptor == fd) ||
00268 (!fd && fstat(d->descriptor, &statbuf) < 0)) {
00269
00270 log_error(LOG_PROBLEMS, "ERR", "EBADF",
00271 "Broken descriptor %d for player #%d", d->descriptor,
00272 d->player);
00273 close(d->descriptor);
00274 shutdownsock(d, R_SOCKDIED);
00275 }
00276 }
00277 if(mux_bound_socket != -1 && fstat(mux_bound_socket, &statbuf) < 0) {
00278 log_error(LOG_PROBLEMS, "ERR", "EBADF",
00279 "Broken descriptor on our main port.");
00280 mux_bound_socket = -1;
00281 return -1;
00282 }
00283 #ifdef IPV6_SUPPORT
00284 if(mux_bound_socket6 != -1 && fstat(mux_bound_socket6, &statbuf) < 0) {
00285 log_error(LOG_PROBLEMS, "ERR", "EBADF",
00286 "Broken descriptor for our ipv6 port.");
00287 mux_bound_socket6 = -1;
00288 return -1;
00289 }
00290 #endif
00291 return 0;
00292 }
00293
00294 void accept_client_input(int fd, short event, void *arg)
00295 {
00296 DESC *connection = (DESC *) arg;
00297 if(connection->descriptor != fd) return;
00298
00299
00300
00301 if(connection->flags & DS_AUTODARK) {
00302 connection->flags &= ~DS_AUTODARK;
00303 s_Flags(connection->player, Flags(connection->player) & ~DARK);
00304 }
00305 bind_descriptor(connection);
00306 process_input(connection);
00307
00308 release_descriptor(connection);
00309 }
00310
00311 void bsd_write_callback(struct bufferevent *bufev, void *arg)
00312 {
00313 }
00314
00315 void bsd_read_callback(struct bufferevent *bufev, void *arg)
00316 {
00317 }
00318
00319 void bsd_error_callback(struct bufferevent *bufev, short whut, void *arg)
00320 {
00321 dprintk("error %d", whut);
00322 }
00323
00324 #ifndef HAVE_GETTIMEOFDAY
00325 #define get_tod(x) { (x)->tv_sec = time(NULL); (x)->tv_usec = 0; }
00326 #else
00327 #define get_tod(x) gettimeofday(x, (struct timezone *)0)
00328 #endif
00329
00330 struct timeval queue_slice = { 0, 0 };
00331 struct event queue_ev;
00332 struct timeval last_slice, current_time;
00333
00334 void runqueues(int fd, short event, void *arg)
00335 {
00336 pid_t pchild;
00337 int status = 0;
00338 event_add(&queue_ev, &queue_slice);
00339 get_tod(¤t_time);
00340 last_slice = update_quotas(last_slice, current_time);
00341 pchild = waitpid(-1, &status, WNOHANG);
00342 if(pchild > 0) {
00343 dprintk("unexpected child %d exited with exit status %d.", pchild,
00344 WEXITSTATUS(status));
00345 }
00346 if(mudconf.queue_chunk)
00347 do_top(mudconf.queue_chunk);
00348 }
00349
00350 void shovechars(int port)
00351 {
00352 unsigned int flags;
00353 queue_slice.tv_sec = 0;
00354 queue_slice.tv_usec = mudconf.timeslice * 1000;
00355
00356 dprintk("shovechars starting, sock is %d.", mux_bound_socket);
00357 #ifdef IPV6_SUPPORT
00358 dprintk("shovechars starting, ipv6 sock is %d.", mux_bound_socket);
00359 #endif
00360
00361 if(mux_bound_socket < 0) {
00362 mux_bound_socket = bind_mux_socket(port);
00363 }
00364 event_set(&listen_sock_ev, mux_bound_socket, EV_READ | EV_PERSIST,
00365 accept_new_connection, NULL);
00366 event_add(&listen_sock_ev, NULL);
00367
00368 flags = fcntl(2, F_GETFD, 0);
00369 dprintk("stderr is %x", flags);
00370 #ifdef IPV6_SUPPORT
00371 if(mux_bound_socket6 < 0) {
00372 mux_bound_socket6 = bind_mux6_socket(port);
00373 }
00374 event_set(&listen6_sock_ev, mux_bound_socket6, EV_READ | EV_PERSIST,
00375 accept_new6_connection, NULL);
00376 event_add(&listen6_sock_ev, NULL);
00377 #endif
00378
00379 evtimer_set(&queue_ev, runqueues, NULL);
00380 evtimer_add(&queue_ev, &queue_slice);
00381
00382 get_tod(&last_slice);
00383 get_tod(¤t_time);
00384
00385 event_dispatch();
00386 }
00387
00388 void accept_new_connection(int sock, short event, void *arg)
00389 {
00390 int newsock, addr_len, len;
00391 char *buff, *buff1;
00392 DESC *d;
00393 struct sockaddr_storage addr;
00394 char addrname[1024];
00395 char addrport[32];
00396
00397
00398 addr_len = sizeof(struct sockaddr);
00399
00400 newsock =
00401 accept(sock, (struct sockaddr *) &addr, (unsigned int *) &addr_len);
00402 if(newsock < 0)
00403 return;
00404
00405 getnameinfo((struct sockaddr *) &addr, addr_len,
00406 addrname, 1024, addrport, 32,
00407 NI_NUMERICHOST | NI_NUMERICSERV);
00408
00409 if(site_check(&addr, addr_len, mudstate.access_list) == H_FORBIDDEN) {
00410 log_error(LOG_NET | LOG_SECURITY, "NET", "SITE",
00411 "Connection refused from %s %s.", addrname, addrport);
00412
00413 fcache_rawdump(newsock, FC_CONN_SITE);
00414 shutdown(newsock, 2);
00415 close(newsock);
00416 errno = 0;
00417 d = NULL;
00418 } else {
00419 log_error(LOG_NET, "NET", "CONN", "Connection opened from %s %s.",
00420 addrname, addrport);
00421
00422 d = initializesock(newsock, &addr, addr_len);
00423 }
00424 return;
00425 }
00426
00427
00428
00429
00430
00431 static const char *disc_reasons[] = {
00432 "Unspecified",
00433 "Quit",
00434 "Inactivity Timeout",
00435 "Booted",
00436 "Remote Close or Net Failure",
00437 "Game Shutdown",
00438 "Login Retry Limit",
00439 "Logins Disabled",
00440 "Logout (Connection Not Dropped)",
00441 "Too Many Connected Players"
00442 };
00443
00444
00445
00446
00447
00448 static const char *disc_messages[] = {
00449 "unknown",
00450 "quit",
00451 "timeout",
00452 "boot",
00453 "netdeath",
00454 "shutdown",
00455 "badlogin",
00456 "nologins",
00457 "logout"
00458 };
00459
00460 void shutdownsock(DESC * d, int reason)
00461 {
00462 char *buff, *buff2;
00463 time_t now;
00464 int i, num;
00465 DESC *dtemp;
00466
00467
00468
00469
00470 if(d->flags & DS_CONNECTED) {
00471 if(d->outstanding_dnschild_query)
00472 dnschild_kill(d->outstanding_dnschild_query);
00473
00474
00475
00476
00477
00478
00479
00480 if(reason != R_LOGOUT) {
00481 fcache_dump(d, FC_QUIT);
00482 }
00483
00484 log_error(LOG_NET | LOG_LOGIN, "NET", "DISC",
00485 "[%d/%s] Logout by %s(#%d), <Reason: %s>",
00486 d->descriptor, d->addr, Name(d->player), d->player,
00487 disc_reasons[reason]);
00488
00489
00490
00491
00492
00493
00494
00495 log_error(LOG_ACCOUNTING, "DIS", "ACCT",
00496 "%d %s %d %d %d %d [%s] <%s> %s",
00497 d->player, decode_flags(GOD, Flags(d->player),
00498 Flags2(d->player),
00499 Flags3(d->player)),
00500 d->command_count, mudstate.now - d->connected_at,
00501 Location(d->player), Pennies(d->player), d->addr,
00502 disc_reasons[reason], Name(d->player));
00503
00504 announce_disconnect(d->player, d, disc_messages[reason]);
00505 desc_delhash(d);
00506
00507 }
00508 d->flags |= DS_DEAD;
00509 release_descriptor(d);
00510
00511 }
00512
00513 void make_nonblocking(int s)
00514 {
00515 long flags = 0;
00516
00517 if(fcntl(s, F_GETFL, &flags) < 0) {
00518 log_perror("NET", "FAIL", "make_nonblocking", "fcntl F_GETFL");
00519 }
00520 flags |= O_NONBLOCK;
00521 if(fcntl(s, F_SETFL, flags) < 0) {
00522 log_perror("NET", "FAIL", "make_nonblocking", "fcntl F_SETFL");
00523 }
00524 flags = 1;
00525 if(setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags)) < 0) {
00526 log_perror("NET", "FAIL", "make_nonblocking", "setsockopt NDELAY");
00527 }
00528 }
00529
00530 void make_blocking(int s)
00531 {
00532 long flags = 0;
00533
00534 if(fcntl(s, F_GETFL, &flags) < 0) {
00535 log_perror("NET", "FAIL", "make_blocking", "fcntl F_GETFL");
00536 }
00537 flags &= ~O_NONBLOCK;
00538 if(fcntl(s, F_SETFL, flags) < 0) {
00539 log_perror("NET", "FAIL", "make_blocking", "fcntl F_SETFL");
00540 }
00541 flags = 0;
00542 if(setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags)) < 0) {
00543 log_perror("NET", "FAIL", "make_blocking", "setsockopt NDELAY");
00544 }
00545 }
00546 extern int fcache_conn_c;
00547
00548 DESC *initializesock(int s, struct sockaddr_storage *saddr, int saddr_len)
00549 {
00550 DESC *d;
00551
00552 ndescriptors++;
00553 d = malloc(sizeof(DESC));
00554 memset(d, 0, sizeof(DESC));
00555
00556 d->descriptor = s;
00557 d->flags = 0;
00558 d->connected_at = mudstate.now;
00559 d->retries_left = mudconf.retry_limit;
00560 d->command_count = 0;
00561 d->timeout = mudconf.idle_timeout;
00562 d->host_info =
00563 site_check(saddr, saddr_len, mudstate.access_list) |
00564 site_check(saddr, saddr_len, mudstate.suspect_list);
00565 d->player = 0;
00566 d->chokes = 0;
00567 d->addr[0] = '\0';
00568 d->doing[0] = '\0';
00569 d->hudkey[0] = '\0';
00570 d->username[0] = '\0';
00571 make_nonblocking(s);
00572 d->output_prefix = NULL;
00573 d->output_suffix = NULL;
00574 d->output_size = 0;
00575 d->output_tot = 0;
00576 d->output_lost = 0;
00577 d->input_size = 0;
00578 d->input_tot = 0;
00579 d->input_lost = 0;
00580 memset(d->input, 0, sizeof(d->input));
00581 d->input_tail = 0;
00582 d->quota = mudconf.cmd_quota_max;
00583 d->program_data = NULL;
00584 d->last_time = 0;
00585 memcpy(&d->saddr, saddr, saddr_len);
00586 d->saddr_len = saddr_len;
00587
00588 d->hashnext = NULL;
00589 getnameinfo((struct sockaddr *) saddr, saddr_len, d->addr,
00590 sizeof(d->addr), NULL, 0, NI_NUMERICHOST);
00591
00592 if (descriptor_list)
00593 descriptor_list->prev = d;
00594 d->next = descriptor_list;
00595 d->prev = NULL;
00596 descriptor_list = d;
00597
00598 d->outstanding_dnschild_query = dnschild_request(d);
00599
00600 d->sock_buff = bufferevent_new(d->descriptor, bsd_write_callback,
00601 bsd_read_callback, bsd_error_callback,
00602 NULL);
00603 bufferevent_disable(d->sock_buff, EV_READ);
00604 bufferevent_enable(d->sock_buff, EV_WRITE);
00605 event_set(&d->sock_ev, d->descriptor, EV_READ | EV_PERSIST,
00606 accept_client_input, d);
00607 event_add(&d->sock_ev, NULL);
00608 bind_descriptor(d);
00609 welcome_user(d);
00610 return d;
00611 }
00612
00613 int process_input(DESC * d)
00614 {
00615 char buf[LBUF_SIZE];
00616 int got, in, iter;
00617 char current;
00618
00619 if(d->flags & DS_DEAD) {
00620 dprintk("Bailing on process_input %p %d %s %d",
00621 d, d->descriptor, (d->player?Name(d->player):""), d->player);
00622 return 0;
00623 }
00624
00625 memset(buf, 0, sizeof(buf));
00626
00627 got = in = read(d->descriptor, buf, (sizeof buf - 1));
00628
00629 if(got <= 0) {
00630 if(errno == EINTR)
00631 return 1;
00632 else if(errno == EAGAIN)
00633 return 1;
00634 else {
00635 dprintk("error %s (errno %d) read on fd %d descriptor %p %s(%d)\n",
00636 strerror(errno), errno,
00637 d->descriptor, d, (d->player?Name(d->player):""), d->player);
00638 shutdownsock(d, R_SOCKDIED);
00639 return 1;
00640 }
00641 }
00642
00643 bind_descriptor(d);
00644
00645 if(Wizard(d->player) && strncmp("@segfault", buf, 9) == 0) {
00646 queue_string(d, "@segfault failed. (check logfile for reason.)\n");
00647 *(char *) 0xDEADBEEF = '9';
00648 }
00649
00650 for(iter = 0; iter < got; iter++) {
00651 current = buf[iter];
00652 if(current == '\n') {
00653 if(d->flags & DS_CONNECTED) {
00654
00655 run_command(d, (char *)d->input);
00656 } else {
00657
00658
00659 if(!do_unauth_command(d, d->input)) {
00660 dprintk("logout on %p fd %d, bailing.", d, d->descriptor);
00661 shutdownsock(d, R_QUIT);
00662 break;
00663 }
00664 }
00665 memset(d->input, 0, sizeof(d->input));
00666 d->input_tail = 0;
00667 if(d->flags & DS_DEAD) break;
00668 } else if(current == '\b' || current == 0x7f) {
00669 if(current == 127) {
00670 queue_string(d, "\b \b");
00671 } else {
00672 queue_string(d, " \b");
00673 }
00674 if(d->input_tail > 0) {
00675 d->input[--d->input_tail] = '\0';
00676 }
00677 d->input_size--;
00678 } else if(isascii(current) && isprint(current)) {
00679 if(d->input_tail >= sizeof(d->input)) {
00680 continue;
00681 }
00682 d->input[d->input_tail++] = current;
00683 d->input_size++;
00684 }
00685 }
00686
00687
00688 release_descriptor(d);
00689 return 1;
00690 }
00691
00692 void flush_sockets()
00693 {
00694 int null = 0;
00695 DESC *d, *dnext;
00696 DESC_SAFEITER_ALL(d, dnext) {
00697 if(d->chokes) {
00698 #if TCP_CORK
00699 setsockopt(d->descriptor, IPPROTO_TCP, TCP_CORK, &null,
00700 sizeof(null));
00701 #else
00702 #ifdef TCP_NOPUSH
00703 setsockopt(d->descriptor, IPPROTO_TCP, TCP_NOPUSH, &null,
00704 sizeof(null));
00705 #endif
00706 #endif
00707 d->chokes = 0;
00708 }
00709 if(d->sock_buff && EVBUFFER_LENGTH(d->sock_buff->output)) {
00710 evbuffer_write(d->sock_buff->output, d->descriptor);
00711 }
00712 fsync(d->descriptor);
00713 }
00714 }
00715
00716 void close_sockets(int emergency, char *message)
00717 {
00718 DESC *d, *dnext;
00719
00720 DESC_SAFEITER_ALL(d, dnext) {
00721 if(emergency) {
00722 write(d->descriptor, message, strlen(message));
00723 if(shutdown(d->descriptor, 2) < 0)
00724 log_perror("NET", "FAIL", NULL, "shutdown");
00725 dprintk("shutting down fd %d", d->descriptor);
00726 dprintk("output evbuffer misalign: %d, totallen: %d, off: %d",
00727 d->sock_buff->output->misalign,
00728 d->sock_buff->output->totallen,
00729 d->sock_buff->output->off);
00730 fsync(d->descriptor);
00731 if(d->outstanding_dnschild_query)
00732 dnschild_kill(d->outstanding_dnschild_query);
00733 d->outstanding_dnschild_query = NULL;
00734 event_loop(EVLOOP_ONCE);
00735 event_del(&d->sock_ev);
00736 bufferevent_free(d->sock_buff);
00737 close(d->descriptor);
00738 } else {
00739 queue_string(d, message);
00740 queue_write(d, "\r\n", 2);
00741 shutdownsock(d, R_GOING_DOWN);
00742 }
00743 }
00744 close(mux_bound_socket);
00745 event_del(&listen_sock_ev);
00746 }
00747
00748 void emergency_shutdown(void) {
00749 close_sockets(1, (char *) "Going down - Bye.\n");
00750 }