]> git.pond.sub.org Git - empserver/blobdiff - src/lib/player/accept.c
Update copyright notice
[empserver] / src / lib / player / accept.c
index 9c87d23a8f238262ef72d127fa0feb5b94afc694..cfda5bd354087bff79b041bd38d1da986e99a9f1 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2010, Dave Pare, Jeff Bailey, Thomas Ruschak,
- *                           Ken Stevens, Steve McClure
+ *  Copyright (C) 1986-2017, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *                Ken Stevens, Steve McClure, Markus Armbruster
  *
- *  This program is free software; you can redistribute it and/or modify
+ *  Empire is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
+ *  the Free Software Foundation, either version 3 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  *  ---
  *
@@ -29,7 +28,7 @@
  *
  *  Known contributors to this file:
  *     Dave Pare, 1994
- *     Markus Armbruster, 2005-2009
+ *     Markus Armbruster, 2005-2014
  */
 
 #include <config.h>
 
 #include "empio.h"
 #include "empthread.h"
-#include "file.h"
 #include "misc.h"
 #include "nat.h"
 #include "optlist.h"
 #include "player.h"
-#include "power.h"
-#include "proto.h"
 #include "prototypes.h"
 
 static struct emp_qelem Players;
 static int player_socket;
 static size_t player_addrlen;
 
