source: trunk/minix/commands/simple/slip.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 7.6 KB
Line 
1/* slip 1.1 - Serial line IP Author: Kees J. Bot
2 * 19 Jul 1997
3 */
4#define nil 0
5#include <sys/types.h>
6#include <stdarg.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <fcntl.h>
10#include <string.h>
11#include <errno.h>
12#include <sys/asynchio.h>
13
14#if __minix && !__minix_vmd
15#define HAS_ASYN 0 /* Standard Minix doesn't have async I/O. */
16#else
17#define HAS_ASYN 1 /* Everyone else does in some way. */
18#endif
19
20#if !HAS_ASYN
21#include <signal.h>
22#endif
23
24#define END 0300 /* End of packet. */
25#define ESC 0333 /* Byte stuffing escape. */
26#define ESC_END 0334 /* END -> ESC ESC_END -> END. */
27#define ESC_ESC 0335 /* ESC -> ESC ESC_ESC -> ESC. */
28
29#define PACKLEN 2048 /* Max datagram size. */
30#define SLIPLEN (1 + 2*PACKLEN + 1) /* Max serial size when all escaped. */
31
32/* Pathetic fprintf() clone to avoid dragging in the stdio library. */
33static int fprintf(int fd, const char *format, ...);
34#define stderr 2
35
36int main(int argc, char **argv)
37{
38 char *ps_device;
39 int ps_fd;
40 int doing[2], discard;
41 ssize_t r;
42#if !HAS_ASYN
43 pid_t other_pid;
44#endif
45 size_t ps_len[2], sl_len[2];
46 unsigned char *sl_end;
47 unsigned char ps_buf[2][PACKLEN];
48 unsigned char sl_buf[2][SLIPLEN];
49 asynchio_t asyn;
50
51 if (argc != 2) {
52 fprintf(stderr, "Usage: slip psip-device\n");
53 exit(1);
54 }
55 ps_device= argv[1];
56
57 if ((ps_fd= open(ps_device, O_RDWR)) < 0) {
58 fprintf(stderr, "slip: can't open %s: %s\n",
59 ps_device, strerror(errno));
60 exit(1);
61 }
62
63 doing[0]= 1; /* We're doing serial -> psip. */
64 discard= 0; /* No input error. */
65 sl_len[0]= 0; /* Nothing read from serial line yet. */
66 sl_end= nil; /* No END marker seen. */
67 ps_len[0]= 0; /* Nothing to write to pseudo IP device. */
68
69 doing[1]= 1; /* We're doing psip -> serial. */
70 sl_len[1]= 0; /* Nothing read from pseudo IP device yet. */
71 ps_len[1]= 0; /* Nothing to write to serial line. */
72
73#if !HAS_ASYN
74 /* Oops, standard Minix can't do asynchronous I/O. Fork and let the parent
75 * do serial -> psip, and the child do psip -> serial. (Note that we have
76 * to make sure that we're not reading and writing at the same time even
77 * for standard Minix. For Minix-vmd we do fill an input buffer while an
78 * output buffer is waiting to be drained to improve performance a bit.)
79 */
80 switch ((other_pid= fork())) {
81 case -1:
82 fprintf(stderr, "slip: can't fork: %s\n", strerror(errno));
83 exit(1);
84 case 0:
85 /* Child. */
86 doing[0]= 0; /* *Not* doing serial -> psip. */
87 other_pid= getppid();
88 break;
89 default:
90 /* Parent. */
91 doing[1]= 0; /* *Not* doing psip -> serial. */
92 }
93#endif
94
95 asyn_init(&asyn);
96
97 for (;;) {
98 if (doing[0]) {
99 /* If there is an END marker in the serial input then create
100 * an IP packet to be send to the TCP/IP task.
101 */
102 while (sl_end != nil && ps_len[0] == 0) {
103 unsigned char *sp= sl_buf[0];
104 unsigned char *pp= ps_buf[0];
105
106 while (sp < sl_end) {
107 int c= *sp++;
108
109 if (c == ESC) {
110 switch (*sp++) {
111 case ESC_ESC: /* ESC ESC_ESC -> ESC. */
112 c= ESC;
113 break;
114 case ESC_END: /* ESC ESC_END -> END. */
115 c= END;
116 break;
117 default:
118 /* Protocol error. */
119 discard= 1;
120 }
121 }
122 if (pp < ps_buf[0] + PACKLEN) {
123 *pp++ = c;
124 } else {
125 /* Packet too big, discard. */
126 discard= 1;
127 }
128 }
129 if (discard) {
130 discard= 0;
131 } else {
132 /* A new packet can be send to the TCP/IP server. */
133 ps_len[0]= (pp - ps_buf[0]);
134 }
135 /* Move what's beyond END to the front. */
136 sl_end++;
137 sl_len[0] -= (sl_end - sl_buf[0]);
138 memmove(sl_buf[0], sl_end, sl_len[0]);
139 sl_end= memchr(sl_buf[0], END, sl_len[0]);
140 }
141
142 /* Reading from serial input. */
143 if (sl_end == nil && (HAS_ASYN || ps_len[0] == 0)) {
144 r= asyn_read(&asyn, 0, sl_buf[0] + sl_len[0],
145 SLIPLEN - sl_len[0]);
146 if (r > 0) {
147 sl_end= memchr(sl_buf[0] + sl_len[0], END, r);
148 sl_len[0]+= r;
149 if (sl_end == nil && sl_len[0] == SLIPLEN) {
150 /* Packet is idiotically big and no END in sight. */
151 sl_len[0]= 0;
152 discard= 1;
153 }
154 } else
155 if (r == 0) {
156 fprintf(stderr, "slip: EOF on serial input\n");
157 break;
158 } else
159 if (errno != ASYN_INPROGRESS) {
160 fprintf(stderr, "slip: serial input error: %s\n",
161 strerror(errno));
162 break;
163 }
164 }
165
166 /* Writing to the psip device. */
167 if (ps_len[0] > 0) {
168 r= asyn_write(&asyn, ps_fd, ps_buf[0], ps_len[0]);
169 if (r == ps_len[0]) {
170 /* Packet written. */
171 ps_len[0]= 0;
172 } else
173 if (r >= 0) {
174 fprintf(stderr,
175 "slip: odd write to %s, tried %u, wrote %d\n",
176 ps_device, (unsigned) ps_len[0], (int) r);
177 break;
178 } else
179 if (errno != ASYN_INPROGRESS) {
180 fprintf(stderr, "slip: error writing %s: %s\n",
181 ps_device, strerror(errno));
182 break;
183 }
184 }
185 }
186
187 if (doing[1]) {
188 /* Transform an IP packet to a "byte stuffed" serial packet. */
189 if (ps_len[1] > 0 && sl_len[1] == 0) {
190 unsigned char *pp= ps_buf[1];
191 unsigned char *sp= sl_buf[1];
192
193 *sp++ = END;
194 while (ps_len[1] > 0) {
195 int c= *pp++;
196 ps_len[1]--;
197 switch (c) {
198 case ESC: /* ESC -> ESC ESC_ESC. */
199 *sp++ = ESC;
200 c= ESC_ESC;
201 break;
202 case END: /* END -> ESC ESC_END. */
203 *sp++ = ESC;
204 c= ESC_END;
205 break;
206 }
207 *sp++ = c;
208 }
209 *sp++ = END;
210 sl_len[1]= (sp - sl_buf[1]);
211 }
212
213 /* Reading from the psip device. */
214 if (ps_len[1] == 0 && (HAS_ASYN || sl_len[1] == 0)) {
215 r= asyn_read(&asyn, ps_fd, ps_buf[1], PACKLEN);
216 if (r > 0) {
217 /* One packet read. */
218 ps_len[1]= r;
219 } else
220 if (r == 0) {
221 fprintf(stderr, "slip: EOF on %s\n", ps_device);
222 break;
223 } else
224 if (errno != ASYN_INPROGRESS) {
225 fprintf(stderr, "slip: error reading %s: %s\n",
226 ps_device, strerror(errno));
227 break;
228 }
229 }
230
231 /* Writing to serial output. */
232 if (sl_len[1] > 0) {
233 r= asyn_write(&asyn, 1, sl_buf[1], sl_len[1]);
234 if (r > 0) {
235 if ((sl_len[1]-= r) > 0) {
236 memmove(sl_buf[1], sl_buf[1] + r, sl_len[1]);
237 }
238 } else
239 if (r == 0) {
240 fprintf(stderr, "slip: EOF on serial output\n");
241 break;
242 } else
243 if (errno != ASYN_INPROGRESS) {
244 fprintf(stderr, "slip: serial output error: %s\n",
245 strerror(errno));
246 break;
247 }
248 }
249 }
250
251 /* Wait for something to happen. */
252 if (asyn_wait(&asyn, 0, nil) < 0) {
253 fprintf(stderr,
254 "slip: error while waiting for I/O to happen: %s\n",
255 strerror(errno));
256 break;
257 }
258 }
259#if !HAS_ASYN
260 /* Tell my alter ego that the game is over. */
261 kill(other_pid, SIGKILL);
262#endif
263 return 1;
264}
265
266static int fprintf(int fd, const char *format, ...)
267/* Simple fprintf() to save a few bytes by not using the stdio library. */
268{
269 int len;
270 ssize_t r;
271 const char *fp0, *fp;
272 va_list ap;
273
274 len= 0;
275 fp= fp0= format;
276 va_start(ap, format);
277
278 while (*fp != 0) {
279 if (*fp == '%' && memchr("sdu", fp[1], 3) != nil) {
280 if (fp > fp0) {
281 if ((r= write(fd, fp0, (fp - fp0))) < 0) return -1;
282 len+= r;
283 }
284 fp++;
285 fp0= fp+1;
286
287 if (*fp == 's') {
288 char *s= va_arg(ap, char *);
289
290 if ((r= write(fd, s, strlen(s))) < 0) return -1;
291 len+= r;
292 } else {
293 int d;
294 unsigned u;
295 char a[3 * sizeof(u) + 2];
296 char *p;
297
298 if (*fp == 'd') {
299 u= d= va_arg(ap, int);
300 if (d < 0) u= -u;
301 } else {
302 u= va_arg(ap, unsigned);
303 d= 0;
304 }
305
306 p= a + sizeof(a);
307 *--p= 0;
308 do *--p= '0' + (u % 10); while ((u /= 10) > 0);
309
310 if (d < 0) *--p= '-';
311 if ((r= write(fd, p, (a + sizeof(a)) - p)) < 0) return -1;
312 len+= r;
313 }
314 }
315 fp++;
316 }
317 if (fp > fp0) {
318 if ((r= write(fd, fp0, (fp - fp0))) < 0) return -1;
319 len+= r;
320 }
321 va_end(ap);
322 return len;
323}
Note: See TracBrowser for help on using the repository browser.