1 /******************************************************************************
2 (c) 2000-2003 Christine Caulfield christine.caulfield@googlemail.com
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 ******************************************************************************/
14 #ifdef HAVE_MCHECK_H
15 #include <mcheck.h>
16 #endif
17 #include <sys/types.h>
18 #include <sys/uio.h>
19 #include <stdio.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <signal.h>
23 #include <string.h>
24 #include <fcntl.h>
25 #include <syslog.h>
26 #include <ctype.h>
27 #include <regex.h>
28 #include <stdlib.h>
29 // #include <utmp.h>
30 #include <sys/socket.h>
31 #include <sys/ioctl.h>
32 #include <sys/wait.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <sys/utsname.h>
36 #include <netinet/in.h>
37 #include <sys/socket.h>
38 #include <signal.h>
39 #include <list>
40 #include <queue>
41 #include <string>
42 #include <map>
43 #include <iterator>
44 #include <sstream>
45
46 #include "lat.h"
47 #include "utils.h"
48 #include "session.h"
49 #include "localport.h"
50 #include "connection.h"
51 #include "circuit.h"
52 #include "latcpcircuit.h"
53 #include "server.h"
54 #include "services.h"
55
56 static void sigchild(int s);
57 static void sigterm(int s);
58 static void sighup(int s);
59
usage(char * prog,FILE * f)60 static void usage(char *prog, FILE *f)
61 {
62 fprintf(f,"\n%s options:\n", prog);
63 fprintf(f," -v Verbose messages\n");
64 fprintf(f," -h Show this help text\n");
65 fprintf(f," -d Debug - don't do initial fork\n");
66 fprintf(f," -t Make rating static (don't check loadvg)\n");
67 fprintf(f," -r<num> Service rating (max if dynamic)\n");
68 fprintf(f," -s<name> Service name\n");
69 fprintf(f," -c<num> Circuit Timer in ms (default 80)\n");
70 fprintf(f," -g<text> Greeting text\n");
71 fprintf(f," -i<name> Interface name (Default to all ethernet)\n");
72 fprintf(f," -l<type> Logging type(s:syslog, e:stderr, m:mono)\n");
73 fprintf(f," -V Show version number\n\n");
74 }
75
76 /* Start Here */
main(int argc,char * argv[])77 int main(int argc, char *argv[])
78 {
79 signed char opt;
80 int verbosity = 0;
81 int debug = 0;
82 char log_char='l';
83 char interface[44];
84 int circuit_timer = 80;
85 int rating = 12;
86 char service[256];
87 char greeting[256];
88 int static_rating = 0;
89 char *interfaces[256];
90 int num_interfaces = 0;
91
92 #ifdef DEBUG_MALLOC
93 putenv("MALLOC_TRACE=/tmp/mtrace.log");
94 mtrace();
95 #endif
96
97 // Make a default greeting.
98 struct utsname uts;
99 uname(&uts);
100
101 snprintf(greeting, sizeof(greeting), "LATD for %s", uts.sysname);
102 interface[0] = '\0';
103 memset(interfaces, 0, sizeof(interfaces));
104
105 strcpy(service, (char *)LATServer::Instance()->get_local_node());
106
107 // Deal with command-line arguments. Do these before the check for root
108 // so we can check the version number and get help without being root.
109 opterr = 0;
110 while ((opt=getopt(argc,argv,"?vVhdl:r:s:t:g:i:c:")) != EOF)
111 {
112 switch(opt)
113 {
114 case 'h':
115 usage(argv[0], stdout);
116 exit(0);
117
118 case '?':
119 usage(argv[0], stderr);
120 exit(0);
121
122 case 'v':
123 verbosity++;
124 break;
125
126 case 'd':
127 debug++;
128 break;
129
130 case 'r':
131 rating = atoi(optarg);
132 break;
133
134 case 'c':
135 circuit_timer = atoi(optarg);
136 if (circuit_timer == 0)
137 {
138 usage(argv[0], stderr);
139 exit(3);
140 }
141 break;
142
143 case 'i':
144 interfaces[num_interfaces++] = optarg;
145 break;
146
147 case 's':
148 strcpy(service, optarg);
149 break;
150
151 case 'g':
152 strcpy(greeting, optarg);
153 break;
154
155 case 't':
156 static_rating = 1;
157 break;
158
159 case 'V':
160 printf("\nlatd version %s\n\n", VERSION);
161 exit(1);
162 break;
163
164 case 'l':
165 if (optarg[0] != 's' &&
166 optarg[0] != 'm' &&
167 optarg[0] != 'e')
168 {
169 usage(argv[0], stderr);
170 exit(2);
171 }
172 log_char = optarg[0];
173 break;
174 }
175 }
176
177 // We need to be root from now on.
178 if (getuid() != 0)
179 {
180 fprintf(stderr, "You need to be root to run this\n");
181 exit(2);
182 }
183
184 // Make sure we were started by latcp
185 if (getenv("LATCP_STARTED") == NULL)
186 {
187 fprintf(stderr, "\nlatd must be started with latcp -s\n");
188 fprintf(stderr, "see the man page for more information.\n\n");
189 exit(2);
190 }
191
192 // Unset it so our children don't inherit it.
193 unsetenv("LATCP_STARTED");
194
195 #ifndef NO_FORK
196 if (!debug) // Also available at run-time
197 {
198 pid_t pid;
199 switch ( pid=fork() )
200 {
201 case -1:
202 perror("server: can't fork");
203 exit(2);
204
205 case 0: // child
206 break;
207
208 default: // Parent.
209 if (verbosity > 1) printf("server: forked process %d\n", pid);
210 exit(0);
211 }
212
213 // Detach ourself from the calling environment
214 int devnull = open("/dev/null", O_RDWR);
215 close(0);
216 close(1);
217 close(2);
218 setsid();
219 dup2(devnull, 0);
220 dup2(devnull, 1);
221 dup2(devnull, 2);
222 chdir("/");
223 }
224 #endif
225
226 struct sigaction siga;
227 sigset_t ss;
228
229 sigemptyset(&ss);
230 siga.sa_handler=sigchild;
231 siga.sa_mask = ss;
232 siga.sa_flags = 0;
233 sigaction(SIGCHLD, &siga, NULL);
234
235 // Make sure we shut down tidily
236 siga.sa_handler=sigterm;
237 sigaction(SIGTERM, &siga, NULL);
238
239 siga.sa_handler=sighup;
240 sigaction(SIGHUP, &siga, NULL);
241
242 // Ignore these.
243 signal(SIGPIPE, SIG_IGN);
244 signal(SIGINT, SIG_IGN);
245 signal(SIGQUIT, SIG_IGN);
246
247 openlog("latd", LOG_PID, LOG_DAEMON);
248
249 // Go!
250 LATServer *server = LATServer::Instance();
251 server->init(static_rating, rating, service, greeting,
252 interfaces, verbosity, circuit_timer);
253 server->run();
254
255 return 0;
256 }
257
258
259 // Catch child process shutdown
sigchild(int s)260 static void sigchild(int s)
261 {
262 int status, pid;
263
264 // Make sure we reap all children
265 do
266 {
267 pid = waitpid(-1, &status, WNOHANG);
268 }
269 while (pid > 0);
270 }
271
272 // Catch termination signal
sigterm(int s)273 static void sigterm(int s)
274 {
275 syslog(LOG_INFO, "SIGTERM caught, going down\n");
276 LATServer *server = LATServer::Instance();
277 server->shutdown();
278 }
279
280
281 // Catch hangup signal
282 // Resend service announcement.
sighup(int s)283 static void sighup(int s)
284 {
285 // Can't do it right now because alarm(0) cancels!
286 alarm(1);
287 }
288
289
290