]> git.pond.sub.org Git - empserver/blob - src/server/main.c
(main) [_WIN32]: Remove unneccessary #ifdef for srand,
[empserver] / src / server / main.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  main.c: Thread and signal initialization for Empire Server
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1994
32  *     Steve McClure, 1996, 1998
33  *     Doug Hay, 1998
34  */
35
36 #if defined(aix) || defined(linux)
37 #include <unistd.h>
38 #endif /* aix or linux */
39
40 #include <signal.h>
41 #include <errno.h>
42 #if !defined(_WIN32)
43 #include <sys/ioctl.h>
44 #endif
45 #include <fcntl.h>
46 #include <stdio.h>
47 #include <string.h>
48
49 #if defined(_WIN32)
50 #include <winsock.h>
51 #include <process.h>
52 #include "getopt.h"
53 #endif
54
55 #include "misc.h"
56 #include "nat.h"
57 #include "file.h"
58 #include "player.h"
59 #include "empthread.h"
60 #include "plane.h"
61 #include "nuke.h"
62 #include "land.h"
63 #include "ship.h"
64 #include "sect.h"
65 #include "product.h"
66 #include "optlist.h"
67 #include "global.h"
68 #include "server.h"
69 #include "prototypes.h"
70
71 static void nullify_objects(void);
72 static void init_files(void);
73 static void close_files(void);
74
75 #if defined(_WIN32)
76 static void loc_NTInit(void);
77 static void loc_NTTerm(void);
78 #endif
79
80 static int mainpid = 0;
81
82 /*
83  * Debugging?
84  * If yes, don't fork into background, don't catch certain signals,
85  * call abort() on internal error.
86  */
87 int debug = 0;
88
89 static void
90 print_usage(char *program_name)
91 {
92 #if defined(_WIN32)
93     printf("Usage: %s -D datadir -e config_file -d\n", program_name);
94 #else
95     printf("Usage: %s -D datadir -e config_file -d -p -s\n", program_name);
96     printf("-p print flag\n");
97     printf("-s stack check flag (include print flag)\n");
98 #endif
99     printf("-d debug mode\n");
100 }
101
102 int
103 main(int argc, char **argv)
104 {
105     int flags = 0;
106     int op;
107     char *config_file = NULL;
108     extern char *optarg;
109     s_char tbuf[256];
110 #ifdef POSIXSIGNALS
111     struct sigaction act;
112 #endif /* POSIXSIGNALS */
113
114     loginit("server");
115
116     mainpid = getpid();
117
118 #if defined(_WIN32)
119     while ((op = getopt(argc, argv, "D:de:h")) != EOF) {
120 #else
121     while ((op = getopt(argc, argv, "D:de:psh")) != EOF) {
122 #endif
123         switch (op) {
124         case 'D':
125             datadir = optarg;
126             break;
127         case 'd':
128             debug++;
129             break;
130         case 'e':
131             config_file = optarg;
132             break;
133 #if !defined(_WIN32)
134         case 'p':
135             flags |= EMPTH_PRINT;
136             break;
137         case 's':
138             flags |= EMPTH_PRINT | EMPTH_STACKCHECK;
139             break;
140 #endif
141         case 'h':
142         default:
143             print_usage(argv[0]);
144             return 0;
145         }
146     }
147
148     if (config_file == NULL) {
149         sprintf(tbuf, "%s/econfig", datadir);
150         config_file = tbuf;
151     }
152
153     logerror("------------------------------------------------------");
154     logerror("Empire server (pid %d) started", getpid());
155
156 #if defined(_WIN32)
157     loc_NTInit();
158 #endif
159     emp_config(config_file);
160     update_policy_check();
161
162     nullify_objects();
163
164 #if !defined(_WIN32)
165     /* signal() should not be used with mit pthreads. Anyway if u
166        have a posix threads u definitly have posix signals -- Sasha */
167 #if defined (POSIXSIGNALS) || defined (_EMPTH_POSIX)
168 #ifdef SA_SIGINFO
169     act.sa_flags = SA_SIGINFO;
170 #endif
171     sigemptyset(&act.sa_mask);
172     if (debug == 0 && flags == 0) {
173         disassoc();
174     }
175     act.sa_handler = shutdwn;
176     /* pthreads on Linux use SIGUSR1 (*shrug*) so only catch it if not on
177        a Linux box running POSIX threads -- STM */
178 #if !(defined(__linux__) && defined(_EMPTH_POSIX))
179     sigaction(SIGUSR1, &act, NULL);
180 #endif
181     sigaction(SIGTERM, &act, NULL);
182     sigaction(SIGINT, &act, NULL);
183     act.sa_handler = panic;
184     sigaction(SIGBUS, &act, NULL);
185     sigaction(SIGSEGV, &act, NULL);
186     sigaction(SIGILL, &act, NULL);
187     sigaction(SIGFPE, &act, NULL);
188     act.sa_handler = SIG_IGN;
189     sigaction(SIGPIPE, &act, NULL);
190 #else
191     if (debug == 0 && flags == 0) {
192         disassoc();
193         /* pthreads on Linux use SIGUSR1 (*shrug*) so only catch it if not on
194            a Linux box running POSIX threads -- STM */
195 #if !(defined(__linux__) && defined(_EMPTH_POSIX))
196         signal(SIGUSR1, shutdwn);
197 #endif
198         signal(SIGTERM, shutdwn);
199         signal(SIGBUS, panic);
200         signal(SIGSEGV, panic);
201         signal(SIGILL, panic);
202         signal(SIGFPE, panic);
203         signal(SIGINT, shutdwn);
204     }
205     signal(SIGPIPE, SIG_IGN);
206 #endif /* POSIXSIGNALS */
207 #endif /* _WIN32 */
208     empth_init((char **)&player, flags);
209     srand(time(NULL));
210     global_init();
211     shutdown_init();
212     player_init();
213     ef_init();
214     init_files();
215     io_init();
216
217     if (opt_MOB_ACCESS) {
218         /* This fixes up mobility upon restart */
219         mobility_init();
220     }
221
222     empth_create(PP_ACCEPT, player_accept, (50 * 1024), flags,
223                  "AcceptPlayers", "Accept network connections", 0);
224     empth_create(PP_KILLIDLE, player_kill_idle, (50 * 1024), flags,
225                  "KillIdle", "Kills idle player connections", 0);
226     empth_create(PP_SCHED, update_sched, (50 * 1024), flags, "UpdateSched",
227                  "Schedules updates to occur", 0);
228     empth_create(PP_TIMESTAMP, delete_lostitems, (50 * 1024), flags,
229                  "DeleteItems", "Deletes old lost items", 0);
230     if (opt_MOB_ACCESS) {
231         /* Start the mobility access check thread */
232         empth_create(PP_TIMESTAMP, mobility_check, (50 * 1024), flags,
233                      "MobilityCheck", "Writes the timestamp file", 0);
234     }
235
236     if (opt_MARKET) {
237         empth_create(PP_TIMESTAMP, market_update, (50 * 1024), flags,
238                      "MarketUpdate", "Updates the market", 0);
239     }
240 #if defined(__linux__) && defined(_EMPTH_POSIX)
241     strcpy(tbuf, argv[0]);
242     for (op = 1; op < argc; op++) {
243         strcat(tbuf, " ");
244         strcat(tbuf, argv[op]);
245     }
246     sprintf(argv[0], "%s (main pid: %d)", tbuf, getpid());
247 #endif
248
249     empth_exit();
250
251 /* We should never get here.  But, just in case... */
252     close_files();
253
254 #if defined(_WIN32)
255     loc_NTTerm();
256 #endif
257     return 0;
258 }
259
260 static void
261 init_files(void)
262 {
263     ef_open(EF_NATION, O_RDWR, EFF_MEM);
264     ef_open(EF_SECTOR, O_RDWR, EFF_MEM);
265     ef_open(EF_SHIP, O_RDWR, EFF_MEM);
266     ef_open(EF_PLANE, O_RDWR, EFF_MEM);
267     ef_open(EF_LAND, O_RDWR, EFF_MEM);
268     ef_open(EF_NEWS, O_RDWR, 0);
269     ef_open(EF_LOAN, O_RDWR, 0);
270     ef_open(EF_TREATY, O_RDWR, 0);
271     ef_open(EF_NUKE, O_RDWR, EFF_MEM);
272     ef_open(EF_POWER, O_RDWR, 0);
273     ef_open(EF_TRADE, O_RDWR, 0);
274     ef_open(EF_MAP, O_RDWR, EFF_MEM);
275     ef_open(EF_BMAP, O_RDWR, EFF_MEM);
276     ef_open(EF_COMM, O_RDWR, 0);
277     ef_open(EF_LOST, O_RDWR, 0);
278 }
279
280 static void
281 close_files(void)
282 {
283     ef_close(EF_NATION);
284     ef_close(EF_SECTOR);
285     ef_close(EF_SHIP);
286     ef_close(EF_PLANE);
287     ef_close(EF_LAND);
288     ef_close(EF_NEWS);
289     ef_close(EF_LOAN);
290     ef_close(EF_TREATY);
291     ef_close(EF_NUKE);
292     ef_close(EF_POWER);
293     ef_close(EF_TRADE);
294     ef_close(EF_MAP);
295     ef_close(EF_COMM);
296     ef_close(EF_BMAP);
297     ef_close(EF_LOST);
298 }
299
300 /* we're going down.  try to close the files at least */
301 void
302 panic(int sig)
303 {
304 #if !defined(_WIN32)
305 #ifdef POSIXSIGNALS
306     struct sigaction act;
307
308     act.sa_flags = 0;
309     sigemptyset(&act.sa_mask);
310     act.sa_handler = SIG_DFL;
311     sigaction(SIGBUS, &act, NULL);
312     sigaction(SIGSEGV, &act, NULL);
313     sigaction(SIGILL, &act, NULL);
314     sigaction(SIGFPE, &act, NULL);
315 #else
316     signal(SIGBUS, SIG_DFL);
317     signal(SIGSEGV, SIG_DFL);
318     signal(SIGILL, SIG_DFL);
319     signal(SIGFPE, SIG_DFL);
320 #endif /* POSIXSIGNALS */
321 #endif /* _WIN32 */
322     logerror("server received fatal signal %d", sig);
323     log_last_commands();
324     close_files();
325     _exit(0);
326 }
327
328 void
329 shutdwn(int sig)
330 {
331     struct player *p;
332     time_t now;
333
334 #if defined(__linux__) && defined(_EMPTH_POSIX)
335 /* This is a hack to get around the way pthreads work on Linux.  This
336    may be useful on other platforms too where threads are turned into
337    processes. */
338     if (getpid() != mainpid) {
339         empth_t *me;
340
341         me = empth_self();
342         if (me && me->name) {
343             if (strlen(me->name) > 5) {
344                 /* Player threads are cleaned up below, so just have
345                    them return.  This should work. */
346                 if (!strncmp("Player", me->name, 6)) {
347                     return;
348                 }
349             }
350         }
351         /* Not a player thread - must be server thread, so exit */
352         empth_exit();
353         return;
354     }
355 #endif
356
357     logerror("Shutdown commencing (cleaning up threads.)");
358
359     for (p = player_next(0); p != 0; p = player_next(p)) {
360         if (p->state != PS_PLAYING)
361             continue;
362         pr_flash(p, "Server shutting down...\n");
363         p->state = PS_SHUTDOWN;
364         p->aborted++;
365         if (p->command) {
366             pr_flash(p, "Shutdown aborting command\n");
367         }
368         empth_wakeup(p->proc);
369     }
370
371     if (!sig) {
372         /* Sleep and let some cleanup happen - note this doesn't work
373            when called from a signal handler, since we may or may not
374            be in the right thread.  So we just pass by and kill 'em
375            all. */
376         time(&now);
377         empth_sleep(now + 1);
378     }
379
380     for (p = player_next(0); p != 0; p = player_next(p)) {
381         p->state = PS_KILL;
382         p->aborted++;
383         empth_terminate(p->proc);
384         p = player_delete(p);
385     }
386     if (sig)
387         logerror("Server shutting down on signal %d", sig);
388     else
389         logerror("Server shutting down at Deity's request");
390     close_files();
391     _exit(0);
392 }
393
394
395 static void
396 nullify_objects(void)
397 {
398     int i, j;
399
400     if (opt_BIG_CITY) {
401         dchr[SCT_CAPIT].d_flg = bigcity_dchr.d_flg;
402         dchr[SCT_CAPIT].d_pkg = bigcity_dchr.d_pkg;
403         dchr[SCT_CAPIT].d_build = bigcity_dchr.d_build;
404         dchr[SCT_CAPIT].d_lcms = bigcity_dchr.d_lcms;
405         dchr[SCT_CAPIT].d_hcms = bigcity_dchr.d_hcms;
406         dchr[SCT_CAPIT].d_name = bigcity_dchr.d_name;
407     }
408     if (opt_NO_LCMS)
409         dchr[SCT_LIGHT].d_cost = -1;
410     if (opt_NO_HCMS)
411         dchr[SCT_HEAVY].d_cost = -1;
412     if (opt_NO_OIL) {
413         dchr[SCT_OIL].d_cost = -1;
414         dchr[SCT_REFINE].d_cost = -1;
415     }
416     for (i = 0; i < pln_maxno; i++) {
417         if (opt_NO_HCMS)
418             plchr[i].pl_hcm = 0;
419         if (opt_NO_LCMS)
420             plchr[i].pl_lcm = 0;
421         if (opt_NO_OIL)
422             plchr[i].pl_fuel = 0;
423     }
424     for (i = 0; i < lnd_maxno; i++) {
425         if (opt_NO_HCMS)
426             lchr[i].l_hcm = 0;
427         if (opt_NO_LCMS)
428             lchr[i].l_lcm = 0;
429         /* Fix up the military values */
430         lchr[i].l_mil = lchr[i].l_item[I_MILIT];
431     }
432     for (i = 0; i < shp_maxno; i++) {
433         if (opt_NO_HCMS)
434             mchr[i].m_hcm = 0;
435         if (opt_NO_LCMS)
436             mchr[i].m_lcm = 0;
437         if (opt_NO_OIL) {
438             if (mchr[i].m_flags & M_OIL)
439                 mchr[i].m_name = 0;
440         }
441     }
442     for (i = 0; i < nuk_maxno; i++) {
443         if (opt_NO_HCMS)
444             nchr[i].n_hcm = 0;
445         if (opt_NO_LCMS)
446             nchr[i].n_lcm = 0;
447     }
448     for (i = 0; i <= SCT_MAXDEF; i++) {
449         if (opt_NO_HCMS)
450             dchr[i].d_hcms = 0;
451         if (opt_NO_LCMS)
452             dchr[i].d_lcms = 0;
453     }
454     for (i = 0; i < prd_maxno; i++) {
455         for (j = 0; j < MAXPRCON; j++) {
456             if (opt_NO_HCMS && pchr[i].p_ctype[j] == I_HCM)
457                 pchr[i].p_camt[j] = 0;
458             if (opt_NO_LCMS && pchr[i].p_ctype[j] == I_LCM)
459                 pchr[i].p_camt[j] = 0;
460             if (opt_NO_OIL && pchr[i].p_ctype[j] == I_OIL)
461                 pchr[i].p_camt[j] = 0;
462         }
463     }
464 }
465
466 #if defined(_WIN32)
467 static void
468 loc_NTInit()
469 {
470     int rc;
471     WORD wVersionRequested;
472     WSADATA wsaData;
473
474     wVersionRequested = MAKEWORD(2, 0);
475     rc = WSAStartup(wVersionRequested, &wsaData);
476     if (rc != 0) {
477         logerror("WSAStartup failed.  %d", rc);
478         _exit(1);
479     }
480 }
481 #endif
482
483 #if defined(_WIN32)
484 static void
485 loc_NTTerm()
486 {
487     WSACleanup();
488 }
489 #endif