Fixed ARM build
[ZeXOS.git] / tools / ips2ip / main.cpp
blobe7a673ffc4f4d013e1b0b69d899c40dea0b2872b
1 /*
2 * ZeX/OS
3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <iostream>
21 #include <string>
22 #include <unistd.h>
23 #include <netdb.h>
24 #include <netinet/in.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <sys/un.h>
29 #include <fcntl.h>
30 #include <termios.h>
31 #include <stdio.h>
32 #include <arpa/inet.h>
33 #include <errno.h>
35 extern int errno;
38 #define BUFSIZE 10240
40 /* baudrate settings are defined in <asm/termbits.h>, which is
41 included by <termios.h> */
42 #define BAUDRATE B9600
43 /* change this definition for the correct port */
44 #define MODEMDEVICE "/dev/ttyS0"
45 #define _POSIX_SOURCE 1 /* POSIX compliant source */
47 #define IPS_PROTO_CONNECT 'c'
48 #define IPS_PROTO_CONNECTED 'k'
49 #define IPS_PROTO_RECV 'r'
50 #define IPS_PROTO_EOF 'e'
51 #define IPS_PROTO_CLOSE 'q'
52 #define IPS_PROTO_SOCKET 's'
53 #define IPS_PROTO_ACCEPT 'a'
54 #define IPS_PROTO_BIND 'b'
55 #define IPS_PROTO_LISTEN 'l'
56 #define IPS_PROTO_FCNTL 'f'
58 #define IPS_PROTO "/#ips#"
60 using namespace std;
62 int serial_write (char *data, unsigned len);
64 int fd, c, res;
65 struct termios oldtio, newtio;
67 bool connected = false;
68 bool nonblock = true;
70 hostent *host; // Vzdálený poèítaè;
71 sockaddr_in serverSock; // Vzdálený "konec potrubí"
72 int mySocket; // Soket
73 int port; // Èíslo portu
74 char buf[BUFSIZE]; // Pøijímací buffer
75 int size; // Poèet pøijatých a odeslaných bytù
76 fd_set set;
77 timeval tv;
79 struct sockaddr_un serv_addr;
81 sockaddr_in sockName; // "Jméno" portu
82 sockaddr_in clientInfo; // Klient, který se pøipojil
83 socklen_t addrlen; // Velikost adresy vzdáleného poèítaèe
85 int unixsock_init (char *path)
87 int servlen;
89 bzero ((char *) &serv_addr, sizeof(serv_addr));
91 serv_addr.sun_family = AF_UNIX;
92 strcpy (serv_addr.sun_path, path);
93 servlen = strlen (serv_addr.sun_path) + sizeof (serv_addr.sun_family);
95 if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {
96 puts ("socket () < 0 - unix domain socket cant be created !");
97 exit (0);
98 return 0;
101 if (connect (fd, (struct sockaddr *) &serv_addr, servlen) < 0) {
102 printf ("connect () < 0 - cant connect to socket '%s'\n", path);
103 exit (-1);
104 return -1;
107 printf ("unix domain socket - connected :P\n");
109 return 1;
112 int serial_init ()
115 Open modem device for reading and writing and not as controlling tty
116 because we don't want to get killed if linenoise sends CTRL-C.
118 fd = open (MODEMDEVICE, O_RDWR | O_NOCTTY);
120 if (fd < 0 )
121 perror(MODEMDEVICE); exit(-1);
123 tcgetattr (fd, &oldtio); /* save current serial port settings */
124 bzero (&newtio, sizeof(newtio)); /* clear struct for new port settings */
127 BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
128 CRTSCTS : output hardware flow control (only used if the cable has
129 all necessary lines. See sect. 7 of Serial-HOWTO)
130 CS8 : 8n1 (8bit,no parity,1 stopbit)
131 CLOCAL : local connection, no modem contol
132 CREAD : enable receiving characters
135 newtio.c_cflag = BAUDRATE | CS8 | /*CLOCAL | */CREAD;
138 IGNPAR : ignore bytes with parity errors
139 ICRNL : map CR to NL (otherwise a CR input on the other computer
140 will not terminate input)
141 otherwise make device raw (no other input processing)
143 // newtio.c_iflag = /*IGNPAR | ICRNL;*/
146 Raw output.
148 newtio.c_oflag = 0;
151 ICANON : enable canonical input
152 disable all echo functionality, and don't send signals to calling program
154 // newtio.c_lflag = ICANON;
157 initialize all control characters
158 default values can be found in /usr/include/termios.h, and are given
159 in the comments, but we don't need them here
161 newtio.c_cc[VINTR] = 0; /* Ctrl-c */
162 newtio.c_cc[VQUIT] = 0; /* Ctrl-\ */
163 newtio.c_cc[VERASE] = 0; /* del */
164 newtio.c_cc[VKILL] = 0; /* @ */
165 newtio.c_cc[VEOF] = 4; /* Ctrl-d */
166 newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
167 newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
168 newtio.c_cc[VSWTC] = 0; /* '\0' */
169 newtio.c_cc[VSTART] = 0; /* Ctrl-q */
170 newtio.c_cc[VSTOP] = 0; /* Ctrl-s */
171 newtio.c_cc[VSUSP] = 0; /* Ctrl-z */
172 newtio.c_cc[VEOL] = 0; /* '\0' */
173 newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */
174 newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */
175 newtio.c_cc[VWERASE] = 0; /* Ctrl-w */
176 newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */
177 newtio.c_cc[VEOL2] = 0; /* '\0' */
180 now clean the modem line and activate the settings for the port
183 tcflush(fd, TCIFLUSH);
184 tcsetattr(fd, TCSANOW,&newtio);
186 return 1;
189 void irs_proto_sendheader (int ret)
191 char num[4];
192 num[0] = (unsigned char) ret;
193 num[1] = (unsigned char) (ret >> 8);
194 num[2] = (unsigned char) (ret >> 16);
195 num[3] = (unsigned char) (ret >> 24);
197 serial_write (num, 4);
200 int ips_proto_parse (int sock, char *data, unsigned len)
202 if (strncmp (data, IPS_PROTO, 6)) {
203 // send
204 if (!len)
205 return -1;
207 if (!data)
208 return 0;
210 // Odeslání dat
211 int ret = send (sock, data, len, 0);
213 printf ("send (%d/%d): %s\n", ret, len, data);
215 return 1;
217 // printf ("dta: %s\n", data);
218 if (data[6] == IPS_PROTO_RECV) {
219 // recv
220 if (!len)
221 return -1;
223 char s[10];
224 int buf_len = 0;
226 sscanf (data, "%s %d", s, &buf_len);
228 if (buf_len <= 0) {
229 printf ("recv (): buf_len ! %d\n", buf_len);
230 irs_proto_sendheader (-1);
231 return -1;
234 char buf[buf_len+1];
235 memset (buf, 0, buf_len);
237 usleep (80); // prevent for fragmentation
239 int ret = recv (sock, buf, buf_len, 0);
241 // printf ("len: %d\n", len);
242 //if (ret == -1) //to vymaz pak -- test
243 // irs_proto_sendheader (0);
244 //else
246 irs_proto_sendheader (ret);
248 if (ret > 0) {
249 serial_write (buf, ret);
250 buf[ret] = '\0';
251 printf ("recv(%d): %d: %s\n", sock, ret, buf);
254 return 1;
257 if (data[6] == IPS_PROTO_ACCEPT) {
258 // Poznaèím si velikost struktury clientInfo.
259 // Pøedám to funkci accept.
260 addrlen = sizeof (clientInfo);
261 // Vyberu z fronty po¾adavek na spojení.
262 // "client" je nový soket spojující klienta se serverem.
263 int client = accept (sock, (sockaddr *) &clientInfo, &addrlen);
265 irs_proto_sendheader (client);
266 // TODO: dodelat vraceni clientInfo structury .. nebo spis jen ip ktera se pripojila
267 /*if (client) {
270 // printf ("accept (%d)\n", client);
272 return 1;
275 if (data[6] == IPS_PROTO_SOCKET) {
276 // Vytvoøíme soket
277 if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
279 cerr << "Nelze vytvoøit soket" << endl;
280 irs_proto_sendheader (sock);
281 return -1;
284 printf ("socket (%d)\n", sock);
286 irs_proto_sendheader (sock);
289 if (data[6] == IPS_PROTO_CONNECT) {
290 // connect
291 if (!len) {
292 irs_proto_sendheader (-1);
293 return 0;
296 char s[10], addr[32];
298 sscanf (data, "%s %s %d", s, addr, &port);
300 // Zjistíme info o vzdáleném poèítaèi
301 if ((host = gethostbyname (addr)) == NULL)
303 printf ("connect () -> wrong address: %s\n", addr);
304 irs_proto_sendheader (-1);
305 return -1;
308 // Zaplníme strukturu sockaddr_in
309 // 1) Rodina protokolù
310 serverSock.sin_family = AF_INET;
311 // 2) Èíslo portu, ke kterému se pøipojíme
312 serverSock.sin_port = htons(port);
313 // 3) Nastavení IP adresy, ke které se pøipojíme
314 memcpy(&(serverSock.sin_addr), host->h_addr, host->h_length);
315 // Pøipojení soketu
317 int ret = 0;
319 if ((ret = connect(sock, (sockaddr *)&serverSock, sizeof(serverSock))) == -1)
321 if (errno != EINPROGRESS)
323 printf ("ERROR -> Cant resolve - %s:%d\n", addr, port);
324 irs_proto_sendheader (ret);
325 return -1;
329 if (nonblock) {
330 FD_ZERO(&set);
331 FD_SET(sock, &set);
332 tv.tv_sec = 10;
333 tv.tv_usec = 0;
334 // Zjistím, jestli je ji¾ spojení navázáno. Jestli¾e ne, poèkáme a¾ bude navázáno.
335 if (select (sock + 1, NULL, &set, NULL, &tv) == 0)
337 printf ("ERROR -> Cant connect to %s:%d\n", addr, port);
338 irs_proto_sendheader (-1);
339 return -1;
343 connected = true;
345 //sleep (1);
346 irs_proto_sendheader (1);
348 printf ("Connected -> %s:%d\n", addr, port);
350 return 1;
353 if (data[6] == IPS_PROTO_BIND) {
355 unsigned yes = 1;
356 setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (yes));
358 char s[10], addr[32];
360 sscanf (data, "%s %s %d", s, addr, &port);
361 // Zaplníme strukturu sockaddr_in
362 // 1) Rodina protokolù
363 sockName.sin_family = AF_INET;
364 // 2) Èíslo portu, na kterém èekáme
365 sockName.sin_port = htons (port);
366 // 3) Nastavení IP adresy lokální sí»ové karty, pøes kterou je mo¾no se
367 // pøipojit. Nastavíme mo¾nost pøipojit se odkudkoliv.
368 sockName.sin_addr.s_addr = INADDR_ANY;
369 // pøiøadíme soketu jméno
371 int ret = 0;
372 if ((ret = bind (sock, (sockaddr *)&sockName, sizeof(sockName))) == -1)
374 cerr << "Problém s pojmenováním soketu." << endl;
375 irs_proto_sendheader (-1);
376 return -1;
379 printf ("bind () on port %d\n", port);
381 irs_proto_sendheader (ret);
383 return 1;
386 if (data[6] == IPS_PROTO_LISTEN) {
387 if (!len) {
388 irs_proto_sendheader (-1);
389 return -1;
392 char s[10];
393 int backlog = 0;
395 sscanf (data, "%s %d", s, &backlog);
397 int ret = listen (sock, backlog);
399 irs_proto_sendheader (ret);
401 return 1;
404 if (data[6] == IPS_PROTO_CLOSE) {
405 close (sock);
407 //printf ("close (%d)\n", sock);
408 return 1;
411 if (data[6] == IPS_PROTO_FCNTL) {
412 if (!len) {
413 irs_proto_sendheader (-1);
414 return 0;
417 char s[10];
418 int act = 0;
419 long flag = 0;
421 sscanf (data, "%s %d %ld", s, &act, &flag);
423 /* Set to nonblocking socket mode */
424 int ret = fcntl (sock, act, flag);
425 /*if (fcntl (sock, F_SETFL, oldFlag | O_NONBLOCK) == -1)
427 cerr << "> ERROR -> Problem with set socket mode" << endl;
428 irs_proto_sendheader (-1);
429 return -1;
432 //if (ret != -1)
433 // printf ("socket is nonblock (%d)\n", sock);
435 irs_proto_sendheader (ret);
437 return 1;
440 return 0;
443 int serial_read (char *data)
445 char buf[2];
447 int len = 0;
449 unsigned char num[5];
450 memset (num, 0, sizeof (num));
452 read (fd, (unsigned char *) &num[0], 1);
453 read (fd, (unsigned char *) &num[1], 1);
454 read (fd, (unsigned char *) &num[2], 1);
455 read (fd, (unsigned char *) &num[3], 1);
457 if (num[0] == '\0')
458 return 0;
460 len = num[0] | (num[1] << 8) | (num[2] << 16) | (num[3] << 24);
462 // printf ("##len: %d\n", len);
464 if (len >= 4096) {
465 printf ("oj ! len: %d\n", len);
466 return -1;
469 unsigned char fds[5];
470 memset (fds, 0, sizeof (fds));
472 read (fd, (unsigned char *) &fds[0], 1);
473 read (fd, (unsigned char *) &fds[1], 1);
474 read (fd, (unsigned char *) &fds[2], 1);
475 read (fd, (unsigned char *) &fds[3], 1);
477 //if (fds[0] == '\0')
478 // return 0;
480 int sock = fds[0] | (fds[1] << 8) | (fds[2] << 16) | (fds[3] << 24);
482 // printf ("##sock: %d\n", sock);
484 /* if (len < 0)
485 return len;*/
487 int x = 0;
489 while (x < len) {
490 read (fd, buf, 1);
492 data[x] = buf[0];
494 x ++;
497 // puts ("##huh");
499 data[len] = '\0';
501 // puts ("##lol");
503 return ips_proto_parse (sock, data, len);
506 int serial_write (char *data, unsigned len)
508 write (fd, data, len);
510 return 1;
513 int main (int argc, char *argv[])
515 puts ("-[ ZeX/OS ips2ip gateway ]-");
517 int mode = 1;
519 if (argc > 1 && argv[1][0] == 'p')
520 mode = 0;
522 if (mode)
523 serial_init ();
524 else
525 if (argc > 2)
526 unixsock_init (argv[2]);
527 else
528 unixsock_init ("/tmp/zexos");
530 char *test = (char *) calloc (sizeof (char), 4096);
532 while (1) {
533 memset (test, 0, 4095);
535 serial_read (test);
537 usleep (1);
540 free (test);
542 /* restore the old port settings */
543 if (mode)
544 tcsetattr (fd, TCSANOW, &oldtio);
546 puts ("ips2ip -> exit ()");
548 return 1;