]>
cvs.zerfleddert.de Git - hmcfgusb/blob - hmland.c
   1 /* HM-CFG-LAN emulation for HM-CFG-USB 
   3  * Copyright (c) 2013 Michael Gernoth <michael@gernoth.net> 
   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: 
  12  * The above copyright notice and this permission notice shall be included in 
  13  * all copies or substantial portions of the Software. 
  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 
  33 #include <sys/types.h> 
  34 #include <sys/socket.h> 
  37 #include <netinet/in.h> 
  38 #include <arpa/inet.h> 
  39 #include <libusb-1.0/libusb.h> 
  44 #define PID_FILE "/var/run/hmland.pid" 
  48 static int impersonate_hmlanif 
= 0; 
  50 static int verbose 
= 0; 
  52 #define FLAG_LENGTH_BYTE        (1<<0) 
  53 #define FLAG_FORMAT_HEX         (1<<1) 
  54 #define FLAG_COMMA_BEFORE       (1<<2) 
  55 #define FLAG_COMMA_AFTER        (1<<3) 
  56 #define FLAG_NL                 (1<<4) 
  57 #define FLAG_IGNORE_COMMAS      (1<<5) 
  58 #define FLAG_PERIODIC_WAKEUP    (1<<6) 
  60 #define CHECK_SPACE(x)          if ((*outpos + x) > outend) { fprintf(stderr, "Not enough space!\n"); return 0; } 
  61 #define CHECK_AVAIL(x)          if ((*inpos + x) > inend) { fprintf(stderr, "Not enough input available!\n"); return 0; } 
  63 static int format_part_out(uint8_t **inpos
, int inlen
, uint8_t **outpos
, int outlen
, int len
, int flags
) 
  65         const uint8_t nibble
[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
  66                 'A', 'B', 'C', 'D', 'E', 'F'}; 
  67         uint8_t *buf_out 
= *outpos
; 
  68         uint8_t *outend 
= *outpos 
+ outlen
; 
  69         uint8_t *inend 
= *inpos 
+ inlen
; 
  72         if (flags 
& FLAG_COMMA_BEFORE
) { 
  78         if (flags 
& FLAG_LENGTH_BYTE
) { 
  84         if (flags 
& FLAG_FORMAT_HEX
) { 
  87                 for (i 
= 0; i 
< len
; i
++) { 
  88                         **outpos 
= nibble
[((**inpos
) & 0xf0) >> 4]; 
  90                         **outpos 
= nibble
[((**inpos
) & 0xf)]; 
  91                         *inpos 
+= 1; *outpos 
+= 1; 
  96                 memcpy(*outpos
, *inpos
, len
); 
 101         if (flags 
& FLAG_COMMA_AFTER
) { 
 107         if (flags 
& FLAG_NL
) { 
 115         return *outpos 
- buf_out
; 
 118 static uint8_t ascii_to_nibble(uint8_t a
) 
 122         if ((a 
>= '0') && (a 
<= '9')) { 
 124         } else if ((a 
>= 'A') && (a 
<= 'F')) { 
 126         } else if ((a 
>= 'a') && (a 
<= 'f')) { 
 133 static int parse_part_in(uint8_t **inpos
, int inlen
, uint8_t **outpos
, int outlen
, int flags
) 
 135         uint8_t *buf_out 
= *outpos
; 
 136         uint8_t *outend 
= *outpos 
+ outlen
; 
 137         uint8_t *inend 
= *inpos 
+ inlen
; 
 139         if (flags 
& FLAG_LENGTH_BYTE
) { 
 147                                 if (!(flags 
& FLAG_IGNORE_COMMAS
)) 
 156                 **outpos 
= (len 
/ 2); 
 160         while(*inpos 
< inend
) { 
 161                 if (**inpos 
== ',') { 
 163                         if (!(flags 
& FLAG_IGNORE_COMMAS
)) 
 172                 **outpos 
= ascii_to_nibble(**inpos
) << 4; 
 174                 **outpos 
|= ascii_to_nibble(**inpos
); 
 175                 *inpos 
+= 1; *outpos 
+= 1; 
 178         return *outpos 
- buf_out
; 
 181 static int hmlan_format_out(uint8_t *buf
, int buf_len
, void *data
) 
 186         int fd 
= *((int*)data
); 
 192         memset(out
, 0, sizeof(out
)); 
 196         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 1, 0); 
 199                         if (impersonate_hmlanif
) { 
 204                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 0, FLAG_LENGTH_BYTE
); 
 205                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 2, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 206                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 0, FLAG_COMMA_BEFORE 
| FLAG_LENGTH_BYTE
); 
 207                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 3, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 208                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 3, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 209                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 4, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 210                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 2, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE 
| FLAG_NL
); 
 214                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 3, FLAG_FORMAT_HEX
); 
 215                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 2, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 216                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 4, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 217                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 1, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 218                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 2, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 219                         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
); 
 223                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 4, FLAG_FORMAT_HEX
); 
 224                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 2, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 225                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 4, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 226                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 1, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 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_FORMAT_HEX 
| FLAG_COMMA_BEFORE 
| FLAG_LENGTH_BYTE 
| FLAG_NL
); 
 232                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 1, FLAG_FORMAT_HEX
); 
 233                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 1, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 234                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 1, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE
); 
 235                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 1, FLAG_FORMAT_HEX 
| FLAG_COMMA_BEFORE 
| FLAG_NL
); 
 239                         format_part_out(&inpos
, (buf_len
-(inpos
-buf
)), &outpos
, (sizeof(out
)-(outpos
-out
)), buf_len
-1, FLAG_FORMAT_HEX 
| FLAG_NL
); 
 240                         hexdump(buf
, buf_len
, "Unknown> "); 
 244                 fprintf(stderr
, "LAN < %s\n", out
); 
 246         w 
= write(fd
, out
, outpos
-out
); 
 255 static int hmlan_parse_in(int fd
, void *data
) 
 257         struct hmcfgusb_dev 
*dev 
= data
; 
 259         uint8_t out
[0x40]; //FIXME!!! 
 266         memset(buf
, 0, sizeof(buf
)); 
 268         r 
= read(fd
, buf
, sizeof(buf
)-1); 
 270                 uint8_t *inend 
= buf 
+ r
; 
 275                         fprintf(stderr
, "\nLAN > %s", buf
); 
 277                 while (inpos 
< inend
) { 
 278                         uint8_t *instart 
= inpos
; 
 280                         if ((*inpos 
== '\r') || (*inpos 
== '\n')) { 
 287                         last 
= inend 
- inpos
; 
 289                         for (i 
= 0; i 
< last
; i
++) { 
 290                                 if ((inpos
[i
] == '\r') || (inpos
[i
] == '\n')) { 
 299                         memset(out
, 0, sizeof(out
)); 
 300                         *outpos
++ = *inpos
++; 
 304                                         parse_part_in(&inpos
, (last
-(inpos
-instart
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 0); 
 305                                         parse_part_in(&inpos
, (last
-(inpos
-instart
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 0); 
 306                                         parse_part_in(&inpos
, (last
-(inpos
-instart
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 0); 
 307                                         parse_part_in(&inpos
, (last
-(inpos
-instart
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 0); 
 308                                         parse_part_in(&inpos
, (last
-(inpos
-instart
)), &outpos
, (sizeof(out
)-(outpos
-out
)), 0); 
 309                                         parse_part_in(&inpos
, (last
-(inpos
-instart
)), &outpos
, (sizeof(out
)-(outpos
-out
)), FLAG_LENGTH_BYTE
); 
 312                                         parse_part_in(&inpos
, (last
-(inpos
-instart
)), &outpos
, (sizeof(out
)-(outpos
-out
)), FLAG_IGNORE_COMMAS
); 
 316                         hmcfgusb_send(dev
, out
, sizeof(out
), 1); 
 328 static int comm(int fd_in
, int fd_out
, int master_socket
, int flags
) 
 330         struct hmcfgusb_dev 
*dev
; 
 331         uint8_t out
[0x40]; //FIXME!!! 
 332         int poll_timeout 
= 3600; 
 335         hmcfgusb_set_debug(debug
); 
 337         dev 
= hmcfgusb_init(hmlan_format_out
, &fd_out
); 
 339                 fprintf(stderr
, "Can't initialize HM-CFG-USB!\n"); 
 343         if (!hmcfgusb_add_pfd(dev
, fd_in
, POLLIN
)) { 
 344                 fprintf(stderr
, "Can't add client to pollfd!\n"); 
 349         if (master_socket 
>= 0) { 
 350                 if (!hmcfgusb_add_pfd(dev
, master_socket
, POLLIN
)) { 
 351                         fprintf(stderr
, "Can't add master_socket to pollfd!\n"); 
 357         if (flags 
& FLAG_PERIODIC_WAKEUP
) 
 360         memset(out
, 0, sizeof(out
)); 
 362         hmcfgusb_send_null_frame(dev
); 
 363         hmcfgusb_send(dev
, out
, sizeof(out
), 1); 
 368                 fd 
= hmcfgusb_poll(dev
, poll_timeout
); 
 370                         if (fd 
== master_socket
) { 
 373                                 client 
= accept(master_socket
, NULL
, 0); 
 375                                         shutdown(client
, SHUT_RDWR
); 
 379                                 if (hmlan_parse_in(fd
, dev
) <= 0) { 
 383                 } else if (fd 
== -1) { 
 385                                 perror("hmcfgusb_poll"); 
 388                                 /* periodically wakeup the device */ 
 389                                 hmcfgusb_send_null_frame(dev
); 
 398 void sigterm_handler(int sig
) 
 400         if (unlink(PID_FILE
) == -1) 
 401                 perror("Can't remove PID file"); 
 406 #define FLAG_DAEMON     (1 << 0) 
 407 #define FLAG_PID_FILE   (1 << 1) 
 409 static int socket_server(char *iface
, int port
, int flags
) 
 411         struct sigaction sact
