Annotation of /trunk/mkinitrd-magellan/busybox/networking/telnet.c
Parent Directory | Revision Log
Revision 532 -
(hide annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 12881 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 12881 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | niro | 532 | /* vi: set sw=4 ts=4: */ |
2 | /* | ||
3 | * telnet implementation for busybox | ||
4 | * | ||
5 | * Author: Tomi Ollila <too@iki.fi> | ||
6 | * Copyright (C) 1994-2000 by Tomi Ollila | ||
7 | * | ||
8 | * Created: Thu Apr 7 13:29:41 1994 too | ||
9 | * Last modified: Fri Jun 9 14:34:24 2000 too | ||
10 | * | ||
11 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. | ||
12 | * | ||
13 | * HISTORY | ||
14 | * Revision 3.1 1994/04/17 11:31:54 too | ||
15 | * initial revision | ||
16 | * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen <andersen@codepoet.org> | ||
17 | * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan | ||
18 | * <jam@ltsp.org> | ||
19 | * Modified 2004/02/11 to add ability to pass the USER variable to remote host | ||
20 | * by Fernando Silveira <swrh@gmx.net> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <termios.h> | ||
25 | #include <arpa/telnet.h> | ||
26 | #include <netinet/in.h> | ||
27 | #include "busybox.h" | ||
28 | |||
29 | #ifdef DOTRACE | ||
30 | #include <arpa/inet.h> /* for inet_ntoa()... */ | ||
31 | #define TRACE(x, y) do { if (x) printf y; } while (0) | ||
32 | #else | ||
33 | #define TRACE(x, y) | ||
34 | #endif | ||
35 | |||
36 | #define DATABUFSIZE 128 | ||
37 | #define IACBUFSIZE 128 | ||
38 | |||
39 | enum { | ||
40 | CHM_TRY = 0, | ||
41 | CHM_ON = 1, | ||
42 | CHM_OFF = 2, | ||
43 | |||
44 | UF_ECHO = 0x01, | ||
45 | UF_SGA = 0x02, | ||
46 | |||
47 | TS_0 = 1, | ||
48 | TS_IAC = 2, | ||
49 | TS_OPT = 3, | ||
50 | TS_SUB1 = 4, | ||
51 | TS_SUB2 = 5, | ||
52 | }; | ||
53 | |||
54 | #define WriteCS(fd, str) write(fd, str, sizeof str -1) | ||
55 | |||
56 | typedef unsigned char byte; | ||
57 | |||
58 | /* use globals to reduce size ??? */ /* test this hypothesis later */ | ||
59 | static struct Globalvars { | ||
60 | int netfd; /* console fd:s are 0 and 1 (and 2) */ | ||
61 | /* same buffer used both for network and console read/write */ | ||
62 | char buf[DATABUFSIZE]; /* allocating so static size is smaller */ | ||
63 | byte telstate; /* telnet negotiation state from network input */ | ||
64 | byte telwish; /* DO, DONT, WILL, WONT */ | ||
65 | byte charmode; | ||
66 | byte telflags; | ||
67 | byte gotsig; | ||
68 | byte do_termios; | ||
69 | /* buffer to handle telnet negotiations */ | ||
70 | char iacbuf[IACBUFSIZE]; | ||
71 | short iaclen; /* could even use byte */ | ||
72 | struct termios termios_def; | ||
73 | struct termios termios_raw; | ||
74 | } G; | ||
75 | |||
76 | #define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */ | ||
77 | |||
78 | #ifdef USE_GLOBALVAR_PTR | ||
79 | struct Globalvars * Gptr; | ||
80 | #define G (*Gptr) | ||
81 | #endif | ||
82 | |||
83 | static void iacflush(void) | ||
84 | { | ||
85 | write(G.netfd, G.iacbuf, G.iaclen); | ||
86 | G.iaclen = 0; | ||
87 | } | ||
88 | |||
89 | /* Function prototypes */ | ||
90 | static void rawmode(void); | ||
91 | static void cookmode(void); | ||
92 | static void do_linemode(void); | ||
93 | static void will_charmode(void); | ||
94 | static void telopt(byte c); | ||
95 | static int subneg(byte c); | ||
96 | |||
97 | /* Some globals */ | ||
98 | static const int one = 1; | ||
99 | |||
100 | #ifdef CONFIG_FEATURE_TELNET_TTYPE | ||
101 | static char *ttype; | ||
102 | #endif | ||
103 | |||
104 | #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN | ||
105 | static const char *autologin; | ||
106 | #endif | ||
107 | |||
108 | #ifdef CONFIG_FEATURE_AUTOWIDTH | ||
109 | static int win_width, win_height; | ||
110 | #endif | ||
111 | |||
112 | static void doexit(int ev) | ||
113 | { | ||
114 | cookmode(); | ||
115 | exit(ev); | ||
116 | } | ||
117 | |||
118 | static void conescape(void) | ||
119 | { | ||
120 | char b; | ||
121 | |||
122 | if (G.gotsig) /* came from line mode... go raw */ | ||
123 | rawmode(); | ||
124 | |||
125 | WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n" | ||
126 | " l go to line mode\r\n" | ||
127 | " c go to character mode\r\n" | ||
128 | " z suspend telnet\r\n" | ||
129 | " e exit telnet\r\n"); | ||
130 | |||
131 | if (read(0, &b, 1) <= 0) | ||
132 | doexit(1); | ||
133 | |||
134 | switch (b) | ||
135 | { | ||
136 | case 'l': | ||
137 | if (!G.gotsig) | ||
138 | { | ||
139 | do_linemode(); | ||
140 | goto rrturn; | ||
141 | } | ||
142 | break; | ||
143 | case 'c': | ||
144 | if (G.gotsig) | ||
145 | { | ||
146 | will_charmode(); | ||
147 | goto rrturn; | ||
148 | } | ||
149 | break; | ||
150 | case 'z': | ||
151 | cookmode(); | ||
152 | kill(0, SIGTSTP); | ||
153 | rawmode(); | ||
154 | break; | ||
155 | case 'e': | ||
156 | doexit(0); | ||
157 | } | ||
158 | |||
159 | WriteCS(1, "continuing...\r\n"); | ||
160 | |||
161 | if (G.gotsig) | ||
162 | cookmode(); | ||
163 | |||
164 | rrturn: | ||
165 | G.gotsig = 0; | ||
166 | |||
167 | } | ||
168 | static void handlenetoutput(int len) | ||
169 | { | ||
170 | /* here we could do smart tricks how to handle 0xFF:s in output | ||
171 | * stream like writing twice every sequence of FF:s (thus doing | ||
172 | * many write()s. But I think interactive telnet application does | ||
173 | * not need to be 100% 8-bit clean, so changing every 0xff:s to | ||
174 | * 0x7f:s | ||
175 | * | ||
176 | * 2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com) | ||
177 | * I don't agree. | ||
178 | * first - I cannot use programs like sz/rz | ||
179 | * second - the 0x0D is sent as one character and if the next | ||
180 | * char is 0x0A then it's eaten by a server side. | ||
181 | * third - whay doy you have to make 'many write()s'? | ||
182 | * I don't understand. | ||
183 | * So I implemented it. It's realy useful for me. I hope that | ||
184 | * others people will find it interesting to. | ||
185 | */ | ||
186 | |||
187 | int i, j; | ||
188 | byte * p = (byte*)G.buf; | ||
189 | byte outbuf[4*DATABUFSIZE]; | ||
190 | |||
191 | for (i = len, j = 0; i > 0; i--, p++) | ||
192 | { | ||
193 | if (*p == 0x1d) | ||
194 | { | ||
195 | conescape(); | ||
196 | return; | ||
197 | } | ||
198 | outbuf[j++] = *p; | ||
199 | if (*p == 0xff) | ||
200 | outbuf[j++] = 0xff; | ||
201 | else if (*p == 0x0d) | ||
202 | outbuf[j++] = 0x00; | ||
203 | } | ||
204 | if (j > 0 ) | ||
205 | write(G.netfd, outbuf, j); | ||
206 | } | ||
207 | |||
208 | |||
209 | static void handlenetinput(int len) | ||
210 | { | ||
211 | int i; | ||
212 | int cstart = 0; | ||
213 | |||
214 | for (i = 0; i < len; i++) | ||
215 | { | ||
216 | byte c = G.buf[i]; | ||
217 | |||
218 | if (G.telstate == 0) /* most of the time state == 0 */ | ||
219 | { | ||
220 | if (c == IAC) | ||
221 | { | ||
222 | cstart = i; | ||
223 | G.telstate = TS_IAC; | ||
224 | } | ||
225 | } | ||
226 | else | ||
227 | switch (G.telstate) | ||
228 | { | ||
229 | case TS_0: | ||
230 | if (c == IAC) | ||
231 | G.telstate = TS_IAC; | ||
232 | else | ||
233 | G.buf[cstart++] = c; | ||
234 | break; | ||
235 | |||
236 | case TS_IAC: | ||
237 | if (c == IAC) /* IAC IAC -> 0xFF */ | ||
238 | { | ||
239 | G.buf[cstart++] = c; | ||
240 | G.telstate = TS_0; | ||
241 | break; | ||
242 | } | ||
243 | /* else */ | ||
244 | switch (c) | ||
245 | { | ||
246 | case SB: | ||
247 | G.telstate = TS_SUB1; | ||
248 | break; | ||
249 | case DO: | ||
250 | case DONT: | ||
251 | case WILL: | ||
252 | case WONT: | ||
253 | G.telwish = c; | ||
254 | G.telstate = TS_OPT; | ||
255 | break; | ||
256 | default: | ||
257 | G.telstate = TS_0; /* DATA MARK must be added later */ | ||
258 | } | ||
259 | break; | ||
260 | case TS_OPT: /* WILL, WONT, DO, DONT */ | ||
261 | telopt(c); | ||
262 | G.telstate = TS_0; | ||
263 | break; | ||
264 | case TS_SUB1: /* Subnegotiation */ | ||
265 | case TS_SUB2: /* Subnegotiation */ | ||
266 | if (subneg(c)) | ||
267 | G.telstate = TS_0; | ||
268 | break; | ||
269 | } | ||
270 | } | ||
271 | if (G.telstate) | ||
272 | { | ||
273 | if (G.iaclen) iacflush(); | ||
274 | if (G.telstate == TS_0) G.telstate = 0; | ||
275 | |||
276 | len = cstart; | ||
277 | } | ||
278 | |||
279 | if (len) | ||
280 | write(1, G.buf, len); | ||
281 | } | ||
282 | |||
283 | |||
284 | /* ******************************* */ | ||
285 | |||
286 | static void putiac(int c) | ||
287 | { | ||
288 | G.iacbuf[G.iaclen++] = c; | ||
289 | } | ||
290 | |||
291 | |||
292 | static void putiac2(byte wwdd, byte c) | ||
293 | { | ||
294 | if (G.iaclen + 3 > IACBUFSIZE) | ||
295 | iacflush(); | ||
296 | |||
297 | putiac(IAC); | ||
298 | putiac(wwdd); | ||
299 | putiac(c); | ||
300 | } | ||
301 | |||
302 | #ifdef CONFIG_FEATURE_TELNET_TTYPE | ||
303 | static void putiac_subopt(byte c, char *str) | ||
304 | { | ||
305 | int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) | ||
306 | |||
307 | if (G.iaclen + len > IACBUFSIZE) | ||
308 | iacflush(); | ||
309 | |||
310 | putiac(IAC); | ||
311 | putiac(SB); | ||
312 | putiac(c); | ||
313 | putiac(0); | ||
314 | |||
315 | while (*str) | ||
316 | putiac(*str++); | ||
317 | |||
318 | putiac(IAC); | ||
319 | putiac(SE); | ||
320 | } | ||
321 | #endif | ||
322 | |||
323 | #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN | ||
324 | static void putiac_subopt_autologin(void) | ||
325 | { | ||
326 | int len = strlen(autologin) + 6; // (2 + 1 + 1 + strlen + 2) | ||
327 | char *user = "USER"; | ||
328 | |||
329 | if (G.iaclen + len > IACBUFSIZE) | ||
330 | iacflush(); | ||
331 | |||
332 | putiac(IAC); | ||
333 | putiac(SB); | ||
334 | putiac(TELOPT_NEW_ENVIRON); | ||
335 | putiac(TELQUAL_IS); | ||
336 | putiac(NEW_ENV_VAR); | ||
337 | |||
338 | while (*user) | ||
339 | putiac(*user++); | ||
340 | |||
341 | putiac(NEW_ENV_VALUE); | ||
342 | |||
343 | while (*autologin) | ||
344 | putiac(*autologin++); | ||
345 | |||
346 | putiac(IAC); | ||
347 | putiac(SE); | ||
348 | } | ||
349 | #endif | ||
350 | |||
351 | #ifdef CONFIG_FEATURE_AUTOWIDTH | ||
352 | static void putiac_naws(byte c, int x, int y) | ||
353 | { | ||
354 | if (G.iaclen + 9 > IACBUFSIZE) | ||
355 | iacflush(); | ||
356 | |||
357 | putiac(IAC); | ||
358 | putiac(SB); | ||
359 | putiac(c); | ||
360 | |||
361 | putiac((x >> 8) & 0xff); | ||
362 | putiac(x & 0xff); | ||
363 | putiac((y >> 8) & 0xff); | ||
364 | putiac(y & 0xff); | ||
365 | |||
366 | putiac(IAC); | ||
367 | putiac(SE); | ||
368 | } | ||
369 | #endif | ||
370 | |||
371 | /* void putiacstring (subneg strings) */ | ||
372 | |||
373 | /* ******************************* */ | ||
374 | |||
375 | static char const escapecharis[] = "\r\nEscape character is "; | ||
376 | |||
377 | static void setConMode(void) | ||
378 | { | ||
379 | if (G.telflags & UF_ECHO) | ||
380 | { | ||
381 | if (G.charmode == CHM_TRY) { | ||
382 | G.charmode = CHM_ON; | ||
383 | printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis); | ||
384 | rawmode(); | ||
385 | } | ||
386 | } | ||
387 | else | ||
388 | { | ||
389 | if (G.charmode != CHM_OFF) { | ||
390 | G.charmode = CHM_OFF; | ||
391 | printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis); | ||
392 | cookmode(); | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | |||
397 | /* ******************************* */ | ||
398 | |||
399 | static void will_charmode(void) | ||
400 | { | ||
401 | G.charmode = CHM_TRY; | ||
402 | G.telflags |= (UF_ECHO | UF_SGA); | ||
403 | setConMode(); | ||
404 | |||
405 | putiac2(DO, TELOPT_ECHO); | ||
406 | putiac2(DO, TELOPT_SGA); | ||
407 | iacflush(); | ||
408 | } | ||
409 | |||
410 | static void do_linemode(void) | ||
411 | { | ||
412 | G.charmode = CHM_TRY; | ||
413 | G.telflags &= ~(UF_ECHO | UF_SGA); | ||
414 | setConMode(); | ||
415 | |||
416 | putiac2(DONT, TELOPT_ECHO); | ||
417 | putiac2(DONT, TELOPT_SGA); | ||
418 | iacflush(); | ||
419 | } | ||
420 | |||
421 | /* ******************************* */ | ||
422 | |||
423 | static void to_notsup(char c) | ||
424 | { | ||
425 | if (G.telwish == WILL) putiac2(DONT, c); | ||
426 | else if (G.telwish == DO) putiac2(WONT, c); | ||
427 | } | ||
428 | |||
429 | static void to_echo(void) | ||
430 | { | ||
431 | /* if server requests ECHO, don't agree */ | ||
432 | if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; } | ||
433 | else if (G.telwish == DONT) return; | ||
434 | |||
435 | if (G.telflags & UF_ECHO) | ||
436 | { | ||
437 | if (G.telwish == WILL) | ||
438 | return; | ||
439 | } | ||
440 | else | ||
441 | if (G.telwish == WONT) | ||
442 | return; | ||
443 | |||
444 | if (G.charmode != CHM_OFF) | ||
445 | G.telflags ^= UF_ECHO; | ||
446 | |||
447 | if (G.telflags & UF_ECHO) | ||
448 | putiac2(DO, TELOPT_ECHO); | ||
449 | else | ||
450 | putiac2(DONT, TELOPT_ECHO); | ||
451 | |||
452 | setConMode(); | ||
453 | WriteCS(1, "\r\n"); /* sudden modec */ | ||
454 | } | ||
455 | |||
456 | static void to_sga(void) | ||
457 | { | ||
458 | /* daemon always sends will/wont, client do/dont */ | ||
459 | |||
460 | if (G.telflags & UF_SGA) | ||
461 | { | ||
462 | if (G.telwish == WILL) | ||
463 | return; | ||
464 | } | ||
465 | else | ||
466 | if (G.telwish == WONT) | ||
467 | return; | ||
468 | |||
469 | if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */ | ||
470 | putiac2(DO, TELOPT_SGA); | ||
471 | else | ||
472 | putiac2(DONT, TELOPT_SGA); | ||
473 | |||
474 | return; | ||
475 | } | ||
476 | |||
477 | #ifdef CONFIG_FEATURE_TELNET_TTYPE | ||
478 | static void to_ttype(void) | ||
479 | { | ||
480 | /* Tell server we will (or won't) do TTYPE */ | ||
481 | |||
482 | if(ttype) | ||
483 | putiac2(WILL, TELOPT_TTYPE); | ||
484 | else | ||
485 | putiac2(WONT, TELOPT_TTYPE); | ||
486 | |||
487 | return; | ||
488 | } | ||
489 | #endif | ||
490 | |||
491 | #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN | ||
492 | static void to_new_environ(void) | ||
493 | { | ||
494 | /* Tell server we will (or will not) do AUTOLOGIN */ | ||
495 | |||
496 | if (autologin) | ||
497 | putiac2(WILL, TELOPT_NEW_ENVIRON); | ||
498 | else | ||
499 | putiac2(WONT, TELOPT_NEW_ENVIRON); | ||
500 | |||
501 | return; | ||
502 | } | ||
503 | #endif | ||
504 | |||
505 | #ifdef CONFIG_FEATURE_AUTOWIDTH | ||
506 | static void to_naws(void) | ||
507 | { | ||
508 | /* Tell server we will do NAWS */ | ||
509 | putiac2(WILL, TELOPT_NAWS); | ||
510 | return; | ||
511 | } | ||
512 | #endif | ||
513 | |||
514 | static void telopt(byte c) | ||
515 | { | ||
516 | switch (c) | ||
517 | { | ||
518 | case TELOPT_ECHO: to_echo(); break; | ||
519 | case TELOPT_SGA: to_sga(); break; | ||
520 | #ifdef CONFIG_FEATURE_TELNET_TTYPE | ||
521 | case TELOPT_TTYPE: to_ttype();break; | ||
522 | #endif | ||
523 | #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN | ||
524 | case TELOPT_NEW_ENVIRON: to_new_environ(); break; | ||
525 | #endif | ||
526 | #ifdef CONFIG_FEATURE_AUTOWIDTH | ||
527 | case TELOPT_NAWS: to_naws(); | ||
528 | putiac_naws(c, win_width, win_height); | ||
529 | break; | ||
530 | #endif | ||
531 | default: to_notsup(c); | ||
532 | break; | ||
533 | } | ||
534 | } | ||
535 | |||
536 | |||
537 | /* ******************************* */ | ||
538 | |||
539 | /* subnegotiation -- ignore all (except TTYPE,NAWS) */ | ||
540 | |||
541 | static int subneg(byte c) | ||
542 | { | ||
543 | switch (G.telstate) | ||
544 | { | ||
545 | case TS_SUB1: | ||
546 | if (c == IAC) | ||
547 | G.telstate = TS_SUB2; | ||
548 | #ifdef CONFIG_FEATURE_TELNET_TTYPE | ||
549 | else | ||
550 | if (c == TELOPT_TTYPE) | ||
551 | putiac_subopt(TELOPT_TTYPE,ttype); | ||
552 | #endif | ||
553 | #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN | ||
554 | else | ||
555 | if (c == TELOPT_NEW_ENVIRON) | ||
556 | putiac_subopt_autologin(); | ||
557 | #endif | ||
558 | break; | ||
559 | case TS_SUB2: | ||
560 | if (c == SE) | ||
561 | return TRUE; | ||
562 | G.telstate = TS_SUB1; | ||
563 | /* break; */ | ||
564 | } | ||
565 | return FALSE; | ||
566 | } | ||
567 | |||
568 | /* ******************************* */ | ||
569 | |||
570 | static void fgotsig(int sig) | ||
571 | { | ||
572 | G.gotsig = sig; | ||
573 | } | ||
574 | |||
575 | |||
576 | static void rawmode(void) | ||
577 | { | ||
578 | if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_raw); | ||
579 | } | ||
580 | |||
581 | static void cookmode(void) | ||
582 | { | ||
583 | if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_def); | ||
584 | } | ||
585 | |||
586 | int telnet_main(int argc, char** argv) | ||
587 | { | ||
588 | char *host; | ||
589 | int port; | ||
590 | int len; | ||
591 | #ifdef USE_POLL | ||
592 | struct pollfd ufds[2]; | ||
593 | #else | ||
594 | fd_set readfds; | ||
595 | int maxfd; | ||
596 | #endif | ||
597 | |||
598 | #ifdef CONFIG_FEATURE_AUTOWIDTH | ||
599 | get_terminal_width_height(0, &win_width, &win_height); | ||
600 | #endif | ||
601 | |||
602 | #ifdef CONFIG_FEATURE_TELNET_TTYPE | ||
603 | ttype = getenv("TERM"); | ||
604 | #endif | ||
605 | |||
606 | /* memset(&G, 0, sizeof G); - already is */ | ||
607 | |||
608 | if (tcgetattr(0, &G.termios_def) >= 0) { | ||
609 | G.do_termios = 1; | ||
610 | G.termios_raw = G.termios_def; | ||
611 | cfmakeraw(&G.termios_raw); | ||
612 | } | ||
613 | |||
614 | if (argc < 2) | ||
615 | bb_show_usage(); | ||
616 | |||
617 | #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN | ||
618 | if (1 & getopt32(argc, argv, "al:", &autologin)) | ||
619 | autologin = getenv("USER"); | ||
620 | argv += optind; | ||
621 | #else | ||
622 | argv++; | ||
623 | #endif | ||
624 | if (!*argv) | ||
625 | bb_show_usage(); | ||
626 | host = *argv++; | ||
627 | port = bb_lookup_port(*argv ? *argv++ : "telnet", "tcp", 23); | ||
628 | if (*argv) /* extra params?? */ | ||
629 | bb_show_usage(); | ||
630 | |||
631 | G.netfd = create_and_connect_stream_or_die(host, port); | ||
632 | |||
633 | setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one); | ||
634 | |||
635 | signal(SIGINT, fgotsig); | ||
636 | |||
637 | #ifdef USE_POLL | ||
638 | ufds[0].fd = 0; ufds[1].fd = G.netfd; | ||
639 | ufds[0].events = ufds[1].events = POLLIN; | ||
640 | #else | ||
641 | FD_ZERO(&readfds); | ||
642 | FD_SET(0, &readfds); | ||
643 | FD_SET(G.netfd, &readfds); | ||
644 | maxfd = G.netfd + 1; | ||
645 | #endif | ||
646 | |||
647 | while (1) { | ||
648 | #ifndef USE_POLL | ||
649 | fd_set rfds = readfds; | ||
650 | |||
651 | switch (select(maxfd, &rfds, NULL, NULL, NULL)) | ||
652 | #else | ||
653 | switch (poll(ufds, 2, -1)) | ||
654 | #endif | ||
655 | { | ||
656 | case 0: | ||
657 | /* timeout */ | ||
658 | case -1: | ||
659 | /* error, ignore and/or log something, bay go to loop */ | ||
660 | if (G.gotsig) | ||
661 | conescape(); | ||
662 | else | ||
663 | sleep(1); | ||
664 | break; | ||
665 | default: | ||
666 | |||
667 | #ifdef USE_POLL | ||
668 | if (ufds[0].revents) /* well, should check POLLIN, but ... */ | ||
669 | #else | ||
670 | if (FD_ISSET(0, &rfds)) | ||
671 | #endif | ||
672 | { | ||
673 | len = read(0, G.buf, DATABUFSIZE); | ||
674 | |||
675 | if (len <= 0) | ||
676 | doexit(0); | ||
677 | |||
678 | TRACE(0, ("Read con: %d\n", len)); | ||
679 | |||
680 | handlenetoutput(len); | ||
681 | } | ||
682 | |||
683 | #ifdef USE_POLL | ||
684 | if (ufds[1].revents) /* well, should check POLLIN, but ... */ | ||
685 | #else | ||
686 | if (FD_ISSET(G.netfd, &rfds)) | ||
687 | #endif | ||
688 | { | ||
689 | len = read(G.netfd, G.buf, DATABUFSIZE); | ||
690 | |||
691 | if (len <= 0) { | ||
692 | WriteCS(1, "Connection closed by foreign host.\r\n"); | ||
693 | doexit(1); | ||
694 | } | ||
695 | TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len)); | ||
696 | |||
697 | handlenetinput(len); | ||
698 | } | ||
699 | } | ||
700 | } | ||
701 | } |