send a full frame containing only zeroes instead of a zero-byte frame
[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 perror("hmcfgusb_poll");
482 quit = 1;
483 } else {
484 /* periodically wakeup the device */
485 hmcfgusb_send_null_frame(dev, 1);
486 }
487 }
488 }
489
490 hmcfgusb_close(dev);
491 return 1;
492 }
493
494 void sigterm_handler(int sig)
495 {
496 if (unlink(PID_FILE) == -1)
497 perror("Can't remove PID file");
498
499 exit(EXIT_SUCCESS);
500 }
501
502 #define FLAG_DAEMON (1 << 0)
503 #define FLAG_PID_FILE (1 << 1)
504
505 static int socket_server(char *iface, int port, int flags)
506 {
507 struct sigaction sact;
508 struct sockaddr_in sin;
509 int sock;
510 int n;
511 pid_t pid;
512
513 if (flags & FLAG_DAEMON) {
514 FILE *pidfile = NULL;
515
516 if (flags & FLAG_PID_FILE) {
517 int fd;
518
519 fd = open(PID_FILE, O_CREAT | O_EXCL | O_WRONLY, 0644);
520 if (fd == -1) {
521 if (errno == EEXIST) {
522 pid_t old_pid;
523 pidfile = fopen(PID_FILE, "r");
524 if (!pidfile) {
525 perror("PID file " PID_FILE " already exists, already running?");
526 exit(EXIT_FAILURE);
527 }
528
529 if (fscanf(pidfile, "%u", &old_pid) != 1) {
530 fclose(pidfile);
531 fprintf(stderr, "Can't read old PID from " PID_FILE ", already running?\n");
532 exit(EXIT_FAILURE);
533 }
534
535 fclose(pidfile);
536
537 fprintf(stderr, "Already running with PID %u according to " PID_FILE "!\n", old_pid);
538 exit(EXIT_FAILURE);
539 }
540 perror("Can't create PID file " PID_FILE);
541 exit(EXIT_FAILURE);
542 }
543
544 pidfile = fdopen(fd, "w");
545 if (!pidfile) {
546 perror("Can't reopen PID file fd");
547 exit(EXIT_FAILURE);
548 }
549
550 memset(&sact, 0, sizeof(sact));
551 sact.sa_handler = sigterm_handler;
552
553 if (sigaction(SIGTERM, &sact, NULL) == -1) {
554 perror("sigaction(SIGTERM)");
555 exit(EXIT_FAILURE);
556 }
557 }
558
559 pid = fork();
560 if (pid > 0) {
561 if (pidfile) {
562 fprintf(pidfile, "%u\n", pid);
563 fclose(pidfile);
564 }
565
566 printf("Daemon with PID %u started!\n", pid);
567 exit(EXIT_SUCCESS);
568 } else if (pid < 0) {
569 perror("fork");
570 exit(EXIT_FAILURE);
571 }
572
573 if (pidfile)
574 fclose(pidfile);
575 }
576
577 memset(&sact, 0, sizeof(sact));
578 sact.sa_handler = SIG_IGN;
579
580 if (sigaction(SIGPIPE, &sact, NULL) == -1) {
581 perror("sigaction(SIGPIPE)");
582 exit(EXIT_FAILURE);
583 }
584
585 impersonate_hmlanif = 1;
586
587 sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
588 if (sock == -1) {
589 perror("Can't open socket");
590 return EXIT_FAILURE;
591 }
592
593 n = 1;
594 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) {
595 perror("Can't set socket options");
596 return EXIT_FAILURE;
597 }
598
599 memset(&sin, 0, sizeof(sin));
600 sin.sin_family = AF_INET;
601 sin.sin_port = htons(port);
602 if (!iface) {
603 sin.sin_addr.s_addr = htonl(INADDR_ANY);
604 } else {
605 if (inet_pton(AF_INET, iface, &(sin.sin_addr.s_addr)) != 1) {
606 perror("inet_ntop");
607 return EXIT_FAILURE;
608 }
609 }
610
611 if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) == -1) {
612 perror("Can't bind socket");
613 return EXIT_FAILURE;
614 }
615
616 if (listen(sock, 1) == -1) {
617 perror("Can't listen on socket");
618 return EXIT_FAILURE;
619 }
620
621 while(1) {
622 struct sockaddr_in csin;
623 socklen_t csinlen;
624 int client;
625 in_addr_t client_addr;
626
627 memset(&csin, 0, sizeof(csin));
628 csinlen = sizeof(csin);
629 client = accept(sock, (struct sockaddr*)&csin, &csinlen);
630 if (client == -1) {
631 perror("Couldn't accept client");
632 continue;
633 }
634
635 /* FIXME: getnameinfo... */
636 client_addr = ntohl(csin.sin_addr.s_addr);
637
638 if (verbose) {
639 print_timestamp(stdout);
640 printf("Client %d.%d.%d.%d connected!\n",
641 (client_addr & 0xff000000) >> 24,
642 (client_addr & 0x00ff0000) >> 16,
643 (client_addr & 0x0000ff00) >> 8,
644 (client_addr & 0x000000ff));
645 }
646
647 comm(client, client, sock, flags);
648
649 shutdown(client, SHUT_RDWR);
650 close(client);
651
652 if (verbose) {
653 print_timestamp(stdout);
654 printf("Connection to %d.%d.%d.%d closed!\n",
655 (client_addr & 0xff000000) >> 24,
656 (client_addr & 0x00ff0000) >> 16,
657 (client_addr & 0x0000ff00) >> 8,
658 (client_addr & 0x000000ff));
659 }
660 sleep(1);
661 }
662
663 return EXIT_SUCCESS;
664 }
665
666 static int interactive_server(int flags)
667 {
668 if (!comm(STDIN_FILENO, STDOUT_FILENO, -1, flags))
669 return EXIT_FAILURE;
670
671 return EXIT_SUCCESS;
672 }
673
674 void hmlan_syntax(char *prog)
675 {
676 fprintf(stderr, "Syntax: %s options\n\n", prog);
677 fprintf(stderr, "Possible options:\n");
678 fprintf(stderr, "\t-D\tdebug mode\n");
679 fprintf(stderr, "\t-d\tdaemon mode\n");
680 fprintf(stderr, "\t-h\tthis help\n");
681 fprintf(stderr, "\t-i\tinteractive mode (connect HM-CFG-USB to terminal)\n");
682 fprintf(stderr, "\t-l ip\tlisten on given IP address only (for example 127.0.0.1)\n");
683 fprintf(stderr, "\t-P\tcreate PID file " PID_FILE " in daemon mode\n");
684 fprintf(stderr, "\t-p n\tlisten on port n (default 1000)\n");
685 fprintf(stderr, "\t-v\tverbose mode\n");
686
687 }
688
689 int main(int argc, char **argv)
690 {
691 int port = 1000;
692 char *iface = NULL;
693 int interactive = 0;
694 int flags = 0;
695 char *ep;
696 int opt;
697
698 while((opt = getopt(argc, argv, "DdhiPp:Rl:v")) != -1) {
699 switch (opt) {
700 case 'D':
701 debug = 1;
702 verbose = 1;
703 break;
704 case 'd':
705 flags |= FLAG_DAEMON;
706 break;
707 case 'i':
708 interactive = 1;
709 break;
710 case 'P':
711 flags |= FLAG_PID_FILE;
712 break;
713 case 'p':
714 port = strtoul(optarg, &ep, 10);
715 if (*ep != '\0') {
716 fprintf(stderr, "Can't parse port!\n");
717 exit(EXIT_FAILURE);
718 }
719 break;
720 case 'R':
721 fprintf(stderr, "-R is no longer needed (1s wakeup is default)\n");
722 break;
723 case 'l':
724 iface = optarg;
725 break;
726 case 'v':
727 verbose = 1;
728 break;
729 case 'h':
730 case ':':
731 case '?':
732 default:
733 hmlan_syntax(argv[0]);
734 exit(EXIT_FAILURE);
735 break;
736 }
737 }
738
739 if (interactive) {
740 return interactive_server(flags);
741 } else {
742 return socket_server(iface, port, flags);
743 }
744 }
Impressum, Datenschutz