1 #include <stdio.h>
2 #include <stdarg.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <time.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <sys/stat.h>
9 #include <errno.h>
10 #include <signal.h>
11 #include <sys/wait.h>
12 #include <sys/ioctl.h>
13 #include "xmalloc.h"
14 #include "main.h"
15 #include "hx.h"
16 
17 #define _PATH_HXD_CONF "./hxd.conf"
18 
19 char **hxd_environ = 0;
20 
21 int hxd_open_max = 0;
22 struct hxd_file *hxd_files = 0;
23 
24 int high_fd = 0;
25 
26 fd_set hxd_rfds,
27        hxd_wfds;
28 
29 void
qbuf_set(struct qbuf * q,u_int32_t pos,u_int32_t len)30 qbuf_set (struct qbuf *q, u_int32_t pos, u_int32_t len)
31 {
32 	int need_more = q->pos + q->len < pos + len;
33 
34 	q->pos = pos;
35 	q->len = len;
36 	if (need_more)
37 		q->buf = xrealloc(q->buf, q->pos + q->len + 1); /* +1 for null */
38 }
39 
40 void
qbuf_add(struct qbuf * q,void * buf,u_int32_t len)41 qbuf_add (struct qbuf *q, void *buf, u_int32_t len)
42 {
43 	size_t pos = q->pos + q->len;
44 
45 	qbuf_set(q, q->pos, q->len + len);
46 	memcpy(&q->buf[pos], buf, len);
47 }
48 
49 void
hxd_log(const char * fmt,...)50 hxd_log (const char *fmt, ...)
51 {
52 	va_list ap;
53 	char buf[2048];
54 	int len;
55 	time_t t;
56 	struct tm tm;
57 
58 	time(&t);
59 	localtime_r(&t, &tm);
60 	strftime(buf, 21, "%H:%M:%S %m/%d/%Y\t", &tm);
61 	va_start(ap, fmt);
62 	len = vsnprintf(&buf[20], sizeof(buf) - 24, fmt, ap);
63 	va_end(ap);
64 	if (len == -1)
65 		len = sizeof(buf) - 24;
66 	len += 20;
67 	buf[len++] = '\n';
68 	buf[len] = 0;
69 	hx_printf_prefix(&hx_htlc, 0, INFOPREFIX, "%s", buf);
70 }
71 
72 static RETSIGTYPE
sig_alrm(int sig)73 sig_alrm (int sig __attribute__((__unused__)))
74 {
75 
76 }
77 
78 #if !defined(ONLY_GTK)
79 struct timer {
80 	struct timer *next;
81 	struct timeval add_tv;
82 	struct timeval tv;
83 	int (*fn)();
84 	void *ptr;
85 	u_int8_t expire;
86 };
87 
88 static struct timer *timer_list = 0;
89 
90 void
timer_add(struct timeval * tv,int (* fn)(),void * ptr)91 timer_add (struct timeval *tv, int (*fn)(), void *ptr)
92 {
93 	struct timer *timer, *timerp;
94 
95 	timer = xmalloc(sizeof(struct timer));
96 	timer->add_tv = *tv;
97 	timer->tv = *tv;
98 	timer->fn = fn;
99 	timer->ptr = ptr;
100 
101 	timer->expire = 0;
102 
103 	if (!timer_list || (timer_list->tv.tv_sec > timer->tv.tv_sec
104 			    || (timer_list->tv.tv_sec == timer->tv.tv_sec && timer_list->tv.tv_usec > timer->tv.tv_usec))) {
105 		timer->next = timer_list;
106 		timer_list = timer;
107 		return;
108 	}
109 	for (timerp = timer_list; timerp; timerp = timerp->next) {
110 		if (!timerp->next || (timerp->next->tv.tv_sec > timer->tv.tv_sec
111 				      || (timerp->next->tv.tv_sec == timer->tv.tv_sec && timerp->next->tv.tv_usec > timer->tv.tv_usec))) {
112 			timer->next = timerp->next;
113 			timerp->next = timer;
114 			return;
115 		}
116 	}
117 }
118 
119 void
timer_delete_ptr(void * ptr)120 timer_delete_ptr (void *ptr)
121 {
122 	struct timer *timerp, *next;
123 
124 	if (!timer_list)
125 		return;
126 	while (timer_list->ptr == ptr) {
127 		next = timer_list->next;
128 		xfree(timer_list);
129 		timer_list = next;
130 		if (!timer_list)
131 			return;
132 	}
133 	for (timerp = timer_list; timerp->next; timerp = next) {
134 		next = timerp->next;
135 		if (next->ptr == ptr) {
136 			next = timerp->next->next;
137 			xfree(timerp->next);
138 			timerp->next = next;
139 			next = timerp;
140 		}
141 	}
142 }
143 
144 void
timer_add_secs(time_t secs,int (* fn)(),void * ptr)145 timer_add_secs (time_t secs, int (*fn)(), void *ptr)
146 {
147 	struct timeval tv;
148 	tv.tv_sec = secs;
149 	tv.tv_usec = 0;
150 	timer_add(&tv, fn, ptr);
151 }
152 
153 static void
timer_check(struct timeval * before,struct timeval * after)154 timer_check (struct timeval *before, struct timeval *after)
155 {
156 	struct timer *timer, *next, *prev;
157 	time_t secdiff, usecdiff;
158 
159 	secdiff = after->tv_sec - before->tv_sec;
160 	if (before->tv_usec > after->tv_usec) {
161 		secdiff--;
162 		usecdiff = 1000000 - (before->tv_usec - after->tv_usec);
163 	} else {
164 		usecdiff = after->tv_usec - before->tv_usec;
165 	}
166 	for (timer = timer_list; timer; timer = timer->next) {
167 		if (secdiff > timer->tv.tv_sec
168 		    || (secdiff == timer->tv.tv_sec && usecdiff >= timer->tv.tv_usec)) {
169 			timer->expire = 1;
170 			timer->tv.tv_sec = timer->add_tv.tv_sec
171 					 - (secdiff - timer->tv.tv_sec);
172 			if (usecdiff > (timer->tv.tv_usec + timer->add_tv.tv_usec)) {
173 				timer->tv.tv_sec -= 1;
174 				timer->tv.tv_usec = 1000000 - timer->add_tv.tv_usec
175 						  + timer->tv.tv_usec - usecdiff;
176 			} else {
177 				timer->tv.tv_usec = timer->add_tv.tv_usec
178 						  + timer->tv.tv_usec - usecdiff;
179 			}
180 		} else {
181 			timer->tv.tv_sec -= secdiff;
182 			if (usecdiff > timer->tv.tv_usec) {
183 				timer->tv.tv_sec -= 1;
184 				timer->tv.tv_usec = 1000000 - (usecdiff - timer->tv.tv_usec);
185 			} else
186 				timer->tv.tv_usec -= usecdiff;
187 		}
188 	}
189 
190 	prev = 0;
191 	for (timer = timer_list; timer; timer = next) {
192 		next = timer->next;
193 		if (timer->expire) {
194 			int keep;
195 			int (*fn)() = timer->fn, *ptr = timer->ptr;
196 
197 			if (prev)
198 				prev->next = next;
199 			if (timer == timer_list)
200 				timer_list = next;
201 			keep = fn(ptr);
202 			if (keep)
203 				timer_add(&timer->add_tv, fn, ptr);
204 			xfree(timer);
205 			next = timer_list;
206 		} else {
207 			prev = timer;
208 		}
209 	}
210 }
211 
212 void
hxd_fd_add(int fd)213 hxd_fd_add (int fd)
214 {
215 	if (high_fd < fd)
216 		high_fd = fd;
217 }
218 
219 void
hxd_fd_del(int fd)220 hxd_fd_del (int fd)
221 {
222 	if (high_fd == fd) {
223 		for (fd--; fd && !FD_ISSET(fd, &hxd_rfds); fd--)
224 			;
225 		high_fd = fd;
226 	}
227 }
228 
229 void
hxd_fd_set(int fd,int rw)230 hxd_fd_set (int fd, int rw)
231 {
232 	if (rw & FDR)
233 		FD_SET(fd, &hxd_rfds);
234 	if (rw & FDW)
235 		FD_SET(fd, &hxd_wfds);
236 }
237 
238 void
hxd_fd_clr(int fd,int rw)239 hxd_fd_clr (int fd, int rw)
240 {
241 	if (rw & FDR)
242 		FD_CLR(fd, &hxd_rfds);
243 	if (rw & FDW)
244 		FD_CLR(fd, &hxd_wfds);
245 }
246 
247 static void loopZ (void) __attribute__((__noreturn__));
248 
249 static void
loopZ(void)250 loopZ (void)
251 {
252 	fd_set rfds, wfds;
253 	struct timeval before, tv;
254 
255 	gettimeofday(&tv, 0);
256 	for (;;) {
257 		register int n, i;
258 
259 		if (timer_list) {
260 			gettimeofday(&before, 0);
261 			timer_check(&tv, &before);
262 			if (timer_list)
263 				tv = timer_list->tv;
264 		}
265 		rfds = hxd_rfds;
266 		wfds = hxd_wfds;
267 		n = select(high_fd + 1, &rfds, &wfds, 0, timer_list ? &tv : 0);
268 		if (n < 0 && errno != EINTR) {
269 			hxd_log("loopZ: select: %s", strerror(errno));
270 			exit(1);
271 		}
272 		gettimeofday(&tv, 0);
273 		if (timer_list) {
274 			timer_check(&before, &tv);
275 		}
276 		if (n <= 0)
277 			continue;
278 		for (i = 0; i < high_fd + 1; i++) {
279 			if (FD_ISSET(i, &rfds) && FD_ISSET(i, &hxd_rfds)) {
280 				if (hxd_files[i].ready_read)
281 					hxd_files[i].ready_read(i);
282 				if (!--n)
283 					break;
284 			}
285 			if (FD_ISSET(i, &wfds) && FD_ISSET(i, &hxd_wfds)) {
286 				if (hxd_files[i].ready_write)
287 					hxd_files[i].ready_write(i);
288 				if (!--n)
289 					break;
290 			}
291 		}
292 	}
293 }
294 #endif /* ONLY_GTK */
295 
296 #if defined(CONFIG_CIPHER)
297 #include "cipher.h"
298 
299 #if USE_OPENSSL && !defined(OPENSSL_NO_EGD)
300 #include <openssl/rand.h>
301 
302 static char *egd_path = 0;
303 
304 static void
set_egd_path(char ** egd_pathp,const char * str)305 set_egd_path (char **egd_pathp, const char *str)
306 {
307 	int r;
308 
309 	if (*egd_pathp)
310 		xfree(*egd_pathp);
311 	*egd_pathp = xstrdup(str);
312 #if 0 /* old openssl */
313 	r = -1;
314 #else
315 	r = RAND_egd(str);
316 #endif
317 	if (r == -1) {
318 		hx_printf_prefix(&hx_htlc, 0, INFOPREFIX,
319 				 "failed to get entropy from egd socket %s\n", str);
320 	}
321 }
322 #endif
323 
324 static void
cipher_init(void)325 cipher_init (void)
326 {
327 #if USE_OPENSSL && !defined(OPENSSL_NO_EGD)
328 	variable_add(&egd_path, set_egd_path, "egd_path");
329 #else
330 	srand(getpid()*clock());
331 #endif
332 }
333 #endif /* CONFIG_CIPHER */
334 
335 extern void hlserver_reap_pid (pid_t pid, int status);
336 extern void hlclient_reap_pid (pid_t pid, int status);
337 
338 RETSIGTYPE
sig_chld(int sig)339 sig_chld (int sig __attribute__((__unused__)))
340 {
341 	int status, serrno = errno;
342 	pid_t pid;
343 
344 #ifndef WAIT_ANY
345 #define WAIT_ANY -1
346 #endif
347 
348 	for (;;) {
349 		pid = waitpid(WAIT_ANY, &status, WNOHANG);
350 		if (pid < 0) {
351 			if (errno == EINTR)
352 				continue;
353 			goto ret;
354 		}
355 		if (!pid)
356 			goto ret;
357 		hlclient_reap_pid(pid, status);
358 	}
359 
360 ret:
361 	errno = serrno;
362 }
363 
364 static RETSIGTYPE
sig_bus(int sig)365 sig_bus (int sig __attribute__((__unused__)))
366 {
367 	hxd_log("\n\
368 caught SIGBUS -- mail ran@krazynet.com with output from:\n\
369 $ gcc -v hxd.c\n\
370 $ cc -v hxd.c\n\
371 $ gdb hxd core\n\
372 (gdb) backtrace\n\
373 and any other information you think is useful");
374 	abort();
375 }
376 
377 extern void hotline_server_init (void);
378 extern void hotline_client_init (int argc, char **argv);
379 extern void tracker_server_init (void);
380 extern void tracker_register_init (void);
381 
382 static RETSIGTYPE
sig_tstp(int sig)383 sig_tstp (int sig __attribute__((__unused__)))
384 {
385 	hxd_log("SIGTSTP");
386 }
387 
388 #if !defined(_SC_OPEN_MAX) && defined(HAVE_GETRLIMIT)
389 #include <sys/time.h>
390 #include <sys/resource.h>
391 #endif
392 
393 #if 0
394 static struct timeval tv1, tv2, tv3, ctv1,ctv2,ctv3;
395 int
396 tfn (struct timeval *tv)
397 {
398 	struct timeval *ctv;
399 	time_t s, us, secdiff, usecdiff;
400 
401 	hxd_log("timer: %u, %u", tv->tv_sec, tv->tv_usec);
402 	if (tv==&tv1)ctv=&ctv1;else if (tv==&tv2)ctv=&ctv2;else if (tv==&tv3)ctv=&ctv3;
403 	s = ctv->tv_sec;
404 	us = ctv->tv_usec;
405 	gettimeofday(ctv,0);
406 	secdiff = ctv->tv_sec - s;
407 	if (us > ctv->tv_usec) {
408 		secdiff--;
409 		usecdiff = 1000000 - (us - ctv->tv_usec);
410 	} else {
411 		usecdiff = ctv->tv_usec - us;
412 	}
413 	hxd_log("real: %u, %u",secdiff,usecdiff);
414 	return 1;
415 }
416 void tfark () __attribute__((__constructor__));
417 void tfark ()
418 {
419 	tv1.tv_sec = 2;
420 	tv1.tv_usec = 100000;
421 	gettimeofday(&ctv1,0);
422 	timer_add(&tv1, tfn, &tv1);
423 	tv2.tv_sec = 1;
424 	tv2.tv_usec = 700000;
425 	gettimeofday(&ctv2,0);
426 	timer_add(&tv2, tfn, &tv2);
427 	tv3.tv_sec = 4;
428 	tv3.tv_usec = 000000;
429 	gettimeofday(&ctv3,0);
430 	timer_add(&tv3, tfn, &tv3);
431 }
432 #endif
433 
434 static RETSIGTYPE
sig_fpe(int sig,int fpe)435 sig_fpe (int sig, int fpe)
436 {
437 	hxd_log("SIGFPE (%d): %d", sig, fpe);
438 	abort();
439 }
440 
441 #if XMALLOC_DEBUG
442 extern void DTBLINIT (void);
443 #endif
444 
445 int
main(int argc,char ** argv,char ** envp)446 main (int argc __attribute__((__unused__)), char **argv __attribute__((__unused__)), char **envp)
447 {
448 	struct sigaction act;
449 
450 #if XMALLOC_DEBUG
451 	DTBLINIT();
452 #endif
453 #if defined(_SC_OPEN_MAX)
454 	hxd_open_max = sysconf(_SC_OPEN_MAX);
455 #elif defined(RLIMIT_NOFILE)
456 	{
457 		struct rlimit rlimit;
458 
459 		if (getrlimit(RLIMIT_NOFILE, &rlimit)) {
460 			exit(1);
461 		}
462 		hxd_open_max = rlimit.rlim_max;
463 	}
464 #elif defined(HAVE_GETDTABLESIZE)
465 	hxd_open_max = getdtablesize();
466 #elif defined(OPEN_MAX)
467 	hxd_open_max = OPEN_MAX;
468 #else
469 	hxd_open_max = 16;
470 #endif
471 	if (hxd_open_max > FD_SETSIZE)
472 		hxd_open_max = FD_SETSIZE;
473 	hxd_files = xmalloc(hxd_open_max * sizeof(struct hxd_file));
474 	memset(hxd_files, 0, hxd_open_max * sizeof(struct hxd_file));
475 	FD_ZERO(&hxd_rfds);
476 	FD_ZERO(&hxd_wfds);
477 
478 	hxd_environ = envp;
479 
480 	act.sa_handler = SIG_IGN;
481 	act.sa_flags = 0;
482 	sigemptyset(&act.sa_mask);
483 	sigaction(SIGHUP, &act, 0);
484 	sigaction(SIGPIPE, &act, 0);
485 	act.sa_handler = (RETSIGTYPE (*)(int))sig_fpe;
486 	sigaction(SIGFPE, &act, 0);
487 	act.sa_handler = sig_bus;
488 	sigaction(SIGBUS, &act, 0);
489 	act.sa_handler = sig_alrm;
490 	sigaction(SIGALRM, &act, 0);
491 	act.sa_handler = sig_chld;
492 	act.sa_flags |= SA_NOCLDSTOP;
493 	sigaction(SIGCHLD, &act, 0);
494 
495 	sigaction(SIGTSTP, &act, 0);
496 	act.sa_handler = sig_tstp;
497 
498 #if defined(HAVE_LIBHPPA)
499 	allow_unaligned_data_access();
500 #endif
501 
502 #if defined(CONFIG_CIPHER)
503 	cipher_init();
504 #endif
505 	hotline_client_init(argc, argv);
506 
507 	hx_output.loop();
508 
509 #if !defined(ONLY_GTK)
510 	loopZ();
511 #endif
512 
513 	return 0;
514 }
515