; 
 412         struct sockaddr_in sin
; 
 417         if (flags 
& FLAG_DAEMON
) { 
 418                 FILE *pidfile 
= NULL
; 
 420                 if (flags 
& FLAG_PID_FILE
) { 
 423                         fd 
= open(PID_FILE
, O_CREAT 
| O_EXCL 
| O_WRONLY
, 0644); 
 425                                 if (errno 
== EEXIST
) { 
 427                                         pidfile 
= fopen(PID_FILE
, "r"); 
 429                                                 perror("PID file " PID_FILE 
" already exists, already running?"); 
 433                                         if (fscanf(pidfile
, "%u", &old_pid
) != 1) { 
 435                                                 fprintf(stderr
, "Can't read old PID from " PID_FILE 
", already running?\n"); 
 441                                         fprintf(stderr
, "Already running with PID %u according to " PID_FILE 
"!\n", old_pid
); 
 444                                 perror("Can't create PID file " PID_FILE
); 
 448                         pidfile 
= fdopen(fd
, "w"); 
 450                                 perror("Can't reopen PID file fd"); 
 454                         memset(&sact
, 0, sizeof(sact
)); 
 455                         sact
.sa_handler 
= sigterm_handler
; 
 457                         if (sigaction(SIGTERM
, &sact
, NULL
) == -1) { 
 458                                 perror("sigaction(SIGTERM)"); 
 466                                 fprintf(pidfile
, "%u\n", pid
); 
 470                         printf("Daemon with PID %u started!\n", pid
); 
 472                 } else if (pid 
< 0) { 
 481         memset(&sact
, 0, sizeof(sact
)); 
 482         sact
.sa_handler 
= SIG_IGN
; 
 484         if (sigaction(SIGPIPE
, &sact
, NULL
) == -1) { 
 485                 perror("sigaction(SIGPIPE)"); 
 489         impersonate_hmlanif 
= 1; 
 491         sock 
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
); 
 493                 perror("Can't open socket"); 
 498         if (setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, &n
, sizeof(n
)) == -1) { 
 499                 perror("Can't set socket options"); 
 503         memset(&sin
, 0, sizeof(sin
)); 
 504         sin
.sin_family 
= AF_INET
; 
 505         sin
.sin_port 
= htons(port
); 
 507                 sin
.sin_addr
.s_addr 
= htonl(INADDR_ANY
); 
 509                 if (inet_pton(AF_INET
, iface
, &(sin
.sin_addr
.s_addr
)) != 1) { 
 515         if (bind(sock
, (struct sockaddr
*)&sin
, sizeof(sin
)) == -1) { 
 516                 perror("Can't bind socket"); 
 520         if (listen(sock
, 1) == -1) { 
 521                 perror("Can't listen on socket"); 
 526                 struct sockaddr_in csin
; 
 529                 in_addr_t client_addr
; 
 531                 memset(&csin
, 0, sizeof(csin
)); 
 532                 csinlen 
= sizeof(csin
); 
 533                 client 
= accept(sock
, (struct sockaddr
*)&csin
, &csinlen
); 
 535                         perror("Couldn't accept client"); 
 539                 /* FIXME: getnameinfo... */ 
 540                 client_addr 
= ntohl(csin
.sin_addr
.s_addr
); 
 543                         printf("Client %d.%d.%d.%d connected!\n", 
 544                                         (client_addr 
& 0xff000000) >> 24, 
 545                                         (client_addr 
& 0x00ff0000) >> 16, 
 546                                         (client_addr 
& 0x0000ff00) >> 8, 
 547                                         (client_addr 
& 0x000000ff)); 
 550                 comm(client
, client
, sock
, flags
); 
 552                 shutdown(client
, SHUT_RDWR
); 
 556                         printf("Connection to %d.%d.%d.%d closed!\n", 
 557                                         (client_addr 
& 0xff000000) >> 24, 
 558                                         (client_addr 
& 0x00ff0000) >> 16, 
 559                                         (client_addr 
& 0x0000ff00) >> 8, 
 560                                         (client_addr 
& 0x000000ff)); 
 568 static int interactive_server(int flags
) 
 570         if (!comm(STDIN_FILENO
, STDOUT_FILENO
, -1, flags
)) 
 576 void hmlan_syntax(char *prog
) 
 578         fprintf(stderr
, "Syntax: %s options\n\n", prog
); 
 579         fprintf(stderr
, "Possible options:\n"); 
 580         fprintf(stderr
, "\t-D\tdebug mode\n"); 
 581         fprintf(stderr
, "\t-d\tdaemon mode\n"); 
 582         fprintf(stderr
, "\t-h\tthis help\n"); 
 583         fprintf(stderr
, "\t-i\tinteractive mode (connect HM-CFG-USB to terminal)\n"); 
 584         fprintf(stderr
, "\t-l ip\tlisten on given IP address only (for example 127.0.0.1)\n"); 
 585         fprintf(stderr
, "\t-P\tcreate PID file " PID_FILE 
" in daemon mode\n"); 
 586         fprintf(stderr
, "\t-p n\tlisten on port n (default 1000)\n"); 
 587         fprintf(stderr
, "\t-R\twakeup the device (and USB-bus) every second (fix for e.g. Raspberry Pi)\n"); 
 588         fprintf(stderr
, "\t-v\tverbose mode\n"); 
 592 int main(int argc
, char **argv
) 
 601         while((opt 
= getopt(argc
, argv
, "DdhiPp:Rl:v")) != -1) { 
 608                                 flags 
|= FLAG_DAEMON
; 
 614                                 flags 
|= FLAG_PID_FILE
; 
 617                                 port 
= strtoul(optarg
, &ep
, 10); 
 619                                         fprintf(stderr
, "Can't parse port!\n"); 
 624                                 flags 
|= FLAG_PERIODIC_WAKEUP
; 
 636                                 hmlan_syntax(argv
[0]); 
 643                 return interactive_server(flags
); 
 645                 return socket_server(iface
, port
, flags
);