]> git.pond.sub.org Git - empserver/blob - src/lib/player/accept.c
COPYING duplicates information from README. Remove. Move GPL from
[empserver] / src / lib / player / accept.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  accept.c: Keep track of people logged in
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1994
32  */
33
34 #include <config.h>
35
36 #if defined(_WIN32)
37 #define WIN32
38 #include <winsock2.h>
39 #undef NS_ALL
40 #endif
41
42 #include "prototypes.h"
43 #include "misc.h"
44 #include "proto.h"
45 #include "empthread.h"
46 #include "player.h"
47 #include "file.h"
48 #include "empio.h"
49 #include "power.h"
50 #include "gen.h"
51 #include "optlist.h"
52
53 #if !defined(_WIN32)
54 #include <arpa/inet.h>
55 #include <sys/socket.h>
56 #include <sys/time.h>
57 #include <netdb.h>
58 #include <netinet/in.h>
59 #include <sys/ioctl.h>
60 #include <unistd.h>
61 #endif
62 #include <signal.h>
63 #include <errno.h>
64 #include <fcntl.h>
65 #include <stdlib.h>
66 #include <stdio.h>
67
68 static struct emp_qelem Players;
69 static int player_socket;
70 static int player_addrlen;
71
72 void
73 player_init(void)
74 {
75     emp_initque(&Players);
76     init_player_commands();
77
78     player_socket = tcp_listen(*listen_addr ? listen_addr : NULL,
79                                loginport, &player_addrlen);
80 }
81
82 struct player *
83 player_new(int s)
84 {
85     struct player *lp;
86
87     lp = malloc(sizeof(struct player));
88     if (!lp)
89       return NULL;
90     memset(lp, 0, sizeof(struct player));
91     if (s >= 0) {
92         /* real player, not dummy created by update and market update */
93         lp->iop = io_open(s,
94                           IO_READ | IO_WRITE | IO_NBLOCK,
95                           IO_BUFSIZE, 0, 0);
96         if (!lp->iop) {
97             free(lp);
98             return NULL;
99         }
100         emp_insque(&lp->queue, &Players);
101         lp->cnum = 255;
102         lp->curid = -1;
103         time(&lp->curup);
104     }
105     return lp;
106 }
107
108 struct player *
109 player_delete(struct player *lp)
110 {
111     struct player *back;
112
113     back = (struct player *)lp->queue.q_back;
114     if (back)
115         emp_remque(&lp->queue);
116     if (lp->iop) {
117         /* it's a real player */
118         io_close(lp->iop);
119         lp->iop = 0;
120     }
121     free(lp);
122     /* XXX may need to free bigmap here */
123     return back;
124 }
125
126 struct player *
127 player_next(struct player *lp)
128 {
129     if (lp == 0)
130         lp = (struct player *)Players.q_forw;
131     else
132         lp = (struct player *)lp->queue.q_forw;
133     if (&lp->queue == &Players)
134         return 0;
135     return lp;
136 }
137
138 struct player *
139 player_prev(struct player *lp)
140 {
141     if (lp == 0)
142         lp = (struct player *)Players.q_back;
143     else
144         lp = (struct player *)lp->queue.q_back;
145     if (&lp->queue == &Players)
146         return 0;
147     return lp;
148 }
149
150 /*
151  * Return player in state PS_PLAYING for CNUM.
152  */
153 struct player *
154 getplayer(natid cnum)
155 {
156     struct emp_qelem *qp;
157     struct player *pl;
158
159     for (qp = Players.q_forw; qp != &Players; qp = qp->q_forw) {
160         pl = (struct player *)qp;
161         if (pl->cnum == cnum && pl->state == PS_PLAYING)
162             return pl;
163     }
164
165     return NULL;
166 }
167
168 void
169 player_wakeup_all(natid cnum)
170 {
171     register struct player *lp;
172
173     if (NULL != (lp = getplayer(cnum)))
174         player_wakeup(lp);
175 }
176
177 void
178 player_wakeup(struct player *pl)
179 {
180     if (pl->waiting)
181         empth_wakeup(pl->proc);
182 }
183
184 /*ARGSUSED*/
185 void
186 player_accept(void *unused)
187 {
188     struct sockaddr *sap;
189     void *inaddr;
190     int s = player_socket;
191     struct player *np;
192     int len;
193     int ns;
194     int set = 1;
195     int stacksize;
196     char buf[128];
197 #ifdef RESOLVE_IPADDRESS
198     struct hostent *hostp;
199 #endif
200
201     /* auto sockaddr_storage would be simpler, but less portable */
202     sap = malloc(player_addrlen);
203
204     while (1) {
205         empth_select(s, EMPTH_FD_READ);
206         len = player_addrlen;
207         ns = accept(s, sap, &len);
208         /* FIXME accept() can block on some systems (RST after select() reported s ready) */
209         if (ns < 0) {
210             logerror("new socket accept");
211             continue;
212         }
213         /* FIXME SO_KEEPALIVE is useless, player_kill_idle() strikes long before */
214         (void)setsockopt(ns, SOL_SOCKET, SO_KEEPALIVE, &set, sizeof(set));
215         np = player_new(ns);
216         if (!np) {
217             logerror("can't create player for fd %d", ns);
218             close(ns);
219             continue;
220         }
221 #ifdef HAVE_GETADDRINFO
222         inaddr = sap->sa_family == AF_INET
223             ? (void *)&((struct sockaddr_in *)sap)->sin_addr
224             : (void *)&((struct sockaddr_in6 *)sap)->sin6_addr;
225         /* Assumes that if you got getaddrinfo(), you got inet_ntop() too */
226         if (!inet_ntop(sap->sa_family, inaddr,
227                        np->hostaddr, sizeof(np->hostaddr))) {
228             logerror("inet_ntop() failed: %s", strerror(errno));
229             close(ns);
230             continue;
231         }
232 #else
233         inaddr = &((struct sockaddr_in *)sap)->sin_addr;
234         strcpy(np->hostaddr, inet_ntoa(*(struct in_addr *)inaddr));
235 #endif
236 #ifdef RESOLVE_IPADDRESS
237         hostp = gethostbyaddr(inaddr, player_addrlen, sap->sa_family);
238         if (NULL != hostp)
239             strcpy(np->hostname, hostp->h_name);
240 #endif /* RESOLVE_IPADDRESS */
241         /* XXX may not be big enough */
242         stacksize = 100000
243 /* budget */  + MAX(WORLD_X * WORLD_Y / 2 * sizeof(int) * 7,
244 /* power */ MAXNOC * sizeof(struct powstr));
245         sprintf(buf, "Player (fd #%d)", ns);
246         empth_create(PP_PLAYER, player_login, stacksize,
247                      0, buf, "Empire player", np);
248     }
249 }