src/lib/player/accept.c

Go to the documentation of this file.
00001 /*
00002  *  Empire - A multi-player, client/server Internet based war game.
00003  *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
00004  *                           Ken Stevens, Steve McClure
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  *  ---
00021  *
00022  *  See files README, COPYING and CREDITS in the root of the source
00023  *  tree for related information and legal notices.  It is expected
00024  *  that future projects/authors will amend these files as needed.
00025  *
00026  *  ---
00027  *
00028  *  accept.c: Keep track of people logged in
00029  * 
00030  *  Known contributors to this file:
00031  *     Dave Pare, 1994
00032  *     Markus Armbruster, 2005
00033  */
00034 
00035 #include <config.h>
00036 
00037 #include <errno.h>
00038 #include <stdio.h>
00039 #include <sys/types.h>
00040 #include <sys/socket.h>
00041 #include <netinet/in.h>
00042 #include <arpa/inet.h>
00043 #include <netdb.h>
00044 #include <unistd.h>
00045 
00046 #include "empio.h"
00047 #include "empthread.h"
00048 #include "file.h"
00049 #include "misc.h"
00050 #include "optlist.h"
00051 #include "player.h"
00052 #include "power.h"
00053 #include "proto.h"
00054 #include "prototypes.h"
00055 
00056 static struct emp_qelem Players;
00057 static int player_socket;
00058 static size_t player_addrlen;
00059 
00060 void
00061 player_init(void)
00062 {
00063     emp_initque(&Players);
00064     init_player_commands();
00065 
00066     player_socket = tcp_listen(*listen_addr ? listen_addr : NULL,
00067                                loginport, &player_addrlen);
00068 }
00069 
00070 struct player *
00071 player_new(int s)
00072 {
00073     struct player *lp;
00074 
00075     lp = malloc(sizeof(struct player));
00076     if (!lp)
00077       return NULL;
00078     memset(lp, 0, sizeof(struct player));
00079     if (s >= 0) {
00080         /* real player, not dummy created by update and market update */
00081         lp->iop = io_open(s, IO_READ | IO_WRITE | IO_NBLOCK, IO_BUFSIZE);
00082         if (!lp->iop) {
00083             free(lp);
00084             return NULL;
00085         }
00086         emp_insque(&lp->queue, &Players);
00087         lp->cnum = 255;
00088         lp->curid = -1;
00089         time(&lp->curup);
00090     }
00091     return lp;
00092 }
00093 
00094 struct player *
00095 player_delete(struct player *lp)
00096 {
00097     struct player *back;
00098 
00099     back = (struct player *)lp->queue.q_back;
00100     if (back)
00101         emp_remque(&lp->queue);
00102     if (lp->iop) {
00103         /* it's a real player */
00104         io_close(lp->iop);
00105         lp->iop = 0;
00106     }
00107     free(lp);
00108     /* XXX may need to free bigmap here */
00109     return back;
00110 }
00111 
00112 struct player *
00113 player_next(struct player *lp)
00114 {
00115     if (lp == 0)
00116         lp = (struct player *)Players.q_forw;
00117     else
00118         lp = (struct player *)lp->queue.q_forw;
00119     if (&lp->queue == &Players)
00120         return 0;
00121     return lp;
00122 }
00123 
00124 struct player *
00125 player_prev(struct player *lp)
00126 {
00127     if (lp == 0)
00128         lp = (struct player *)Players.q_back;
00129     else
00130         lp = (struct player *)lp->queue.q_back;
00131     if (&lp->queue == &Players)
00132         return 0;
00133     return lp;
00134 }
00135 
00136 /*
00137  * Return player in state PS_PLAYING for CNUM.
00138  */
00139 struct player *
00140 getplayer(natid cnum)
00141 {
00142     struct emp_qelem *qp;
00143     struct player *pl;
00144 
00145     for (qp = Players.q_forw; qp != &Players; qp = qp->q_forw) {
00146         pl = (struct player *)qp;
00147         if (pl->cnum == cnum && pl->state == PS_PLAYING)
00148             return pl;
00149     }
00150 
00151     return NULL;
00152 }
00153 
00154 /*ARGSUSED*/
00155 void
00156 player_accept(void *unused)
00157 {
00158     struct sockaddr *sap;
00159     void *inaddr;
00160     int s = player_socket;
00161     struct player *np;
00162     socklen_t len;
00163     int ns;
00164     int set = 1;
00165     int stacksize;
00166     char buf[128];
00167 #ifdef RESOLVE_IPADDRESS
00168     struct hostent *hostp;
00169 #endif
00170 
00171     /* auto sockaddr_storage would be simpler, but less portable */
00172     sap = malloc(player_addrlen);
00173 
00174     while (1) {
00175         empth_select(s, EMPTH_FD_READ);
00176         len = player_addrlen;
00177         ns = accept(s, sap, &len);
00178         /* FIXME accept() can block on some systems (RST after select() reports ready) */
00179         if (ns < 0) {
00180             logerror("new socket accept");
00181             continue;
00182         }
00183         /* FIXME SO_KEEPALIVE is useless, player_kill_idle() strikes long before */
00184         (void)setsockopt(ns, SOL_SOCKET, SO_KEEPALIVE, &set, sizeof(set));
00185         np = player_new(ns);
00186         if (!np) {
00187             logerror("can't create player for fd %d", ns);
00188             close(ns);
00189             continue;
00190         }
00191 #ifdef HAVE_GETADDRINFO
00192         inaddr = sap->sa_family == AF_INET
00193             ? (void *)&((struct sockaddr_in *)sap)->sin_addr
00194             : (void *)&((struct sockaddr_in6 *)sap)->sin6_addr;
00195         /* Assumes that if you got getaddrinfo(), you got inet_ntop() too */
00196         if (!inet_ntop(sap->sa_family, inaddr,
00197                        np->hostaddr, sizeof(np->hostaddr))) {
00198             logerror("inet_ntop() failed: %s", strerror(errno));
00199             close(ns);
00200             continue;
00201         }
00202 #else
00203         inaddr = &((struct sockaddr_in *)sap)->sin_addr;
00204         strcpy(np->hostaddr, inet_ntoa(*(struct in_addr *)inaddr));
00205 #endif
00206 #ifdef RESOLVE_IPADDRESS
00207         hostp = gethostbyaddr(inaddr, player_addrlen, sap->sa_family);
00208         if (NULL != hostp)
00209             strcpy(np->hostname, hostp->h_name);
00210 #endif /* RESOLVE_IPADDRESS */
00211         /* FIXME ancient black magic; figure out true stack need */
00212         stacksize = 100000
00213 /* budget */  + MAX(WORLD_SZ() * sizeof(int) * 7,
00214 /* power */ MAXNOC * sizeof(struct powstr));
00215         sprintf(buf, "Player (fd #%d)", ns);
00216         empth_create(player_login, stacksize, 0, buf, np);
00217     }
00218 }

Generated on Fri Mar 28 11:01:14 2008 for empserver by  doxygen 1.5.2