root/1.8.3/tags/p6/src/bsd.c

Revision 1167, 126.8 KB (checked in by shawnw, 13 months ago)

Merge devel into trunk for p6 release

Line 
1/**
2 * \file bsd.c
3 *
4 * \brief Network communication through BSD sockets for PennMUSH.
5 *
6 * While mysocket.c provides low-level functions for working with
7 * sockets, bsd.c focuses on player descriptors, a higher-level
8 * structure that tracks all information associated with a connection,
9 * and through which connection i/o is done.
10 *
11 *
12 */
13
14#include "copyrite.h"
15#include "config.h"
16
17#include <stdio.h>
18#include <stdarg.h>
19#ifdef I_SYS_TYPES
20#include <sys/types.h>
21#endif
22#ifdef WIN32
23#define FD_SETSIZE 256
24#include <windows.h>
25#include <winsock.h>
26#include <io.h>
27#include <process.h>
28#define EINTR WSAEINTR
29#define EWOULDBLOCK WSAEWOULDBLOCK
30#define MAXHOSTNAMELEN 32
31#pragma warning( disable : 4761)        /* disable warning re conversion */
32#else                           /* !WIN32 */
33#ifdef I_SYS_FILE
34#include <sys/file.h>
35#endif
36#ifdef I_SYS_TIME
37#include <sys/time.h>
38#ifdef TIME_WITH_SYS_TIME
39#include <time.h>
40#endif
41#else
42#include <time.h>
43#endif
44#include <sys/ioctl.h>
45#include <errno.h>
46#ifdef I_SYS_SOCKET
47#include <sys/socket.h>
48#endif
49#ifdef I_NETINET_IN
50#include <netinet/in.h>
51#endif
52#ifdef I_NETDB
53#include <netdb.h>
54#endif
55#ifdef I_SYS_PARAM
56#include <sys/param.h>
57#endif
58#ifdef I_SYS_STAT
59#include <sys/stat.h>
60#endif
61#endif                          /* !WIN32 */
62#include <fcntl.h>
63#include <ctype.h>
64#include <signal.h>
65#include <string.h>
66#include <stdlib.h>
67#ifdef I_SYS_SELECT
68#include <sys/select.h>
69#endif
70#ifdef HAVE_UNISTD_H
71#include <unistd.h>
72#endif
73#ifdef HAVE_SYS_UIO_H
74#include <sys/uio.h>
75#endif
76#include <limits.h>
77#ifdef I_FLOATINGPOINT
78#include <floatingpoint.h>
79#endif
80#ifdef HAVE_IEEEFP_H
81#include <ieeefp.h>
82#endif
83#include <locale.h>
84#include <setjmp.h>
85
86#include "conf.h"
87
88#include "externs.h"
89#include "chunk.h"
90#include "mushdb.h"
91#include "dbdefs.h"
92#include "flags.h"
93#include "lock.h"
94#include "help.h"
95#include "match.h"
96#include "ansi.h"
97#include "pueblo.h"
98#include "parse.h"
99#include "access.h"
100#include "command.h"
101#include "version.h"
102#include "patches.h"
103#include "mysocket.h"
104#include "ident.h"
105
106#ifndef WIN32
107#include "wait.h"
108#ifdef INFO_SLAVE
109#include "lookup.h"
110#endif
111#endif
112
113#include "strtree.h"
114#include "log.h"
115#include "mypcre.h"
116#ifdef HAS_OPENSSL
117#include "myssl.h"
118#endif
119#include "mymalloc.h"
120#include "extmail.h"
121#include "attrib.h"
122#include "game.h"
123#include "dbio.h"
124#include "confmagic.h"
125
126#ifdef HAS_GETRLIMIT
127void init_rlimit(void);
128#endif
129
130
131/* BSD 4.2 and maybe some others need these defined */
132#ifndef FD_ZERO
133/** An fd_set is 4 bytes */
134#define fd_set int
135/** Clear an fd_set */
136#define FD_ZERO(p)       (*p = 0)
137/** Set a bit in an fd_set */
138#define FD_SET(n,p)      (*p |= (1<<(n)))
139/** Clear a bit in an fd_set */
140#define FD_CLR(n,p)      (*p &= ~(1<<(n)))
141/** Check a bit in an fd_set */
142#define FD_ISSET(n,p)    (*p & (1<<(n)))
143#endif                          /* defines for BSD 4.2 */
144
145#ifdef HAS_GETRUSAGE
146void rusage_stats(void);
147#endif
148int que_next(void);             /* from cque.c */
149
150void dispatch(void);            /* from timer.c */
151dbref email_register_player(const char *name, const char *email, const char *host, const char *ip);     /* from player.c */
152
153#ifdef SUN_OS
154static int extrafd;
155#endif
156int shutdown_flag = 0;          /**< Is it time to shut down? */
157void chat_player_announce(dbref player, char *msg, int ungag);
158
159static int login_number = 0;
160static int under_limit = 1;
161
162char cf_motd_msg[BUFFER_LEN] = { '\0' }; /**< The message of the day */
163char cf_wizmotd_msg[BUFFER_LEN] = { '\0' };      /**< The wizard motd */
164char cf_downmotd_msg[BUFFER_LEN] = { '\0' };     /**< The down message */
165char cf_fullmotd_msg[BUFFER_LEN] = { '\0' };     /**< The 'mush full' message */
166static char poll_msg[DOING_LEN] = { '\0' };
167char confname[BUFFER_LEN] = { '\0' };    /**< Name of the config file */
168char errlog[BUFFER_LEN] = { '\0' };      /**< Name of the error log file */
169
170/** Is this descriptor connected to a telnet-compatible terminal? */
171#define TELNET_ABLE(d) ((d)->conn_flags & (CONN_TELNET | CONN_TELNET_QUERY))
172
173
174/* When the mush gets a new connection, it tries sending a telnet
175 * option negotiation code for setting client-side line-editing mode
176 * to it. If it gets a reply, a flag in the descriptor struct is
177 * turned on indicated telnet-awareness.
178 *
179 * If the reply indicates that the client supports linemode, further
180 * instructions as to what linemode options are to be used is sent.
181 * Those options: Client-side line editing, and expanding literal
182 * client-side-entered tabs into spaces.
183 *
184 * Option negotation requests sent by the client are processed,
185 * with the only one we confirm rather than refuse outright being
186 * suppress-go-ahead, since a number of telnet clients try it.
187 *
188 * The character 255 is the telnet option escape character, so when it
189 * is sent to a telnet-aware client by itself (Since it's also often y-umlaut)
190 * it must be doubled to escape it for the client. This is done automatically,
191 * and is the original purpose of adding telnet option support.
192 */
193
194/* Telnet codes */
195#define IAC 255                 /**< interpret as command: */
196#define NOP 241                 /**< no operation */
197#define AYT 246                 /**< are you there? */
198#define DONT 254                /**< you are not to use option */
199#define DO      253             /**< please, you use option */
200#define WONT 252                /**< I won't use option */
201#define WILL    251             /**< I will use option */
202#define SB      250             /**< interpret as subnegotiation */
203#define SE      240             /**< end sub negotiation */
204#define TN_SGA 3                /**< Suppress go-ahead */
205#define TN_LINEMODE 34          /**< Line mode */
206#define TN_NAWS 31              /**< Negotiate About Window Size */
207#define TN_TTYPE 24             /**< Ask for termial type information */
208static void test_telnet(DESC *d);
209static void setup_telnet(DESC *d);
210static int handle_telnet(DESC *d, unsigned char **q, unsigned char *qend);
211
212/** Iterate through a list of descriptors, and do something with those
213 * that are connected.
214 */
215#define DESC_ITER_CONN(d) \
216        for(d = descriptor_list;(d);d=(d)->next) \
217          if((d)->connected)
218
219/** Is a descriptor hidden? */
220#define Hidden(d)        ((d->hide == 1) && Can_Hide(d->player))
221
222static const char *create_fail =
223  "Either there is already a player with that name, or that name is illegal.";
224static const char *password_fail = "The password is invalid (or missing).";
225static const char *register_fail =
226  "Unable to register that player with that email address.";
227static const char *register_success =
228  "Registration successful! You will receive your password by email.";
229static const char *shutdown_message = "Going down - Bye";
230#ifdef HAS_OPENSSL
231static const char *ssl_shutdown_message =
232  "GAME: SSL connections must be dropped, sorry.";
233#endif
234static const char *asterisk_line =
235  "**********************************************************************";
236/** Where we save the descriptor info across reboots. */
237#define REBOOTFILE              "reboot.db"
238
239#if 0
240/* For translation */
241static void dummy_msgs(void);
242static void
243dummy_msgs()
244{
245  char *temp;
246  temp = T("Either that player does not exist, or has a different password.");
247  temp =
248    T
249    ("Either there is already a player with that name, or that name is illegal.");
250  temp = T("The password is invalid (or missing).");
251  temp = T("Unable to register that player with that email address.");
252  temp = T("Registration successful! You will receive your password by email.");
253  temp = T("Going down - Bye");
254  temp = T("GAME: SSL connections must be dropped, sorry.");
255}
256
257#endif
258
259DESC *descriptor_list = NULL;   /**< The linked list of descriptors */
260
261static int sock;
262#ifdef HAS_OPENSSL
263static int sslsock = 0;
264SSL *ssl_master_socket = NULL;  /**< Master SSL socket for ssl port */
265#endif
266static int ndescriptors = 0;
267#ifdef WIN32
268static WSADATA wsadata;
269#endif
270int restarting = 0;     /**< Are we restarting the server after a reboot? */
271int maxd = 0;
272
273extern const unsigned char *tables;
274
275sig_atomic_t signal_shutdown_flag = 0;  /**< Have we caught a shutdown signal? */
276sig_atomic_t signal_dump_flag = 0;      /**< Have we caught a dump signal? */
277
278#ifndef BOOLEXP_DEBUGGING
279#ifdef WIN32SERVICES
280void shutdown_checkpoint(void);
281int mainthread(int argc, char **argv);
282#else
283int main(int argc, char **argv);
284#endif
285#endif
286void set_signals(void);
287static struct timeval *timeval_sub(struct timeval *now, struct timeval *then);
288#ifdef WIN32
289/** Windows doesn't have gettimeofday(), so we implement it here */
290#define our_gettimeofday(now) win_gettimeofday((now))
291static void win_gettimeofday(struct timeval *now);
292#else
293/** A wrapper for gettimeofday() in case the system doesn't have it */
294#define our_gettimeofday(now) gettimeofday((now), (struct timezone *)NULL)
295#endif
296static long int msec_diff(struct timeval *now, struct timeval *then);
297static struct timeval *msec_add(struct timeval *t, int x);
298static void update_quotas(struct timeval *last, struct timeval *current);
299
300int how_many_fds(void);
301static void shovechars(Port_t port, Port_t sslport);
302static int test_connection(int newsock);
303#ifndef INFO_SLAVE
304static DESC *new_connection(int oldsock, int *result, int use_ssl);
305#endif
306
307static void clearstrings(DESC *d);
308
309/** A block of cached text. */
310typedef struct fblock {
311  unsigned char *buff;    /**< Pointer to the block as a string */
312  size_t len;             /**< Length of buff */
313} FBLOCK;
314
315/** The complete collection of cached text files. */
316struct fcache_entries {
317  FBLOCK connect_fcache[2];     /**< connect.txt and connect.html */
318  FBLOCK motd_fcache[2];        /**< motd.txt and motd.html */
319  FBLOCK wizmotd_fcache[2];     /**< wizmotd.txt and wizmotd.html */
320  FBLOCK newuser_fcache[2];     /**< newuser.txt and newuser.html */
321  FBLOCK register_fcache[2];    /**< register.txt and register.html */
322  FBLOCK quit_fcache[2];        /**< quit.txt and quit.html */
323  FBLOCK down_fcache[2];        /**< down.txt and down.html */
324  FBLOCK full_fcache[2];        /**< full.txt and full.html */
325  FBLOCK guest_fcache[2];       /**< guest.txt and guest.html */
326};
327
328static struct fcache_entries fcache;
329static void fcache_dump(DESC *d, FBLOCK fp[2], const unsigned char *prefix);
330static int fcache_read(FBLOCK *cp, const char *filename);
331static void logout_sock(DESC *d);
332static void shutdownsock(DESC *d);
333DESC *initializesock(int s, char *addr, char *ip, int use_ssl);
334int process_output(DESC *d);
335/* Notify.c */
336extern void free_text_block(struct text_block *t);
337extern void add_to_queue(struct text_queue *q, const unsigned char *b, int n);
338extern int queue_write(DESC *d, const unsigned char *b, int n);
339extern int queue_eol(DESC *d);
340extern int queue_newwrite(DESC *d, const unsigned char *b, int n);
341extern int queue_string(DESC *d, const char *s);
342extern int queue_string_eol(DESC *d, const char *s);
343extern void freeqs(DESC *d);
344static void welcome_user(DESC *d);
345static void dump_info(DESC *call_by);
346static void save_command(DESC *d, const unsigned char *command);
347static int process_input(DESC *d, int output_ready);
348static void process_input_helper(DESC *d, char *tbuf1, int got);
349static void set_userstring(unsigned char **userstring, const char *command);
350static void process_commands(void);
351static int do_command(DESC *d, char *command);
352static void parse_puebloclient(DESC *d, char *command);
353static int dump_messages(DESC *d, dbref player, int new);
354static int check_connect(DESC *d, const char *msg);
355static void parse_connect(const char *msg, char *command, char *user,
356                          char *pass);
357static void close_sockets(void);
358dbref find_player_by_desc(int port);
359static DESC *lookup_desc(dbref executor, const char *name);
360void NORETURN bailout(int sig);
361void WIN32_CDECL signal_shutdown(int sig);
362void WIN32_CDECL signal_dump(int sig);
363void reaper(int sig);
364#ifndef WIN32
365sig_atomic_t dump_error = 0;
366WAIT_TYPE dump_status = 0;
367#ifdef INFO_SLAVE
368sig_atomic_t slave_error = 0;
369#endif
370#endif
371extern pid_t forked_dump_pid;   /**< Process id of forking dump process */
372static void dump_users(DESC *call_by, char *match, int doing);
373static const char *time_format_1(time_t dt);
374static const char *time_format_2(time_t dt);
375static void announce_connect(dbref player, int isnew, int num);
376static void announce_disconnect(DESC *saved);
377void inactivity_check(void);
378void reopen_logs(void);
379void load_reboot_db(void);
380
381static bool in_suid_root_mode = 0;
382static char *pidfile = NULL;
383static char **saved_argv = NULL;
384
385#ifndef BOOLEXP_DEBUGGING
386#ifdef WIN32SERVICES
387/* Under WIN32, MUSH is a "service", so we just start a thread here.
388 * The real "main" is in win32/services.c
389 */
390int
391mainthread(int argc, char **argv)
392#else
393/** The main function.
394 * \param argc number of arguments.
395 * \param argv vector of arguments.
396 * \return exit code.
397 */
398int
399main(int argc, char **argv)
400#endif                          /* WIN32SERVICES */
401{
402  FILE *newerr;
403  bool detach_session = 1;
404
405/* disallow running as root on unix.
406 * This is done as early as possible, before translation is initialized.
407 * Hence, no T()s around messages.
408 */
409#ifndef WIN32
410#ifdef HAVE_GETUID
411  if (getuid() == 0) {
412    fputs("Please run the server as another user.\n", stderr);
413    fputs("PennMUSH will not run as root as a security measure.\n", stderr);
414    return EXIT_FAILURE;
415  }
416  /* Add suid-root checks here. */
417#endif
418#ifdef HAVE_GETEUID
419  if (geteuid() == 0) {
420    fprintf(stderr, "The  %s binary is set suid and owned by root.\n", argv[0]);
421#ifdef HAVE_SETEUID
422    fprintf(stderr, "Changing effective user to %d.\n", getuid());
423    seteuid(getuid());
424    in_suid_root_mode = 1;
425#endif
426  }
427#endif                          /* HAVE_GETEUID */
428#endif                          /* !WIN32 */
429
430  /* read the configuration file */
431  if (argc < 2) {
432    fprintf(stderr,
433            "WARNING: Called without a config file argument. Assuming mush.cnf\n");
434    strcpy(confname, "mush.cnf");
435  } else {
436    int n;
437    for (n = 1; n < argc; n++) {
438      if (argv[n][0] == '-') {
439        if (strcmp(argv[n], "--no-session") == 0)
440          detach_session = 0;
441        else if (strncmp(argv[n], "--pid-file", 10) == 0) {
442          char *eq;
443          if ((eq = strchr(argv[n], '=')))
444            pidfile = eq + 1;
445          else {
446            if (n + 1 >= argc) {
447              fprintf(stderr, "%s: --pid-file needs a filename.\n", argv[0]);
448              return EXIT_FAILURE;
449            }
450            pidfile = argv[n + 1];
451            n++;
452          }
453        } else
454          fprintf(stderr, "%s: unknown option \"%s\"\n", argv[0], argv[n]);
455      } else {
456        mush_strncpy(confname, argv[n], BUFFER_LEN);
457        break;
458      }
459    }
460  }
461
462
463#ifdef HAVE_FORK
464  /* Fork off and detach from controlling terminal. */
465  if (detach_session) {
466    pid_t child;
467
468    child = fork();
469    if (child < 0) {
470      /* Print a warning and continue */
471      penn_perror("fork");
472    } else if (child > 0) {
473      /* Parent process of a successful fork() */
474      return EXIT_SUCCESS;
475    } else {
476      /* Child process */
477      if (new_process_session() < 0)
478        penn_perror("Couldn't create a new process session");
479    }
480  }
481#endif
482
483#ifdef HAVE_GETPID
484  if (pidfile) {
485    FILE *f;
486    if (!(f = fopen(pidfile, "w"))) {
487      fprintf(stderr, "%s: Unable to write to pidfile '%s'\n", argv[0],
488              pidfile);
489      return EXIT_FAILURE;
490    }
491    fprintf(f, "%d\n", getpid());
492    fclose(f);
493  }
494#endif
495
496  saved_argv = argv;
497
498#ifdef WIN32
499  {
500    unsigned short wVersionRequested = MAKEWORD(1, 1);
501    int err;
502
503    /* Need to include library: wsock32.lib for Windows Sockets */
504    err = WSAStartup(wVersionRequested, &wsadata);
505    if (err) {
506      printf(T("Error %i on WSAStartup\n"), err);
507      exit(1);
508    }
509  }
510#endif                          /* WIN32 */
511
512#ifdef HAS_GETRLIMIT
513  init_rlimit();                /* unlimit file descriptors */
514#endif
515
516  /* These are BSDisms to fix floating point exceptions */
517#ifdef HAVE_FPSETROUND
518  fpsetround(FP_RN);
519#endif
520#ifdef HAVE_FPSETMASK
521  fpsetmask(0L);
522#endif
523
524  time(&mudtime);
525
526  options.mem_check = 1;
527
528  /* If we have setlocale, call it to set locale info
529   * from environment variables
530   */
531#ifdef HAS_SETLOCALE
532  {
533    char *loc;
534    if ((loc = setlocale(LC_CTYPE, "")) == NULL)
535      do_rawlog(LT_ERR, "Failed to set ctype locale from environment.");
536    else
537      do_rawlog(LT_ERR, "Setting ctype locale to %s", loc);
538    if ((loc = setlocale(LC_TIME, "")) == NULL)
539      do_rawlog(LT_ERR, "Failed to set time locale from environment.");
540    else
541      do_rawlog(LT_ERR, "Setting time locale to %s", loc);
542#ifdef LC_MESSAGES
543    if ((loc = setlocale(LC_MESSAGES, "")) == NULL)
544      do_rawlog(LT_ERR, "Failed to set messages locale from environment.");
545    else
546      do_rawlog(LT_ERR, "Setting messages locale to %s", loc);
547#else
548    do_rawlog(LT_ERR, "No support for message locale.");
549#endif
550    if ((loc = setlocale(LC_COLLATE, "")) == NULL)
551      do_rawlog(LT_ERR, "Failed to set collate locale from environment.");
552    else
553      do_rawlog(LT_ERR, "Setting collate locale to %s", loc);
554  }
555#endif
556#ifdef HAS_TEXTDOMAIN
557  textdomain("pennmush");
558#endif
559#ifdef HAS_BINDTEXTDOMAIN
560  bindtextdomain("pennmush", "../po");
561#endif
562
563  /* Build the locale-dependant tables used by PCRE */
564  tables = pcre_maketables();
565
566  init_game_config(confname);
567
568  /* save a file descriptor */
569  reserve_fd();
570#ifdef SUN_OS
571  extrafd = open("/dev/null", O_RDWR);
572#endif
573
574  /* decide if we're in @shutdown/reboot */
575  restarting = 0;
576  newerr = fopen(REBOOTFILE, "r");
577  if (newerr) {
578    restarting = 1;
579    fclose(newerr);
580  }
581
582  if (init_game_dbs() < 0) {
583    do_rawlog(LT_ERR, T("ERROR: Couldn't load databases! Exiting."));
584    exit(2);
585  }
586
587  init_game_postdb(confname);
588
589  globals.database_loaded = 1;
590
591  set_signals();
592
593#ifdef INFO_SLAVE
594  init_info_slave();
595#endif
596
597  /* go do it */
598#ifdef CSRI
599#ifdef CSRI_DEBUG
600  mal_verify(1);
601#endif
602#ifdef CSRI_TRACE
603  mal_leaktrace(1);
604#endif
605#endif
606  load_reboot_db();
607
608  shovechars((Port_t) TINYPORT, (Port_t) SSLPORT);
609#ifdef CSRI
610#ifdef CSRI_DEBUG
611  mal_verify(1);
612#endif
613#endif
614
615  /* someone has told us to shut down */
616#ifdef WIN32SERVICES
617  /* Keep service manager happy */
618  shutdown_checkpoint();
619#endif
620
621  shutdown_queues();
622
623#ifdef WIN32SERVICES
624  /* Keep service manager happy */
625  shutdown_checkpoint();
626#endif
627
628  close_sockets();
629  sql_shutdown();
630
631#ifdef INFO_SLAVE
632  kill_info_slave();
633#endif
634
635#ifdef WIN32SERVICES
636  /* Keep service manager happy */
637  shutdown_checkpoint();
638#endif
639
640  dump_database();
641
642  local_shutdown();
643
644  end_all_logs();
645
646  if (pidfile)
647    remove(pidfile);
648
649#ifdef CSRI
650#ifdef CSRI_PROFILESIZES
651  mal_statsdump(stderr);
652#endif
653#ifdef CSRI_TRACE
654  mal_dumpleaktrace(stderr);
655#endif
656  fflush(stderr);
657#endif
658
659#ifdef WIN32SERVICES
660  /* Keep service manager happy */
661  shutdown_checkpoint();
662#endif
663
664#ifdef HAS_GETRUSAGE
665  rusage_stats();
666#endif                          /* HAS_RUSAGE */
667
668  do_rawlog(LT_ERR, T("MUSH shutdown completed."));
669
670  closesocket(sock);
671#ifdef WIN32
672#ifdef WIN32SERVICES
673  shutdown_checkpoint();
674#endif
675  WSACleanup();                 /* clean up */
676#else
677  exit(0);
678#endif
679}
680#endif                          /* BOOLEXP_DEBUGGING */
681
682/** Close and reopen the logfiles - called on SIGHUP */
683void
684reopen_logs(void)
685{
686  FILE *newerr;
687  /* close up the log files */
688  end_all_logs();
689  newerr = fopen(errlog, "a");
690  if (!newerr) {
691    fprintf(stderr,
692            T("Unable to open %s. Error output continues to stderr.\n"),
693            errlog);
694  } else {
695    if (!freopen(errlog, "a", stderr)) {
696      printf(T("Ack!  Failed reopening stderr!"));
697      exit(1);
698    }
699    setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
700    fclose(newerr);
701  }
702  start_all_logs();
703}
704
705/** Install our default signal handlers. */
706void
707set_signals(void)
708{
709
710#ifndef WIN32
711  /* we don't care about SIGPIPE, we notice it in select() and write() */
712  ignore_signal(SIGPIPE);
713  install_sig_handler(SIGUSR2, signal_dump);
714  install_sig_handler(SIGINT, signal_shutdown);
715  install_sig_handler(SIGTERM, bailout);
716  install_sig_handler(SIGCHLD, reaper);
717#else
718  /* Win32 stuff:
719   *   No support for SIGUSR2 or SIGINT.
720   *   SIGTERM is never generated on NT-based Windows (according to MSDN)
721   *   MSVC++ will let you get away with installing a handler anyway,
722   *   but VS.NET will not. So if it's MSVC++, we give it a try.
723   */
724#if _MSC_VER < 1200
725  install_sig_handler(SIGTERM, bailout);
726#endif
727#endif
728
729}
730
731#ifdef WIN32
732/** Get the time using Windows function call.
733 * Looks weird, but it works. :-P
734 * \param now address to store timeval data.
735 */
736static void
737win_gettimeofday(struct timeval *now)
738{
739
740  FILETIME win_time;
741
742  GetSystemTimeAsFileTime(&win_time);
743  /* dwLow is in 100-s nanoseconds, not microseconds */
744  now->tv_usec = win_time.dwLowDateTime % 10000000 / 10;
745
746  /* dwLow contains at most 429 least significant seconds, since 32 bits maxint is 4294967294 */
747  win_time.dwLowDateTime /= 10000000;
748
749  /* Make room for the seconds of dwLow in dwHigh */
750  /* 32 bits of 1 = 4294967295. 4294967295 / 429 = 10011578 */
751  win_time.dwHighDateTime %= 10011578;
752  win_time.dwHighDateTime *= 429;
753
754  /* And add them */
755  now->tv_sec = win_time.dwHighDateTime + win_time.dwLowDateTime;
756}
757
758#endif
759
760/** Return the difference between two timeval structs as a timeval struct.
761 * \param now pointer to the timeval to subtract from.
762 * \param then pointer to the timeval to subtract.
763 * \return pointer to a statically allocated timeval of the difference.
764 */
765static struct timeval *
766timeval_sub(struct timeval *now, struct timeval *then)
767{
768  static struct timeval mytime;
769  mytime.tv_sec = now->tv_sec;
770  mytime.tv_usec = now->tv_usec;
771
772  mytime.tv_sec -= then->tv_sec;
773  mytime.tv_usec -= then->tv_usec;
774  if (mytime.tv_usec < 0) {
775    mytime.tv_usec += 1000000;
776    mytime.tv_sec--;
777  }
778  return &mytime;
779}
780
781/** Return the difference between two timeval structs in milliseconds.
782 * \param now pointer to the timeval to subtract from.
783 * \param then pointer to the timeval to subtract.
784 * \return milliseconds of difference between them.
785 */
786static long int
787msec_diff(struct timeval *now, struct timeval *then)
788{
789  long int secs = now->tv_sec - then->tv_sec;
790  if (secs == 0)
791    return (now->tv_usec - then->tv_usec) / 1000;
792  else if (secs == 1)
793    return (now->tv_usec + (1000000 - then->tv_usec)) / 100;
794  else if (secs > 1)
795    return (secs * 1000) + ((now->tv_usec + (1000000 - then->tv_usec)) / 1000);
796  else
797    return 0;
798}
799
800/** Add a given number of milliseconds to a timeval.
801 * \param t pointer to a timeval struct.
802 * \param x number of milliseconds to add to t.
803 * \return address of static timeval struct representing the sum.
804 */
805static struct timeval *
806msec_add(struct timeval *t, int x)
807{
808  static struct timeval mytime;
809  mytime.tv_sec = t->tv_sec;
810  mytime.tv_usec = t->tv_usec;
811  mytime.tv_sec += x / 1000;
812  mytime.tv_usec += (x % 1000) * 1000;
813  if (mytime.tv_usec >= 1000000) {
814    mytime.tv_sec += mytime.tv_usec / 1000000;
815    mytime.tv_usec = mytime.tv_usec % 1000000;
816  }
817  return &mytime;
818}
819
820/** Update each descriptor's allowed rate of issuing commands.
821 * Players are rate-limited; they may only perform up to a certain
822 * number of commands per time slice. This function is run periodically
823 * to refresh each descriptor's available command quota based on how
824 * many slices have passed since it was last updated.
825 * \param last pointer to timeval struct of last time quota was updated.
826 * \param current pointer to timeval struct of current time.
827 */
828static void
829update_quotas(struct timeval *last, struct timeval *current)
830{
831  int nslices;
832  DESC *d;
833  nslices = (int) msec_diff(current, last) / COMMAND_TIME_MSEC;
834
835  if (nslices > 0) {
836    for (d = descriptor_list; d; d = d->next) {
837      d->quota += COMMANDS_PER_TIME * nslices;
838      if (d->quota > COMMAND_BURST_SIZE)
839        d->quota = COMMAND_BURST_SIZE;
840<