send a full frame containing only zeroes instead of a zero-byte frame
[hmcfgusb] / hmland.c
CommitLineData
4732a863 1/* HM-CFG-LAN emulation for HM-CFG-USB
9db2e455
MG
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>
4371275b 31#include <signal.h>
9db2e455 32#include <errno.h>
e0a7146e
MG
33#include <sys/types.h>
34#include <sys/socket.h>
b0bf6ad2 35#include <sys/stat.h>
e6ab4631 36#include <fcntl.h>
fbbbfa37 37#include <time.h>
e0a7146e
MG
38#include <netinet/in.h>
39#include <arpa/inet.h>
9db2e455
MG
40#include <libusb-1.0/libusb.h>
41
42#include "hexdump.h"
43#include "hmcfgusb.h"
44
b0bf6ad2
MG
45#define PID_FILE "/var/run/hmland.pid"
46
627e3f33
MG
47extern char *optarg;
48
e0a7146e 49static int impersonate_hmlanif = 0;
627e3f33
MG
50static int debug = 0;
51static int verbose = 0;
e0a7146e 52
d84111c4
MG
53struct queued_rx {
54 char *rx;
55 int len;
56 struct queued_rx *next;
57};
58
59static struct queued_rx *qrx = NULL;
60static int wait_for_h = 0;
61
e75295bb
MG
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
fbbbfa37
MG
72static 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
e75295bb
MG
85static int format_part_out(uint8_t **inpos, int inlen, uint8_t **outpos, int outlen, int len, int flags)
86{
51d4ece6
MG
87 const uint8_t nibble[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
88 'A', 'B', 'C', 'D', 'E', 'F'};
e75295bb
MG
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) {
e75295bb
MG
107 CHECK_AVAIL(len);
108 CHECK_SPACE(len*2);
109 for (i = 0; i < len; i++) {
51d4ece6
MG
110 **outpos = nibble[((**inpos) & 0xf0) >> 4];
111 *outpos += 1;
112 **outpos = nibble[((**inpos) & 0xf)];
113 *inpos += 1; *outpos += 1;
e75295bb
MG
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
51d4ece6
MG
140static 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
e75295bb
MG
155static 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;
e75295bb
MG
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);
e75295bb 193
51d4ece6
MG
194 **outpos = ascii_to_nibble(**inpos) << 4;
195 *inpos += 1;
196 **outpos |= ascii_to_nibble(**inpos);
197 *inpos += 1; *outpos += 1;
e75295bb
MG
198 }
199
200 return *outpos - buf_out;
201}
202
4371275b 203static int hmlan_format_out(uint8_t *buf, int buf_len, void *data)
9db2e455 204{
e75295bb
MG
205 uint8_t out[1024];
206 uint8_t *outpos;
207 uint8_t *inpos;
e0a7146e 208 int fd = *((int*)data);
4371275b 209 int w;
9db2e455
MG
210
211 if (buf_len < 1)
4371275b 212 return 1;
9db2e455 213
e0a7146e 214 memset(out, 0, sizeof(out));
e75295bb
MG
215 outpos = out;
216 inpos = buf;
e0a7146e 217
e75295bb 218 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 1, 0);
9db2e455
MG
219 switch(buf[0]) {
220 case 'H':
e0a7146e
MG
221 if (impersonate_hmlanif) {
222 buf[5] = 'L';
223 buf[6] = 'A';
224 buf[7] = 'N';
225 }
e75295bb
MG
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);
9db2e455
MG
233
234 break;
235 case 'E':
e75295bb
MG
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
9db2e455
MG
243 break;
244 case 'R':
e75295bb
MG
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
9db2e455
MG
252 break;
253 case 'I':
e75295bb
MG
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;
9db2e455 260 default:
e75295bb 261 format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), buf_len-1, FLAG_FORMAT_HEX | FLAG_NL);
9db2e455
MG
262 hexdump(buf, buf_len, "Unknown> ");
263 break;
264 }
d84111c4
MG
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
62f60cc1
MG
292 if (verbose) {
293 int i;
294
fbbbfa37 295 print_timestamp(stdout);
62f60cc1 296 printf("LAN < ");
11806002 297 for (i = 0; i < outpos-out-2; i++)
62f60cc1 298 printf("%c", out[i]);
11806002 299 printf("\n");
62f60cc1 300 }
4371275b
MG
301
302 w = write(fd, out, outpos-out);
303 if (w <= 0) {
304 perror("write");
305 return 0;
306 }
307
59360394 308 /* Send all queued packets */
d84111c4
MG
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
fbbbfa37 317 print_timestamp(stdout);
d84111c4
MG
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");
d84111c4
MG
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
4371275b 340 return 1;
9db2e455
MG
341}
342
e0a7146e 343static int hmlan_parse_in(int fd, void *data)
9db2e455
MG
344{
345 struct hmcfgusb_dev *dev = data;
627e3f33 346 uint8_t buf[1025];
e75295bb
MG
347 uint8_t out[0x40]; //FIXME!!!
348 uint8_t *outpos;
349 uint8_t *inpos;
9db2e455 350 int i;
627e3f33 351 int last;
9db2e455
MG
352 int r;
353
627e3f33
MG
354 memset(buf, 0, sizeof(buf));
355
356 r = read(fd, buf, sizeof(buf)-1);
9db2e455 357 if (r > 0) {
627e3f33
MG
358 uint8_t *inend = buf + r;
359
360 inpos = buf;
361
627e3f33
MG
362 while (inpos < inend) {
363 uint8_t *instart = inpos;
364
365 if ((*inpos == '\r') || (*inpos == '\n')) {
366 inpos++;
367 continue;
9db2e455 368 }
627e3f33
MG
369
370 outpos = out;
9db2e455 371
627e3f33
MG
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
62f60cc1 384 if (verbose) {
fbbbfa37 385 print_timestamp(stdout);
62f60cc1
MG
386 printf("LAN > ");
387 for (i = 0; i < last; i++)
388 printf("%c", instart[i]);
389 printf("\n");
390 }
391
627e3f33
MG
392 memset(out, 0, sizeof(out));
393 *outpos++ = *inpos++;
394
03ca736e 395 switch(*instart) {
627e3f33
MG
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;
d419ace3
MG
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);
d26506bf 408 break;
627e3f33
MG
409 default:
410 parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), FLAG_IGNORE_COMMAS);
411 break;
412 }
e75295bb 413
33df13be 414 hmcfgusb_send(dev, out, sizeof(out), 1);
627e3f33 415 }
9db2e455 416 } else if (r < 0) {
fbbbfa37
MG
417 if (errno != ECONNRESET)
418 perror("read");
e0a7146e
MG
419 return r;
420 } else {
421 return 0;
9db2e455 422 }
e0a7146e
MG
423
424 return 1;
9db2e455
MG
425}
426
23d96b59 427static int comm(int fd_in, int fd_out, int master_socket, int flags)
9db2e455
MG
428{
429 struct hmcfgusb_dev *dev;
23d96b59 430 uint8_t out[0x40]; //FIXME!!!
9db2e455
MG
431 int quit = 0;
432
627e3f33
MG
433 hmcfgusb_set_debug(debug);
434
e0a7146e 435 dev = hmcfgusb_init(hmlan_format_out, &fd_out);
9db2e455
MG
436 if (!dev) {
437 fprintf(stderr, "Can't initialize HM-CFG-USB!\n");
e0a7146e
MG
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;
9db2e455
MG
445 }
446
e0a7146e
MG
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 }
9db2e455
MG
453 }
454
23d96b59
MG
455 memset(out, 0, sizeof(out));
456 out[0] = 'K';
d84111c4 457 wait_for_h = 1;
6262005e 458 hmcfgusb_send_null_frame(dev, 1);
23d96b59 459 hmcfgusb_send(dev, out, sizeof(out), 1);
9db2e455
MG
460
461 while(!quit) {
462 int fd;
463
b55c340d 464 fd = hmcfgusb_poll(dev, 1); /* Wakeup device/bus at least once a second */
9db2e455 465 if (fd >= 0) {
e0a7146e
MG
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 }
9db2e455
MG
479 } else if (fd == -1) {
480 if (errno) {
481 perror("hmcfgusb_poll");
482 quit = 1;
23d96b59
MG
483 } else {
484 /* periodically wakeup the device */
6262005e 485 hmcfgusb_send_null_frame(dev, 1);
9db2e455
MG
486 }
487 }
488 }
489
813afd12 490 hmcfgusb_close(dev);
e0a7146e
MG
491 return 1;
492}
493
b0bf6ad2
MG
494void 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
505static int socket_server(char *iface, int port, int flags)
e0a7146e 506{
4371275b 507 struct sigaction sact;
e0a7146e
MG
508 struct sockaddr_in sin;
509 int sock;
510 int n;
627e3f33
MG
511 pid_t pid;
512
b0bf6ad2
MG
513 if (flags & FLAG_DAEMON) {
514 FILE *pidfile = NULL;
515
516 if (flags & FLAG_PID_FILE) {
e6ab4631
MG
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 }
b0bf6ad2 543
e6ab4631 544 pidfile = fdopen(fd, "w");
b0bf6ad2 545 if (!pidfile) {
e6ab4631 546 perror("Can't reopen PID file fd");
b0bf6ad2
MG
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
627e3f33
MG
559 pid = fork();
560 if (pid > 0) {
b0bf6ad2
MG
561 if (pidfile) {
562 fprintf(pidfile, "%u\n", pid);
563 fclose(pidfile);
564 }
565
627e3f33
MG
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 }
b0bf6ad2
MG
572
573 if (pidfile)
574 fclose(pidfile);
627e3f33 575 }
e0a7146e 576
4371275b
MG
577 memset(&sact, 0, sizeof(sact));
578 sact.sa_handler = SIG_IGN;
579
580 if (sigaction(SIGPIPE, &sact, NULL) == -1) {
b0bf6ad2 581 perror("sigaction(SIGPIPE)");
27f4063e 582 exit(EXIT_FAILURE);
4371275b
MG
583 }
584
e0a7146e
MG
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);
4a8a2269
MG
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 }
e0a7146e
MG
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;
627e3f33 625 in_addr_t client_addr;
e0a7146e
MG
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
627e3f33
MG
635 /* FIXME: getnameinfo... */
636 client_addr = ntohl(csin.sin_addr.s_addr);
637
638 if (verbose) {
fbbbfa37 639 print_timestamp(stdout);
627e3f33
MG
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 }
e0a7146e 646
23d96b59 647 comm(client, client, sock, flags);
e0a7146e
MG
648
649 shutdown(client, SHUT_RDWR);
650 close(client);
651
627e3f33 652 if (verbose) {
fbbbfa37 653 print_timestamp(stdout);
627e3f33
MG
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 }
e09806b6 660 sleep(1);
e0a7146e
MG
661 }
662
663 return EXIT_SUCCESS;
664}
665
23d96b59 666static int interactive_server(int flags)
e0a7146e 667{
23d96b59 668 if (!comm(STDIN_FILENO, STDOUT_FILENO, -1, flags))
e0a7146e 669 return EXIT_FAILURE;
9db2e455
MG
670
671 return EXIT_SUCCESS;
672}
e0a7146e 673
627e3f33
MG
674void 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");
4a8a2269 682 fprintf(stderr, "\t-l ip\tlisten on given IP address only (for example 127.0.0.1)\n");
b0bf6ad2 683 fprintf(stderr, "\t-P\tcreate PID file " PID_FILE " in daemon mode\n");
627e3f33
MG
684 fprintf(stderr, "\t-p n\tlisten on port n (default 1000)\n");
685 fprintf(stderr, "\t-v\tverbose mode\n");
686
687}
688
e0a7146e
MG
689int main(int argc, char **argv)
690{
627e3f33 691 int port = 1000;
4a8a2269 692 char *iface = NULL;
627e3f33 693 int interactive = 0;
b0bf6ad2 694 int flags = 0;
627e3f33
MG
695 char *ep;
696 int opt;
697
23d96b59 698 while((opt = getopt(argc, argv, "DdhiPp:Rl:v")) != -1) {
627e3f33
MG
699 switch (opt) {
700 case 'D':
701 debug = 1;
702 verbose = 1;
703 break;
704 case 'd':
b0bf6ad2 705 flags |= FLAG_DAEMON;
627e3f33
MG
706 break;
707 case 'i':
708 interactive = 1;
709 break;
b0bf6ad2
MG
710 case 'P':
711 flags |= FLAG_PID_FILE;
712 break;
627e3f33
MG
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;
23d96b59 720 case 'R':
b55c340d 721 fprintf(stderr, "-R is no longer needed (1s wakeup is default)\n");
23d96b59 722 break;
4a8a2269
MG
723 case 'l':
724 iface = optarg;
725 break;
627e3f33
MG
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) {
23d96b59 740 return interactive_server(flags);
627e3f33 741 } else {
b0bf6ad2 742 return socket_server(iface, port, flags);
627e3f33 743 }
e0a7146e 744}
Impressum, Datenschutz