src/bsd.c

Go to the documentation of this file.
00001 /*
00002  * bsd.c 
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 /*    if(!hdesc) {
00073         dprintk("Creating new list root for '%s'(#%d) at %p.", 
00074             Name(d->player), d->player, d); 
00075     } else {
00076         dprintk("Adding descriptor %p to list root at %p for '%s'(#%d).",
00077         d, hdesc, Name(d->player), d->player);
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 /*    dprintk("removing descriptor %p from list root %p for '%s'(#%d).", d, hdesc, Name(d->player), d->player); */
00090     hdesc = (DESC *) rb_find(mudstate.desctree, (void *) d->player);
00091 /*    dprintk("removing descriptor %p from list root %p for '%s'(#%d).", d, hdesc, Name(d->player), d->player); */
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   /*  dprintk("hdesc: %p, d: %p, hdesc->hashnext: %p, d->hashnext: %p", hdesc,
00104             d, hdesc->hashnext, d->hashnext);
00105 */
00106     if(hdesc == d && hdesc->hashnext) {
00107   /*      dprintk("updating %d to use hashroot %p", d->player, d->hashnext);*/
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 /*        dprintk("removing %d table", d->player); */
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     //dprintk("bound desciptor %p, refcount now %d", d, d->refcount);
00134 }
00135 
00136 void release_descriptor(DESC *d) {
00137     d->refcount--;
00138     //dprintk("descriptor %p released, refcount now %d", d, d->refcount);
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 /*        if(descriptor_list == d) {
00168             descriptor_list = d->next;
00169         } else {
00170             if(!descriptor_list) {
00171                 dprintk("Oh sweet jesus, we have major braindamage.");
00172                 descriptor_list = d->next;
00173             } else {
00174                 DESC *dtemp = descriptor_list;
00175                 while(dtemp->next != NULL) {
00176                     if(dtemp->next == d) {
00177                         dtemp->next = d->next;
00178                         break;
00179                     } else {
00180                         dtemp = dtemp->next;
00181                     }
00182                 }
00183             }
00184         }
00185 
00186         d->next = NULL;
00187         */
00188          if (d->prev)
00189                      d->prev->next = d->next;
00190            else                          /* d was the first one! */
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                         /* An invalid player connection... eject, eject, eject. */
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     //dprintk("callback on fd %d DESC %p", fd, arg);
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     //dprintk("finish on fd %d DESC %p", fd, arg);
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(&current_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(&current_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  * Disconnect reasons that get written to the logfile 
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  * Disconnect reasons that get fed to A_ADISCONNECT via announce_disconnect 
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 /*    dprintk("shutdownsock called on %p %s(#%d) refcount %d", 
00468         d, (d->player?Name(d->player):""), d->player, d->refcount); */
00469 
00470     if(d->flags & DS_CONNECTED) {
00471                 if(d->outstanding_dnschild_query)
00472                         dnschild_kill(d->outstanding_dnschild_query);
00473 
00474                 /*
00475                  * Do the disconnect stuff if we aren't doing a LOGOUT * * *
00476                  * * * * (which keeps the connection open so the player can *
00477                  * * connect * * * * to a different character). 
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                  * If requested, write an accounting record of the form: * *
00491                  * * * * * Plyr# Flags Cmds ConnTime Loc Money [Site]
00492                  * <DiscRsn>  * *  * Name 
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    /* dprintk("shutdown."); */
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                 //dprintk("authed as %s running command '%s' refcount %d descriptor %p fd %d", Name(d->player), d->input, d->refcount, d, d->descriptor);
00655                 run_command(d, (char *)d->input);
00656             } else {
00657                 //dprintk("unauth running command '%s' refcount %d descriptor %p fd %d", d->input, d->refcount, 
00658                 //d, d->descriptor);
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     //dprintk("finished %p fd %d", d, d->descriptor);
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 }

Generated on Mon May 28 04:25:18 2007 for BattletechMUX by  doxygen 1.4.7