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