1 /*-
2  * Copyright (c) 1998-2008 DHIS, Dynamic Host Information System
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include<string.h>
29 #include<stdio.h>
30 
31 #include "dhisd.h"
32 #include "online.h"
33 #include "network.h"
34 #include "ddb.h"
35 #include "qrc.h"
36 #include "misc.h"
37 
38 /* Locally defined prototypes */
39 void sig_parse(int);
40 void sig_hup(int);
41 void sig_usr1(int);
42 void sig_usr2(int);
43 void sig_void(int);
44 void sig_chld(int);
45 void sig_term(int);
46 void usage(char *);
47 
48 
49 int do_reload=0;
50 int do_parse=0;
51 int debug_level = 0;
52 
53 char logfile[256];
54 char pid_file[256];
55 char database_file[256];
56 char conf_file[256];
57 
58 extern int udp_port;
59 extern char dhisd_bind_address[32];
60 extern int db_mode;
61 
62 #ifdef	WITH_MYSQL
63 char sql_server[128];
64 char sql_user[128];
65 char sql_password[128];
66 char sql_dbase[128];
67 #endif
68 
69 
read_conf(void)70 int read_conf(void) {
71 
72 	FILE *fp;
73 	char str[256];
74 
75 	DSYSLOG(1,(LOG_DEBUG,"read_conf(): Reading configuration File\n"));
76 
77 #ifdef	WITH_MYSQL
78 	sql_server[0]='\0';
79 	sql_user[0]='\0';
80 	sql_password[0]='\0';
81 	sql_dbase[0]='\0';
82 #endif
83 
84 	fp=fopen(conf_file,"r");
85 	if(fp==NULL) return 0;
86 	while(fgets(str,255,fp)!=NULL) {
87 		char command[256];
88 		off_nl(str);
89 		strcpy(command,line_entry(1,str));
90 		strtolower(command);
91 		if(!strcmp(command,"bindaddress"))
92 			strncpy(dhisd_bind_address,line_entry(2,str),31);
93 		if(!strcmp(command,"pidfile"))
94 			strncpy(pid_file,line_entry(2,str),255);
95 		if(!strcmp(command,"logfile"))
96 			strncpy(logfile,line_entry(2,str),255);
97 		if(!strcmp(command,"dbfile"))
98 			strncpy(database_file,line_entry(2,str),255);
99 		if(!strcmp(command,"bindport"))
100 			udp_port=atoi(line_entry(2,str));
101 #ifdef	WITH_MYSQL
102 		if(!strcmp(command,"mysqlserver"))
103 			strncpy(sql_server,line_entry(2,str),127);
104 		if(!strcmp(command,"mysqluser"))
105 			strncpy(sql_user,line_entry(2,str),127);
106 		if(!strcmp(command,"mysqlpassword"))
107 			strncpy(sql_password,line_entry(2,str),127);
108 		if(!strcmp(command,"mysqldbase"))
109 			strncpy(sql_dbase,line_entry(2,str),127);
110 #endif
111 	}
112 	fclose(fp);
113 	return 1;
114 }
115 
sig_parse(int s)116 void sig_parse(int s) {
117 
118 	if(s!=SIGALRM) return;
119 	do_parse=1;
120 	signal(SIGALRM,sig_parse);
121 	alarm(PARSE_TIMEOUT);
122 }
123 
sig_hup(int s)124 void sig_hup(int s) {
125 
126 	if(s!=SIGHUP) return;
127 	DSYSLOG(0,(LOG_INFO,"sig_hup(): Reload HUP Received\n"));
128 	do_reload=1;
129 	signal(SIGHUP,sig_hup);
130 }
131 
sig_void(int s)132 void sig_void(int s) {
133 
134 	if(s!=SIGCHLD) return;	/* Just so that cc doesn't complain */
135 	return;
136 }
137 
sig_usr1(int s)138 void sig_usr1(int s) {
139 	if(s!=SIGUSR1) return;
140 	debug_level++;
141 	syslog(LOG_DEBUG,"debug level %d\n", debug_level);
142 	signal(SIGUSR1,sig_usr1);
143 }
144 
sig_usr2(int s)145 void sig_usr2(int s) {
146 	if(s!=SIGUSR2) return;
147 	debug_level = 0;
148 	syslog(LOG_DEBUG,"debug level %d\n", debug_level);
149 	signal(SIGUSR2,sig_usr2);
150 }
151 
152 
sig_chld(int s)153 void sig_chld(int s) {
154 
155 	if(s!=SIGCHLD) return;
156 	int r;
157 	wait(&r);
158 	signal(SIGCHLD,sig_chld);
159 }
160 
sig_term(int s)161 void sig_term(int s) {
162 
163 	if(s!=SIGTERM && s!=SIGKILL && s!=SIGINT && s!=SIGQUIT) return;
164 	signal(SIGCHLD,sig_void);
165 	on_free();
166 	net_close();
167  	msg_log("SIGTERM received. Exiting ...");
168 	unlink(pid_file);
169 	exit(0);
170 }
171 
172 
usage(char * s)173 void usage(char *s) {
174 
175 	fprintf(stderr,"Syntax: %s [-D] [-P pid_file] [-l log_file] [-c config_file]\n",s);
176 
177 #ifdef	WITH_MYSQL
178 	fprintf(stderr,"        [-d dbfile|mysql] [-b ipv4_interface_address] [-p udp_port] \n");
179 #else
180 	fprintf(stderr,"        [-d dbfile] [-b ipv4_interface_address] [-p udp_port] \n");
181 #endif
182 
183 	exit(0);
184 }
185 
main(int argc,char * argv[])186 int main(int argc,char *argv[]) {
187 
188 	FILE *fp;
189 	char str[128];
190 	extern char *optarg;
191 	extern int optreset;
192 	extern int optind;
193 	int c;
194 
195 	strcpy(logfile,DHISD_LOG);
196 	strcpy(pid_file,DHISD_PID);
197 	strcpy(database_file,DHISD_DB_FILE);
198 	strcpy(conf_file,DHISD_CONF_FILE);
199 
200 	while((c=getopt(argc,argv,"Dhp:P:l:b:d:c:")) !=EOF) {
201 		switch(c) {
202 			case('c'):  strcpy(conf_file,optarg);break;
203 		}
204 	}
205 
206 	read_conf();
207 	optreset=1;
208 	optind=1;
209 
210 	while((c=getopt(argc,argv,"Dhp:P:l:b:d:c:")) !=EOF) {
211 	switch(c) {
212 	case('l'):strcpy(logfile,optarg);break;
213 	case('P'):strcpy(pid_file,optarg);break;
214 	case('p'):udp_port=atoi(optarg);break;
215 	case('b'):strcpy(dhisd_bind_address,optarg);break;
216 	case('d'):strcpy(database_file,optarg);break;
217 	case('D'):debug_level++;break;
218 	case('h'): usage(argv[0]);
219 	case('c'):  strcpy(conf_file,optarg);break;
220 	default: usage(argv[0]);
221 	}
222 	}
223 
224 
225 #ifdef WITH_MYSQL
226 	if(!strcmp(database_file,"mysql")) db_mode=DB_MYSQL;
227 	if(db_mode==DB_MYSQL && (sql_server[0]=='\0' || sql_user[0]=='\0'
228            || sql_password[0]=='\0' || sql_dbase[0]=='\0')) {
229 		syslog(LOG_ERR,"Unable to read all SQL login parameters. Cannot start server! Exiting ...");
230 		fprintf(stderr,"Unable to read all SQL login parameters. Cannot start server! Exiting ...\n");
231 
232 		exit(255);
233 	}
234 #endif
235 
236 #ifndef	DONT_FORK
237 	setsid();
238 	if(fork()) _exit(0);
239 #endif
240 
241 	if(!db_reload()) {
242 #ifdef	WITH_MYSQL
243 		if(db_mode==DB_MYSQL) {
244 
245 		// If MySQL read failed we may need to wait for the mysql server
246 		// to start. We try 3 times with 15 second intervals.
247 		int count;
248 		for(count=0;count<3;count++) {
249 			sleep(15);
250 			if(db_reload()) break;
251 		}
252 		if(count==3) {
253 		  syslog(LOG_ERR,"SQL database read failed: Please double-check your login data.");
254 		  exit(255);
255 		}
256 
257 		} else {
258 #endif
259 		  syslog(LOG_ERR,"Unable to load database. Exiting ...");
260 		  exit(255);
261 #ifdef	WITH_MYSQL
262 		}
263 #endif
264 	}
265 
266 
267 	if(net_init()) {
268 		syslog(LOG_ERR,"Unable to initialise network");
269 
270 		DSYSLOG(1,(LOG_DEBUG,"main(): Failed to initialise network\n"));
271 
272 		exit(255);
273 	}
274 
275 #ifndef	DONT_FORK
276 	close(0);
277 	close(1);
278 	close(2);
279 #endif
280 
281 	unlink(pid_file);
282 	fp=fopen(pid_file,"w");
283 	if(fp!=NULL) {
284 		fprintf(fp,"%d",(int)getpid());
285 		fclose(fp);
286 	}
287 
288 
289 
290 	sprintf(str,"Datagram Server Started [%d]",(int)getpid());
291 	msg_log(str);
292 	syslog(LOG_INFO,"DHIS Server Started");
293 
294 	signal(SIGUSR1,sig_usr1);
295 	signal(SIGUSR2,sig_usr2);
296 	signal(SIGTERM,sig_term);
297 	signal(SIGKILL,sig_term);
298 	signal(SIGINT,sig_term);
299 	signal(SIGQUIT,sig_term);
300 	signal(SIGHUP,sig_hup);
301 	signal(SIGALRM,sig_parse);
302 	signal(SIGCHLD,sig_chld);
303 	alarm(PARSE_TIMEOUT);
304 
305 
306 	for(;;) {
307 		msg_t msg;
308 		int from;
309 		if(net_check_message())
310 		  if(net_read_message(&msg,&from))
311 			net_do_dgram(msg,from);
312 
313 		if(do_reload) {
314 			db_reload();
315 			do_reload=0;
316 		}
317 
318 		if(do_parse) {
319 			on_parse();
320 			do_parse=0;
321 		}
322 		usleep(100000);		// Sleep for 100 ms
323 	}
324 }
325 
326