added latency tool
[tridge/junkcode.git] / serialtcp.c
1 /*
2   listen on a TCP port. When a connection comes in, open a local character devices 
3   (such as a serial port) and send/recv data between the tcp socket and the serial
4   device
5
6   tridge@samba.org, March 2004
7 */
8
9 #define _GNU_SOURCE
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <signal.h>
15 #include <time.h>
16 #include <errno.h>
17 #include <sys/socket.h>
18 #include <netdb.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <termios.h>
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #include <arpa/inet.h>
27 #include <netinet/in.h>
28
29 static void set_nonblocking(int fd)
30 {
31         unsigned v = fcntl(fd, F_GETFL, 0);
32         fcntl(fd, F_SETFL, v | O_NONBLOCK);
33 }
34
35 /*
36   open a socket of the specified type, port and address for incoming data
37 */
38 static int open_socket_in(int port)
39 {
40         struct sockaddr_in sock;
41         int res;
42         int one=1;
43
44         memset(&sock,0,sizeof(sock));
45
46 #ifdef HAVE_SOCK_SIN_LEN
47         sock.sin_len = sizeof(sock);
48 #endif
49         sock.sin_port = htons(port);
50         sock.sin_family = AF_INET;
51
52         res = socket(AF_INET, SOCK_STREAM, 0);
53         if (res == -1) { 
54                 fprintf(stderr, "socket failed\n"); return -1; 
55                 return -1;
56         }
57
58         setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
59
60         if (bind(res, (struct sockaddr *)&sock, sizeof(sock)) < 0) { 
61                 return(-1); 
62         }
63
64         return res;
65 }
66
67 /* write to a file descriptor, making sure we get all the data out or
68  * die trying */
69 static void write_all(int fd, unsigned char *s, size_t n)
70 {
71         while (n) {
72                 int r;
73                 r = write(fd, s, n);
74                 if (r <= 0) {
75                         exit(1);
76                 }
77                 s += r;
78                 n -= r;
79         }
80 }
81
82 #define MAX(a,b) ((a)>(b)?(a):(b))
83
84 static void main_loop(int fd1, int fd2)
85 {
86         unsigned char buf[1024];
87
88         set_nonblocking(fd1);
89         set_nonblocking(fd2);
90
91         while (1) {
92                 fd_set fds;
93                 int ret;
94
95                 FD_ZERO(&fds);
96                 FD_SET(fd1, &fds);
97                 FD_SET(fd2, &fds);
98
99                 ret = select(MAX(fd1, fd2)+1, &fds, NULL, NULL, NULL);
100                 if (ret == -1 && errno == EINTR) continue;
101                 if (ret <= 0) break;
102
103                 if (FD_ISSET(fd1, &fds)) {
104                         int n = read(fd1, buf, sizeof(buf));
105                         if (n <= 0) break;
106                         write_all(fd2, buf, n);
107                 }
108
109                 if (FD_ISSET(fd2, &fds)) {
110                         int n = read(fd2, buf, sizeof(buf));
111                         if (n <= 0) break;
112                         write_all(fd1, buf, n);
113                 }
114         }       
115 }
116
117
118 static int open_serial(const char *device)
119 {
120         struct termios tty;
121         int fd;
122         char *cmd;
123
124         fd = open(device, O_RDWR);
125         if (fd == -1) {
126                 return -1;
127         }
128         
129         asprintf(&cmd, "stty 5:4:cbe:a30:3:1c:7f:15:4:0:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 < %s", device);
130         system(cmd);
131         free(cmd);
132
133         if (ioctl(fd,TCGETS,&tty) != 0) {
134                 close(fd);
135                 return -1;
136         }
137
138         tty.c_cflag &= ~CBAUD;
139         tty.c_cflag |= B19200;
140
141         if (ioctl(fd,TCSETS,&tty) != 0) {
142                 close(fd);
143                 return -1;
144         }
145
146         return fd;
147 }
148
149 int main(int argc, char *argv[])
150 {
151         int listen_port;
152         int sock_in;
153         int fd_out;
154         int listen_fd;
155         struct sockaddr addr;
156         int in_addrlen = sizeof(addr);
157         const char *device;
158
159         if (argc < 3) {
160                 printf("Usage: serialtcp <inport> <device>\n");
161                 exit(1);
162         }
163
164         listen_port = atoi(argv[1]);
165         device = argv[2];
166
167         signal(SIGCHLD, SIG_IGN);
168
169         listen_fd = open_socket_in(listen_port);
170
171         if (listen_fd == -1) {
172                 fprintf(stderr,"listen on port %d failed - %s\n", 
173                         listen_port, strerror(errno));
174                 exit(1);
175         }
176
177         if (listen(listen_fd, 5) == -1) {
178                 fprintf(stderr,"listen failed\n");
179                 exit(1);
180         }
181
182         while ((sock_in = accept(listen_fd,&addr,&in_addrlen)) != -1) {
183                 if (fork() == 0) {
184                         close(listen_fd);
185
186                         fd_out = open_serial(device);
187                         
188                         if (fd_out == -1) {
189                                 perror(device);
190                                 exit(1);
191                         }
192
193                         main_loop(sock_in, fd_out);
194                         exit(0);
195                 }
196
197                 close(sock_in);
198         }
199
200         return 0;
201 }