+static const char *sockaddr_ntop(struct sockaddr *, char *, size_t);
+
 void
 player_init(void)
 {
@@ -72,17 +70,14 @@ struct player *
 player_new(int s)
 {
     struct player *lp;
-    struct timeval idle_timeout;
 
     lp = malloc(sizeof(struct player));
     if (!lp)
        return NULL;
     memset(lp, 0, sizeof(struct player));
-    idle_timeout.tv_sec = max_idle * 60;
-    idle_timeout.tv_usec = 0;
     if (s >= 0) {
        /* real player, not dummy created by update and market update */
-       lp->iop = io_open(s, IO_READ | IO_WRITE, IO_BUFSIZE, idle_timeout);
+       lp->iop = io_open(s, IO_READ | IO_WRITE, IO_BUFSIZE);
        if (!lp->iop) {
            free(lp);
            return NULL;
@@ -101,14 +96,14 @@ player_delete(struct player *lp)
 {
     struct player *back;
 
-    back = (struct player *)lp->queue.q_back;
-    if (back)
-       emp_remque(&lp->queue);
     if (lp->iop) {
        /* it's a real player */
-       io_close(lp->iop);
+       io_close(lp->iop, player->curup + login_grace_time);
        lp->iop = NULL;
     }
+    back = (struct player *)lp->queue.q_back;
+    if (back)
+       emp_remque(&lp->queue);
     free(lp);
     /* XXX may need to free bigmap here */
     return back;
@@ -139,7 +134,7 @@ player_prev(struct player *lp)
 }
 
 /*
- * Return player in state PS_PLAYING for CNUM.
+ * Return player in state PS_PLAYING for @cnum.
  */
 struct player *
 getplayer(natid cnum)
@@ -156,36 +151,51 @@ getplayer(natid cnum)
     return NULL;
 }
 
+time_t
+player_io_deadline(struct player *pl, int write)
+{
+    if (pl->may_sleep < (write ? PLAYER_SLEEP_FREELY : PLAYER_SLEEP_ON_INPUT))
+       return 0;
+    if (pl->state != PS_PLAYING)
+       return pl->curup + login_grace_time;
+    return pl->curup
+       + minutes(pl->nstat & NONVIS ? max_idle: max_idle_visitor);
+}
+
 /*ARGSUSED*/
 void
 player_accept(void *unused)
 {
+    static int conn_cnt;
     struct sockaddr *sap;
-    void *inaddr;
-    int s = player_socket;
     struct player *np;
     socklen_t len;
+    const char *p;
     int ns;
     int set = 1;
-    int stacksize;
     char buf[128];
-#ifdef RESOLVE_IPADDRESS
-    struct hostent *hostp;
-#endif
 
     /* auto sockaddr_storage would be simpler, but less portable */
     sap = malloc(player_addrlen);
+    len = player_addrlen;
+    if (getsockname(player_socket, sap, &len)) {
+       logerror("getsockname() failed: %s", strerror(errno));
+       p = NULL;
+    } else {
+       p = sockaddr_ntop(sap, buf, sizeof(buf));
+       CANT_HAPPEN(!p);
+    }
+    logerror("Listening on %s", p ? buf : "unknown address");
 
     while (1) {
-       empth_select(s, EMPTH_FD_READ, NULL);
+       empth_select(player_socket, EMPTH_FD_READ, NULL);
        len = player_addrlen;
-       ns = accept(s, sap, &len);
+       ns = accept(player_socket, sap, &len);
        /* FIXME accept() can block on some systems (RST after select() reports ready) */
        if (ns < 0) {
            logerror("new socket accept");
            continue;
        }
-       /* FIXME SO_KEEPALIVE is useless, player_kill_idle() strikes long before */
        (void)setsockopt(ns, SOL_SOCKET, SO_KEEPALIVE, &set, sizeof(set));
        np = player_new(ns);
        if (!np) {
@@ -193,31 +203,45 @@ player_accept(void *unused)
            close(ns);
            continue;
        }
-#ifdef HAVE_GETADDRINFO
-       inaddr = sap->sa_family == AF_INET
-           ? (void *)&((struct sockaddr_in *)sap)->sin_addr
-           : (void *)&((struct sockaddr_in6 *)sap)->sin6_addr;
-       /* Assumes that if you got getaddrinfo(), you got inet_ntop() too */
-       if (!inet_ntop(sap->sa_family, inaddr,
-                      np->hostaddr, sizeof(np->hostaddr))) {
-           logerror("inet_ntop() failed: %s", strerror(errno));
+       if (!sockaddr_ntop(sap, np->hostaddr, sizeof(np->hostaddr))) {
+           CANT_REACH();
            player_delete(np);
            continue;
        }
+       logerror("Connect from %s", np->hostaddr);
+       sprintf(buf, "Conn%d", conn_cnt++);
+       empth_create(player_login, 1024 * 1024, 0, buf, np);
+    }
+}
+
+static const char *
+sockaddr_ntop(struct sockaddr *sap, char *buf, size_t bufsz)
+{
+#ifdef HAVE_GETADDRINFO
+    /* Assumes that if you got getaddrinfo(), you got inet_ntop() too */
+    sa_family_t af = sap->sa_family;
+    void *addr;
+    struct sockaddr_in6 *sap6;
+
+    if (af == AF_INET)
+       addr = &((struct sockaddr_in *)sap)->sin_addr;
+    else {
+       sap6 = (struct sockaddr_in6 *)sap;
+       addr = &sap6->sin6_addr;
+       if (IN6_IS_ADDR_V4MAPPED(&sap6->sin6_addr)) {
+           af = AF_INET;
+           addr = sap6->sin6_addr.s6_addr + 12;
+       }
+    }
+    return inet_ntop(af, addr, buf, bufsz);
 #else
-       inaddr = &((struct sockaddr_in *)sap)->sin_addr;
-       strcpy(np->hostaddr, inet_ntoa(*(struct in_addr *)inaddr));
-#endif
-#ifdef RESOLVE_IPADDRESS
-       hostp = gethostbyaddr(inaddr, player_addrlen, sap->sa_family);
-       if (NULL != hostp)
-           strcpy(np->hostname, hostp->h_name);
-#endif /* RESOLVE_IPADDRESS */
-       /* FIXME ancient black magic; figure out true stack need */
-       stacksize = 100000
-/* budget */  + MAX(WORLD_SZ() * sizeof(int) * 7,
-/* power */ MAXNOC * sizeof(struct powstr));
-       sprintf(buf, "Conn%d", ns);
-       empth_create(player_login, stacksize, 0, buf, np);
+    const char *p;
+
+    p = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr);
+    if (strlen(p) >= bufsz) {
+       errno = ENOSPC;
+       return NULL;
     }
+    return strcpy(buf, p);
+#endif
 }