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