Crossfire Server, Branches 1.12  R18729
crossfire-loop.c
Go to the documentation of this file.
1 /* This is a watchdog pgrogram from Christian Stieber. It is not an
2  * officially supported piece of crossfire (I hope it works, but I am not
3  * going to be spending time debugging problems in this piece of code). The
4  * idea is that it periodically sends/gets udp messages to the server - if
5  * the server isn't responding, it kills it off and starts a new one. There
6  * is a bit more logic to it - From Christian:
7  *
8  * The wrapper is just a hack. I'm using it on a Solaris machine, and it
9  * seems to work fine. Notable features:
10  * - uses the watchdog interface
11  * - if the server crashes more than 10 times, with the time between
12  * successive crashes being less than 30 seconds, the wrapper terminates
13  * itself (to prevent bringing down the machine in case of startup problems)
14  * - the server runs at nice 10
15  *
16  * Note that the main advantage the watchdog has over just the simple
17  * crossloop scripts is in the case of infinite loops. For simple crashes,
18  * the crossloop programs do a fine job.
19  */
20 
21 /*
22  * Version 1
23  */
24 
25 /************************************************************************/
26 /*
27  * Configuration options
28  */
29 
30 /* server executable */
31 #define CROSSFIRE_SERVER "/usr/stud/stieber/bin/server"
32 
33 /* directory to cd to before starting the server */
34 #define CROSSFIRE_TMPDIR "/usr/stud/stieber/crossfire/tmp/"
35 
36 /* if the server crashes more than CRASH_COUNT times, with less than
37  * CRASH_INTERVAL seconds between two successive crashes, the loop
38  * program is terminated. */
39 #define CRASH_COUNT 10
40 #define CRASH_INTERVAL 30
41 
42 #define USE_WATCHDOG
43 #define ERROR_SLEEP 30
44 
45 /************************************************************************/
46 
47 #include <sys/unistd.h>
48 #include <sys/wait.h>
49 #include <stdlib.h>
50 #include <signal.h>
51 #include <stdio.h>
52 #include <unistd.h>
53 #include <sys/types.h>
54 #include <sys/socket.h>
55 #include <netinet/in.h>
56 #include <netdb.h>
57 #include <errno.h>
58 
59 /************************************************************************/
60 
61 #ifdef USE_WATCHDOG
62 int Pipe[2];
63 #endif
64 
65 /************************************************************************/
66 
67 void SignalHandler(int Unused) {
68  if (write(Pipe[1], "", 1) != 1) {
69  perror("Pipe");
70  exit(EXIT_FAILURE);
71  }
72 }
73 
74 /************************************************************************/
75 
76 int main(void) {
77  int CrashCount;
78 #ifdef USE_WATCHDOG
79  struct protoent *protoent;
80  struct sockaddr_in insock;
81  int fd;
82 
83  memset(&insock, 0, sizeof(insock));
84 
85  if ((protoent = getprotobyname("udp")) == NULL) {
86  perror("Can't get protobyname");
87  return EXIT_FAILURE;
88  }
89  if ((fd = socket(PF_INET, SOCK_DGRAM, protoent->p_proto)) == -1) {
90  perror("Can't create socket");
91  return EXIT_FAILURE;
92  }
93  insock.sin_family = AF_INET;
94  insock.sin_port = htons((unsigned short)13325);
95  if (bind(fd, (struct sockaddr *)&insock, sizeof(insock)) == -1) {
96  perror("Error on bind");
97  return EXIT_FAILURE;
98  }
99 #endif
100 
101  CrashCount = 0;
102  nice(10-nice(0));
103  while (CrashCount < CRASH_COUNT) {
104  time_t StartTime;
105  time_t EndTime;
106  pid_t Server;
107 
108  chdir(CROSSFIRE_TMPDIR);
109  time(&StartTime);
110 #ifdef USE_WATCHDOG
111  if (pipe(Pipe) == 0) {
112  void (*OldHandler)(int);
113 
114  OldHandler = signal(SIGCHLD, SignalHandler);
115 #endif
116  switch (Server = fork()) {
117  case 0:
118  execl(CROSSFIRE_SERVER, CROSSFIRE_SERVER, "-server", NULL);
119  return EXIT_FAILURE;
120 
121  case -1:
123  break;
124 
125  default:
126 #ifdef USE_WATCHDOG
127  while (1) {
128  fd_set Files;
129  struct timeval Timeout;
130  int Max;
131 
132  FD_ZERO(&Files);
133  FD_SET(Pipe[0], &Files);
134  FD_SET(fd, &Files);
135  Timeout.tv_sec = 5*60;
136  Timeout.tv_usec = 0;
137  if (fd > Pipe[0]) {
138  Max = fd+1;
139  } else {
140  Max = Pipe[0]+1;
141  }
142  while (select(Max, &Files, NULL, NULL, &Timeout) == -1) {
143  if (errno != EINTR) {
144  perror("Error on select");
145  return EXIT_FAILURE;
146  }
147  }
148  if (FD_ISSET(Pipe[0], &Files)) {
149  /* crash */
150  unlink("core");
151  waitpid(Server, NULL, 0);
152  printf("Server crash!\n");
153  break;
154  } else if (FD_ISSET(fd, &Files)) {
155  /* watchdog */
156  char t;
157 
158  recv(fd, &t, 1, 0);
159  } else {
160  /* timeout */
161  printf("Watchdog timeout!\n");
162  if (kill(Server, SIGKILL) != 0) {
163  perror("Error on kill");
164  return EXIT_FAILURE;
165  }
166  }
167  }
168 #else
169  waitpid(Server, NULL, 0);
170 #endif
171 #ifdef USE_WATCHDOG
172  signal(SIGCHLD, OldHandler);
173 #endif
174  time(&EndTime);
175  if (EndTime-StartTime < CRASH_INTERVAL) {
176  CrashCount++;
177  } else {
178  CrashCount = 0;
179  }
180  break;
181  }
182 #ifdef USE_WATCHDOG
183  close(Pipe[0]);
184  close(Pipe[1]);
185  } else {
187  }
188 #endif
189  }
190 #ifdef USE_WATCHDOG
191  close(fd);
192 #endif
193  return 0;
194 }
void SignalHandler(int Unused)
#define CRASH_COUNT
#define CROSSFIRE_SERVER
int Pipe[2]
#define sleep(x)
Definition: win32.h:167
int main(void)
#define unlink(__a)
Definition: win32.h:67
#define ERROR_SLEEP
#define CRASH_INTERVAL
#define CROSSFIRE_TMPDIR