only wake the device up when the timeout really expired
[hmcfgusb] / hmland.c
1 /* HM-CFG-LAN emulation for HM-CFG-USB
2 *
3 * Copyright (c) 2013 Michael Gernoth <michael@gernoth.net>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <poll.h>
31 #include <signal.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <time.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <libusb-1.0/libusb.h>
41
42 #include "hexdump.h"
43 #include "hmcfgusb.h"
44
45 #define PID_FILE "/var/run/hmland.pid"
46
47 extern char *optarg;
48
49 static int impersonate_hmlanif = 0;
50 static int debug = 0;
51 static int verbose = 0;
52
53 struct queued_rx {
54 char *rx;
55 int len;
56 struct queued_rx *next;
57 };
58
59 static struct queued_rx *qrx = NULL;
60 static int wait_for_h = 0;
61
62 #define FLAG_LENGTH_BYTE (1<<0)
63 #define FLAG_FORMAT_HEX (1<<1)
64 #define FLAG_COMMA_BEFORE (1<<2)
65 #define FLAG_COMMA_AFTER (1<<3)
66 #define FLAG_NL (1<<4)
67 #define FLAG_IGNORE_COMMAS (1<<5)
68
69 #define CHECK_SPACE(x) if ((*outpos + x) > outend) { fprintf(stderr, "Not enough space!\n"); return 0; }
70 #define CHECK_AVAIL(x) if ((*inpos + x) > inend) { fprintf(stderr, "Not enough input available!\n"); return 0; }
71
72 static void print_timestamp(FILE *f)
73 {
74 struct timeval tv;
75 struct tm *tmp;
76 char ts[32];
77
78 gettimeofday(&tv, NULL);
79 tmp = localtime(&tv.tv_sec);
80 memset(ts, 0, sizeof(ts));
81 strftime(ts, sizeof(ts)-1, "%Y-%m-%d %H:%M:%S", tmp);
82 fprintf(f, "%s.%06ld: ", ts, tv.tv_usec);
83 }
84
85 static int format_part_out(uint8_t **inpos, int inlen, uint8_t **outpos, int outlen, int len, int flags)
86 {
87 const uint8_t nibble[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
88 'A', 'B', 'C', 'D', 'E', 'F'};
89 uint8_t *buf_out = *outpos;
90 uint8_t *outend = *outpos + outlen;
91 uint8_t *inend = *inpos + inlen;
92 int i;
93
94 if (flags & FLAG_COMMA_BEFORE) {
95 CHECK_SPACE(1);
96 **outpos=',';
97 *outpos += 1;
98 }
99
100 if (flags & FLAG_LENGTH_BYTE) {
101 CHECK_AVAIL(1);
102 len = **inpos;
103 *inpos += 1;
104 }
105
106 if (flags & FLAG_FORMAT_HEX) {
107 CHECK_AVAIL(len);
108 CHECK_SPACE(len*2);
109 for (i = 0; i < len; i++) {
110 **outpos = nibble[((**inpos) & 0xf0) >> 4];
111 *outpos += 1;
112 **outpos = nibble[((**inpos) & 0xf)];
113 *inpos += 1; *outpos += 1;
114 }
115 } else {
116 CHECK_AVAIL(len);
117 CHECK_SPACE(len);
118 memcpy(*outpos, *inpos, len);
119 *outpos += len;
120 *inpos += len;
121 }
122
123 if (flags & FLAG_COMMA_AFTER) {
124 CHECK_SPACE(1);
125 **outpos=',';
126 *outpos += 1;
127 }
128
129 if (flags & FLAG_NL) {
130 CHECK_SPACE(2);
131 **outpos='\r';
132 *outpos += 1;
133 **outpos='\n';
134 *outpos += 1;
135 }
136
137 return *outpos - buf_out;
138 }
139
140 static uint8_t ascii_to_nibble(uint8_t a)
141 {
142 uint8_t c = 0x00;
143
144 if ((a >= '0') && (a <= '9')) {
145 c = a - '0';
146 } else if ((a >= 'A') && (a <= 'F')) {
147 c = (a - 'A') + 10;
148 } else if ((a >= 'a') && (a <= 'f')) {
149 c = (a - 'a') + 10;
150 }
151
152 return c;
153 }
154
155 static int parse_part_in(uint8_t **inpos, int inlen, uint8_t **outpos, int outlen, int flags)
156 {
157 uint8_t *buf_out = *outpos;
158 uint8_t *outend = *outpos + outlen;
159 uint8_t *inend = *inpos + inlen;
160
161 if (flags & FLAG_LENGTH_BYTE) {
162 int len = 0;
163 uint8_t *ip;
164
165 ip = *inpos;
166 while(ip < inend) {
167 if (*ip == ',') {
168 ip++;
169 if (!(flags & FLAG_IGNORE_COMMAS))
170 break;
171
172 continue;
173 }
174 len++;
175 ip++;
176 }
177 CHECK_SPACE(1);
178 **outpos = (len / 2);
179 *outpos += 1;
180 }
181
182 while(*inpos < inend) {
183 if (**inpos == ',') {
184 *inpos += 1;
185 if (!(flags & FLAG_IGNORE_COMMAS))
186 break;
187
188 continue;
189 }
190
191 CHECK_SPACE(1);
192 CHECK_AVAIL(2);
193
194 **outpos = ascii_to_nibble(**inpos) << 4;
195 *inpos += 1;
196 **outpos |= ascii_to_nibble(**inpos);
197 *inpos += 1; *outpos += 1;
198 }
199
200 return *outpos - buf_out;
201 }
202
203 static int hmlan_format_out(uint8_t *buf, int buf_len, void *data)
204 {
205 uint8_t out[1024];
206 uint8_t *outpos;
207 uint8_t *inpos;
208 int fd = *((int*)data);
209 int w;
210
211 if (buf_len < 1)
212 return 1;
213
214 memset(out, 0, sizeof(out));
215 outpos = out;
216 inpos = buf;
217
218 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 1, 0);
219 switch(buf[0]) {
220 case 'H':
221 if (impersonate_hmlanif) {
222 buf[5] = 'L';
223 buf[6] = 'A';
224 buf[7] = 'N';
225 }
226 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 0, FLAG_LENGTH_BYTE);
227 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 2, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
228 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 0, FLAG_COMMA_BEFORE | FLAG_LENGTH_BYTE);
229 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 3, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
230 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 3, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
231 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 4, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
232 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 2, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE | FLAG_NL);
233
234 break;
235 case 'E':
236 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 3, FLAG_FORMAT_HEX);
237 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 2, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
238 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 4, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
239 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 1, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
240 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 2, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
241 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 0, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE | FLAG_LENGTH_BYTE | FLAG_NL);
242
243 break;
244 case 'R':
245 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 4, FLAG_FORMAT_HEX);
246 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 2, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
247 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 4, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
248 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 1, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
249 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 2, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
250 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 0, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE | FLAG_LENGTH_BYTE | FLAG_NL);
251
252 break;
253 case 'I':
254 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 1, FLAG_FORMAT_HEX);
255 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 1, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
256 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 1, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE);
257 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 1, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE | FLAG_NL);
258
259 break;
260 default:
261 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), buf_len-1, FLAG_FORMAT_HEX | FLAG_NL);
262 hexdump(buf, buf_len, "Unknown> ");
263 break;
264 }
265
266 /* Queue packet until first respone to 'K' is received */
267 if (wait_for_h && buf[0] != 'H') {
268 struct queued_rx **rxp = &qrx;
269
270 while (*rxp)
271 rxp = &((*rxp)->next);
272
273 *rxp = malloc(sizeof(struct queued_rx));
274 if (!*rxp) {
275 perror("malloc");
276 return 0;
277 }
278
279 memset(*rxp, 0, sizeof(struct queued_rx));
280 (*rxp)->len = outpos-out;
281 (*rxp)->rx = malloc((*rxp)->len);
282 if (!(*rxp)->rx) {
283 perror("malloc");
284 return 0;
285 }
286 memset((*rxp)->rx, 0, (*rxp)->len);
287 memcpy((*rxp)->rx, out, (*rxp)->len);
288
289 return 1;
290 }
291
292 if (verbose) {
293 int i;
294
295 print_timestamp(stdout);
296 printf("LAN < ");
297 for (i = 0; i < outpos-out-2; i++)
298 printf("%c", out[i]);
299 printf("\n");
300 }
301
302 w = write(fd, out, outpos-out);
303 if (w <= 0) {
304 perror("write");
305 return 0;
306 }
307
308 /* Send all queued packets */
309 if (wait_for_h) {
310 struct queued_rx *curr_rx = qrx;
311 struct queued_rx *last_rx;
312
313 while (curr_rx) {
314 if (verbose) {
315 int i;
316
317 print_timestamp(stdout);
318 printf("LAN < ");
319 for (i = 0; i < curr_rx->len-2; i++)
320 printf("%c", curr_rx->rx[i]);
321 printf("\n");
322 }
323
324 w = write(fd, curr_rx->rx, curr_rx->len);
325 if (w <= 0) {
326 perror("write");
327 }
328 last_rx = curr_rx;
329 curr_rx = curr_rx->next;
330
331 free(last_rx->rx);
332 free(last_rx);
333 }
334
335 qrx = NULL;
336
337 wait_for_h = 0;
338 }
339
340 return 1;
341 }
342
343 static int hmlan_parse_in(int fd, void *data)
344 {
345 struct hmcfgusb_dev *dev = data;
346 uint8_t buf[1025];
347 uint8_t out[0x40]; //FIXME!!!
348 uint8_t *outpos;
349 uint8_t *inpos;
350 int i;
351 int last;
352 int r;
353
354 memset(buf, 0, sizeof(buf));
355
356 r = read(fd, buf, sizeof(buf)-1);
357 if (r > 0) {
358 uint8_t *inend = buf + r;
359
360 inpos = buf;
361
362 while (inpos < inend) {
363 uint8_t *instart = inpos;
364
365 if ((*inpos == '\r') || (*inpos == '\n')) {
366 inpos++;
367 continue;
368 }
369
370 outpos = out;
371
372 last = inend - inpos;
373
374 for (i = 0; i < last; i++) {
375 if ((inpos[i] == '\r') || (inpos[i] == '\n')) {
376 last = i;
377 break;
378 }
379 }
380
381 if (last == 0)
382 continue;
383
384 if (verbose) {
385 print_timestamp(stdout);
386 printf("LAN > ");
387 for (i = 0; i < last; i++)
388 printf("%c", instart[i]);
389 printf("\n");
390 }
391
392 memset(out, 0, sizeof(out));
393 *outpos++ = *inpos++;
394
395 switch(*instart) {
396 case 'S':
397 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0);
398 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0);
399 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0);
400 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0);
401 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0);
402 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), FLAG_LENGTH_BYTE);
403 break;
404 case 'Y':
405 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0);
406 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0);
407 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), FLAG_LENGTH_BYTE);
408 break;
409 default:
410 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), FLAG_IGNORE_COMMAS);
411 break;
412 }
413
414 hmcfgusb_send(dev, out, sizeof(out), 1);
415 }
416 } else if (r < 0) {
417 if (errno != ECONNRESET)
418 perror("read");
419 return r;
420 } else {
421 return 0;
422 }
423
424 return 1;
425 }
426
427 static int comm(int fd_in, int fd_out, int master_socket, int flags)
428 {
429 struct hmcfgusb_dev *dev;
430 uint8_t out[0x40]; //FIXME!!!
431 int quit = 0;
432
433 hmcfgusb_set_debug(debug);
434
435 dev = hmcfgusb_init(hmlan_format_out, &fd_out);
436 if (!dev) {
437 fprintf(stderr, "Can't initialize HM-CFG-USB!\n");
438 return 0;
439 }
440
441 if (!hmcfgusb_add_pfd(dev, fd_in, POLLIN)) {
442 fprintf(stderr, "Can't add client to pollfd!\n");
443 hmcfgusb_close(dev);
444 return 0;
445 }
446
447 if (master_socket >= 0) {
448 if (!hmcfgusb_add_pfd(dev, master_socket, POLLIN)) {
449 fprintf(stderr, "Can't add master_socket to pollfd!\n");
450 hmcfgusb_close(dev);
451 return 0;
452 }
453 }
454
455 memset(out, 0, sizeof(out));
456 out[0] = 'K';
457 wait_for_h = 1;
458 hmcfgusb_send_null_frame(dev, 1);
459 hmcfgusb_send(dev, out, sizeof(out), 1);
460
461 while(!quit) {
462 int fd;
463
464 fd = hmcfgusb_poll(dev, 1); /* Wakeup device/bus at least once a second */
465 if (fd >= 0) {
466 if (fd == master_socket) {
467 int client;
468
469 client = accept(master_socket, NULL, 0);
470 if (client >= 0) {
471 shutdown(client, SHUT_RDWR);
472 close(client);
473 }
474 } else {
475 if (hmlan_parse_in(fd, dev) <= 0) {
476 quit = 1;
477 }
478 }
479 } else if (fd == -1) {
480 if (errno) {
481 if (errno != ETIMEDOUT) {
482 perror("hmcfgusb_poll");
483 quit = 1;
484 } else {
485 /* periodically wakeup the device */
486 hmcfgusb_send_null_frame(dev, 1);
487 if (wait_for_h) {
488 memset(out, 0, sizeof(out));
489 out[0] = 'K';
490 hmcfgusb_send(dev, out, sizeof(out), 1);
491 }
492 }
493 }
494 }
495 }
496
497 hmcfgusb_close(dev);
498 return 1;
499 }
500
501 void sigterm_handler(int sig)
502 {
503 if (unlink(PID_FILE) == -1)
504 perror("Can't remove PID file");
505
506 exit(EXIT_SUCCESS);
507 }
508
509 #define FLAG_DAEMON (1 << 0)
510 #define FLAG_PID_FILE (1 << 1)
511
512 static int socket_server(char *iface, int port, int flags)
513 {
514 struct sigaction sact;
515 struct sockaddr_in sin;
516 int sock;
517 int n;
518 pid_t pid;
519
520 if (flags & FLAG_DAEMON) {
521 FILE *pidfile = NULL;
522
523 if (flags & FLAG_PID_FILE) {
524 int fd;
525
526 fd = open(PID_FILE, O_CREAT | O_EXCL | O_WRONLY, 0644);
527 if (fd == -1) {
528 if (errno == EEXIST) {
529 pid_t old_pid;
530 pidfile = fopen(PID_FILE, "r");
531 if (!pidfile) {
532 perror("PID file " PID_FILE " already exists, already running?");
533 exit(EXIT_FAILURE);
534 }
535
536 if (fscanf(pidfile, "%u", &old_pid) != 1) {
537 fclose(pidfile);
538 fprintf(stderr, "Can't read old PID from " PID_FILE ", already running?\n");
539 exit(EXIT_FAILURE);
540 }
541
542 fclose(pidfile);
543
544 fprintf(stderr, "Already running with PID %u according to " PID_FILE "!\n", old_pid);
545 exit(EXIT_FAILURE);
546 }
547 perror("Can't create PID file " PID_FILE);
548 exit(EXIT_FAILURE);
549 }
550
551 pidfile = fdopen(fd, "w");
552 if (!pidfile) {
553 perror("Can't reopen PID file fd");
554 exit(EXIT_FAILURE);
555 }
556
557 memset(&sact, 0, sizeof(sact));
558 sact.sa_handler = sigterm_handler;
559
560 if (sigaction(SIGTERM, &sact, NULL) == -1) {
561 perror("sigaction(SIGTERM)");
562 exit(EXIT_FAILURE);
563 }
564 }
565
566 pid = fork();
567 if (pid > 0) {
568 if (pidfile) {
569 fprintf(pidfile, "%u\n", pid);
570 fclose(pidfile);
571 }
572
573 printf("Daemon with PID %u started!\n", pid);
574 exit(EXIT_SUCCESS);
575 } else if (pid < 0) {
576 perror("fork");
577 exit(EXIT_FAILURE);
578 }
579
580 if (pidfile)
581 fclose(pidfile);
582 }
583
584 memset(&sact, 0, sizeof(sact));
585 sact.sa_handler = SIG_IGN;
586
587 if (sigaction(SIGPIPE, &sact, NULL) == -1) {
588 perror("sigaction(SIGPIPE)");
589 exit(EXIT_FAILURE);
590 }
591
592 impersonate_hmlanif = 1;
593
594 sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
595 if (sock == -1) {
596 perror("Can't open socket");
597 return EXIT_FAILURE;
598 }
599
600 n = 1;
601 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) {
602 perror("Can't set socket options");
603 return EXIT_FAILURE;
604 }
605
606 memset(&sin, 0, sizeof(sin));
607 sin.sin_family = AF_INET;
608 sin.sin_port = htons(port);
609 if (!iface) {
610 sin.sin_addr.s_addr = htonl(INADDR_ANY);
611 } else {
612 if (inet_pton(AF_INET, iface, &(sin.sin_addr.s_addr)) != 1) {
613 perror("inet_ntop");
614 return EXIT_FAILURE;
615 }
616 }
617
618 if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) == -1) {
619 perror("Can't bind socket");
620 return EXIT_FAILURE;
621 }
622
623 if (listen(sock, 1) == -1) {
624 perror("Can't listen on socket");
625 return EXIT_FAILURE;
626 }
627
628 while(1) {
629 struct sockaddr_in csin;
630 socklen_t csinlen;
631 int client;
632 in_addr_t client_addr;
633
634 memset(&csin, 0, sizeof(csin));
635 csinlen = sizeof(csin);
636 client = accept(sock, (struct sockaddr*)&csin, &csinlen);
637 if (client == -1) {
638 perror("Couldn't accept client");
639 continue;
640 }
641
642 /* FIXME: getnameinfo... */
643 client_addr = ntohl(csin.sin_addr.s_addr);
644
645 if (verbose) {
646 print_timestamp(stdout);
647 printf("Client %d.%d.%d.%d connected!\n",
648 (client_addr & 0xff000000) >> 24,
649 (client_addr & 0x00ff0000) >> 16,
650 (client_addr & 0x0000ff00) >> 8,
651 (client_addr & 0x000000ff));
652 }
653
654 comm(client, client, sock, flags);
655
656 shutdown(client, SHUT_RDWR);
657 close(client);
658
659 if (verbose) {
660 print_timestamp(stdout);
661 printf("Connection to %d.%d.%d.%d closed!\n",
662 (client_addr & 0xff000000) >> 24,
663 (client_addr & 0x00ff0000) >> 16,
664 (client_addr & 0x0000ff00) >> 8,
665 (client_addr & 0x000000ff));
666 }
667 sleep(1);
668 }
669
670 return EXIT_SUCCESS;
671 }
672
673 static int interactive_server(int flags)
674 {
675 if (!comm(STDIN_FILENO, STDOUT_FILENO, -1, flags))
676 return EXIT_FAILURE;
677
678 return EXIT_SUCCESS;
679 }
680
681 void hmlan_syntax(char *prog)
682 {
683 fprintf(stderr, "Syntax: %s options\n\n", prog);
684 fprintf(stderr, "Possible options:\n");
685 fprintf(stderr, "\t-D\tdebug mode\n");
686 fprintf(stderr, "\t-d\tdaemon mode\n");
687 fprintf(stderr, "\t-h\tthis help\n");
688 fprintf(stderr, "\t-i\tinteractive mode (connect HM-CFG-USB to terminal)\n");
689 fprintf(stderr, "\t-l ip\tlisten on given IP address only (for example 127.0.0.1)\n");
690 fprintf(stderr, "\t-P\tcreate PID file " PID_FILE " in daemon mode\n");
691 fprintf(stderr, "\t-p n\tlisten on port n (default 1000)\n");
692 fprintf(stderr, "\t-v\tverbose mode\n");
693
694 }
695
696 int main(int argc, char **argv)
697 {
698 int port = 1000;
699 char *iface = NULL;
700 int interactive = 0;
701 int flags = 0;
702 char *ep;
703 int opt;
704
705 while((opt = getopt(argc, argv, "DdhiPp:Rl:v")) != -1) {
706 switch (opt) {
707 case 'D':
708 debug = 1;
709 verbose = 1;
710 break;
711 case 'd':
712 flags |= FLAG_DAEMON;
713 break;
714 case 'i':
715 interactive = 1;
716 break;
717 case 'P':
718 flags |= FLAG_PID_FILE;
719 break;
720 case 'p':
721 port = strtoul(optarg, &ep, 10);
722 if (*ep != '\0') {
723 fprintf(stderr, "Can't parse port!\n");
724 exit(EXIT_FAILURE);
725 }
726 break;
727 case 'R':
728 fprintf(stderr, "-R is no longer needed (1s wakeup is default)\n");
729 break;
730 case 'l':
731 iface = optarg;
732 break;
733 case 'v':
734 verbose = 1;
735 break;
736 case 'h':
737 case ':':
738 case '?':
739 default:
740 hmlan_syntax(argv[0]);
741 exit(EXIT_FAILURE);
742 break;
743 }
744 }
745
746 if (interactive) {
747 return interactive_server(flags);
748 } else {
749 return socket_server(iface, port, flags);
750 }
751 }
Impressum, Datenschutz