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