diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-11 02:56:39 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-11 02:56:39 +0000 |
commit | 9f2f808b0dd531840b906e6dd09550a626c32bf1 (patch) | |
tree | 732344f72ee3d4f852cc2bddeb21c92e4d4f5ee7 | |
parent | e9b9a19ad30e004b3532105af417e43575ce7779 (diff) | |
download | busybox-w32-9f2f808b0dd531840b906e6dd09550a626c32bf1.tar.gz busybox-w32-9f2f808b0dd531840b906e6dd09550a626c32bf1.tar.bz2 busybox-w32-9f2f808b0dd531840b906e6dd09550a626c32bf1.zip |
telnetd: correctly output 0xff char. ~100 bytes.
telnet: fix some atrocious names and style. no code changes
-rw-r--r-- | networking/telnet.c | 232 | ||||
-rw-r--r-- | networking/telnetd.c | 58 |
2 files changed, 168 insertions, 122 deletions
diff --git a/networking/telnet.c b/networking/telnet.c index 5d7ecef3b..ba6f2fb83 100644 --- a/networking/telnet.c +++ b/networking/telnet.c | |||
@@ -93,7 +93,7 @@ static void will_charmode(void); | |||
93 | static void telopt(byte c); | 93 | static void telopt(byte c); |
94 | static int subneg(byte c); | 94 | static int subneg(byte c); |
95 | 95 | ||
96 | static void iacflush(void) | 96 | static void iac_flush(void) |
97 | { | 97 | { |
98 | write(netfd, G.iacbuf, G.iaclen); | 98 | write(netfd, G.iacbuf, G.iaclen); |
99 | G.iaclen = 0; | 99 | G.iaclen = 0; |
@@ -108,11 +108,11 @@ static void doexit(int ev) | |||
108 | exit(ev); | 108 | exit(ev); |
109 | } | 109 | } |
110 | 110 | ||
111 | static void conescape(void) | 111 | static void con_escape(void) |
112 | { | 112 | { |
113 | char b; | 113 | char b; |
114 | 114 | ||
115 | if (bb_got_signal) /* came from line mode... go raw */ | 115 | if (bb_got_signal) /* came from line mode... go raw */ |
116 | rawmode(); | 116 | rawmode(); |
117 | 117 | ||
118 | write_str(1, "\r\nConsole escape. Commands are:\r\n\n" | 118 | write_str(1, "\r\nConsole escape. Commands are:\r\n\n" |
@@ -128,13 +128,13 @@ static void conescape(void) | |||
128 | case 'l': | 128 | case 'l': |
129 | if (!bb_got_signal) { | 129 | if (!bb_got_signal) { |
130 | do_linemode(); | 130 | do_linemode(); |
131 | goto rrturn; | 131 | goto ret; |
132 | } | 132 | } |
133 | break; | 133 | break; |
134 | case 'c': | 134 | case 'c': |
135 | if (bb_got_signal) { | 135 | if (bb_got_signal) { |
136 | will_charmode(); | 136 | will_charmode(); |
137 | goto rrturn; | 137 | goto ret; |
138 | } | 138 | } |
139 | break; | 139 | break; |
140 | case 'z': | 140 | case 'z': |
@@ -150,13 +150,12 @@ static void conescape(void) | |||
150 | 150 | ||
151 | if (bb_got_signal) | 151 | if (bb_got_signal) |
152 | cookmode(); | 152 | cookmode(); |
153 | 153 | ret: | |
154 | rrturn: | ||
155 | bb_got_signal = 0; | 154 | bb_got_signal = 0; |
156 | 155 | ||
157 | } | 156 | } |
158 | 157 | ||
159 | static void handlenetoutput(int len) | 158 | static void handle_net_output(int len) |
160 | { | 159 | { |
161 | /* here we could do smart tricks how to handle 0xFF:s in output | 160 | /* 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 | 161 | * stream like writing twice every sequence of FF:s (thus doing |
@@ -169,19 +168,19 @@ static void handlenetoutput(int len) | |||
169 | * first - I cannot use programs like sz/rz | 168 | * first - I cannot use programs like sz/rz |
170 | * second - the 0x0D is sent as one character and if the next | 169 | * second - the 0x0D is sent as one character and if the next |
171 | * char is 0x0A then it's eaten by a server side. | 170 | * char is 0x0A then it's eaten by a server side. |
172 | * third - whay doy you have to make 'many write()s'? | 171 | * third - why do you have to make 'many write()s'? |
173 | * I don't understand. | 172 | * I don't understand. |
174 | * So I implemented it. It's realy useful for me. I hope that | 173 | * So I implemented it. It's really useful for me. I hope that |
175 | * others people will find it interesting too. | 174 | * other people will find it interesting too. |
176 | */ | 175 | */ |
177 | 176 | ||
178 | int i, j; | 177 | int i, j; |
179 | byte * p = (byte*)G.buf; | 178 | byte *p = (byte*)G.buf; |
180 | byte outbuf[4*DATABUFSIZE]; | 179 | byte outbuf[4*DATABUFSIZE]; |
181 | 180 | ||
182 | for (i = len, j = 0; i > 0; i--, p++) { | 181 | for (i = len, j = 0; i > 0; i--, p++) { |
183 | if (*p == 0x1d) { | 182 | if (*p == 0x1d) { |
184 | conescape(); | 183 | con_escape(); |
185 | return; | 184 | return; |
186 | } | 185 | } |
187 | outbuf[j++] = *p; | 186 | outbuf[j++] = *p; |
@@ -194,7 +193,7 @@ static void handlenetoutput(int len) | |||
194 | write(netfd, outbuf, j); | 193 | write(netfd, outbuf, j); |
195 | } | 194 | } |
196 | 195 | ||
197 | static void handlenetinput(int len) | 196 | static void handle_net_input(int len) |
198 | { | 197 | { |
199 | int i; | 198 | int i; |
200 | int cstart = 0; | 199 | int cstart = 0; |
@@ -207,51 +206,54 @@ static void handlenetinput(int len) | |||
207 | cstart = i; | 206 | cstart = i; |
208 | G.telstate = TS_IAC; | 207 | G.telstate = TS_IAC; |
209 | } | 208 | } |
210 | } else | 209 | continue; |
211 | switch (G.telstate) { | 210 | } |
212 | case TS_0: | 211 | switch (G.telstate) { |
213 | if (c == IAC) | 212 | case TS_0: |
214 | G.telstate = TS_IAC; | 213 | if (c == IAC) |
215 | else | 214 | G.telstate = TS_IAC; |
216 | G.buf[cstart++] = c; | 215 | else |
217 | break; | 216 | G.buf[cstart++] = c; |
217 | break; | ||
218 | 218 | ||
219 | case TS_IAC: | 219 | case TS_IAC: |
220 | if (c == IAC) { /* IAC IAC -> 0xFF */ | 220 | if (c == IAC) { /* IAC IAC -> 0xFF */ |
221 | G.buf[cstart++] = c; | 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; | 222 | G.telstate = TS_0; |
244 | break; | 223 | break; |
245 | case TS_SUB1: /* Subnegotiation */ | 224 | } |
246 | case TS_SUB2: /* Subnegotiation */ | 225 | /* else */ |
247 | if (subneg(c)) | 226 | switch (c) { |
248 | G.telstate = TS_0; | 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; | ||
249 | break; | 236 | break; |
237 | default: | ||
238 | G.telstate = TS_0; /* DATA MARK must be added later */ | ||
250 | } | 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 | } | 251 | } |
252 | if (G.telstate) { | 252 | if (G.telstate) { |
253 | if (G.iaclen) iacflush(); | 253 | if (G.iaclen) |
254 | if (G.telstate == TS_0) G.telstate = 0; | 254 | iac_flush(); |
255 | if (G.telstate == TS_0) | ||
256 | G.telstate = 0; | ||
255 | len = cstart; | 257 | len = cstart; |
256 | } | 258 | } |
257 | 259 | ||
@@ -259,87 +261,87 @@ static void handlenetinput(int len) | |||
259 | write(STDOUT_FILENO, G.buf, len); | 261 | write(STDOUT_FILENO, G.buf, len); |
260 | } | 262 | } |
261 | 263 | ||
262 | static void putiac(int c) | 264 | static void put_iac(int c) |
263 | { | 265 | { |
264 | G.iacbuf[G.iaclen++] = c; | 266 | G.iacbuf[G.iaclen++] = c; |
265 | } | 267 | } |
266 | 268 | ||
267 | static void putiac2(byte wwdd, byte c) | 269 | static void put_iac2(byte wwdd, byte c) |
268 | { | 270 | { |
269 | if (G.iaclen + 3 > IACBUFSIZE) | 271 | if (G.iaclen + 3 > IACBUFSIZE) |
270 | iacflush(); | 272 | iac_flush(); |
271 | 273 | ||
272 | putiac(IAC); | 274 | put_iac(IAC); |
273 | putiac(wwdd); | 275 | put_iac(wwdd); |
274 | putiac(c); | 276 | put_iac(c); |
275 | } | 277 | } |
276 | 278 | ||
277 | #if ENABLE_FEATURE_TELNET_TTYPE | 279 | #if ENABLE_FEATURE_TELNET_TTYPE |
278 | static void putiac_subopt(byte c, char *str) | 280 | static void put_iac_subopt(byte c, char *str) |
279 | { | 281 | { |
280 | int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) | 282 | int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) |
281 | 283 | ||
282 | if (G.iaclen + len > IACBUFSIZE) | 284 | if (G.iaclen + len > IACBUFSIZE) |
283 | iacflush(); | 285 | iac_flush(); |
284 | 286 | ||
285 | putiac(IAC); | 287 | put_iac(IAC); |
286 | putiac(SB); | 288 | put_iac(SB); |
287 | putiac(c); | 289 | put_iac(c); |
288 | putiac(0); | 290 | put_iac(0); |
289 | 291 | ||
290 | while (*str) | 292 | while (*str) |
291 | putiac(*str++); | 293 | put_iac(*str++); |
292 | 294 | ||
293 | putiac(IAC); | 295 | put_iac(IAC); |
294 | putiac(SE); | 296 | put_iac(SE); |
295 | } | 297 | } |
296 | #endif | 298 | #endif |
297 | 299 | ||
298 | #if ENABLE_FEATURE_TELNET_AUTOLOGIN | 300 | #if ENABLE_FEATURE_TELNET_AUTOLOGIN |
299 | static void putiac_subopt_autologin(void) | 301 | static void put_iac_subopt_autologin(void) |
300 | { | 302 | { |
301 | int len = strlen(G.autologin) + 6; // (2 + 1 + 1 + strlen + 2) | 303 | int len = strlen(G.autologin) + 6; // (2 + 1 + 1 + strlen + 2) |
302 | const char *user = "USER"; | 304 | const char *user = "USER"; |
303 | 305 | ||
304 | if (G.iaclen + len > IACBUFSIZE) | 306 | if (G.iaclen + len > IACBUFSIZE) |
305 | iacflush(); | 307 | iac_flush(); |
306 | 308 | ||
307 | putiac(IAC); | 309 | put_iac(IAC); |
308 | putiac(SB); | 310 | put_iac(SB); |
309 | putiac(TELOPT_NEW_ENVIRON); | 311 | put_iac(TELOPT_NEW_ENVIRON); |
310 | putiac(TELQUAL_IS); | 312 | put_iac(TELQUAL_IS); |
311 | putiac(NEW_ENV_VAR); | 313 | put_iac(NEW_ENV_VAR); |
312 | 314 | ||
313 | while (*user) | 315 | while (*user) |
314 | putiac(*user++); | 316 | put_iac(*user++); |
315 | 317 | ||
316 | putiac(NEW_ENV_VALUE); | 318 | put_iac(NEW_ENV_VALUE); |
317 | 319 | ||
318 | while (*G.autologin) | 320 | while (*G.autologin) |
319 | putiac(*G.autologin++); | 321 | put_iac(*G.autologin++); |
320 | 322 | ||
321 | putiac(IAC); | 323 | put_iac(IAC); |
322 | putiac(SE); | 324 | put_iac(SE); |
323 | } | 325 | } |
324 | #endif | 326 | #endif |
325 | 327 | ||
326 | #if ENABLE_FEATURE_AUTOWIDTH | 328 | #if ENABLE_FEATURE_AUTOWIDTH |
327 | static void putiac_naws(byte c, int x, int y) | 329 | static void put_iac_naws(byte c, int x, int y) |
328 | { | 330 | { |
329 | if (G.iaclen + 9 > IACBUFSIZE) | 331 | if (G.iaclen + 9 > IACBUFSIZE) |
330 | iacflush(); | 332 | iac_flush(); |
331 | 333 | ||
332 | putiac(IAC); | 334 | put_iac(IAC); |
333 | putiac(SB); | 335 | put_iac(SB); |
334 | putiac(c); | 336 | put_iac(c); |
335 | 337 | ||
336 | putiac((x >> 8) & 0xff); | 338 | put_iac((x >> 8) & 0xff); |
337 | putiac(x & 0xff); | 339 | put_iac(x & 0xff); |
338 | putiac((y >> 8) & 0xff); | 340 | put_iac((y >> 8) & 0xff); |
339 | putiac(y & 0xff); | 341 | put_iac(y & 0xff); |
340 | 342 | ||
341 | putiac(IAC); | 343 | put_iac(IAC); |
342 | putiac(SE); | 344 | put_iac(SE); |
343 | } | 345 | } |
344 | #endif | 346 | #endif |
345 | 347 | ||
@@ -368,9 +370,9 @@ static void will_charmode(void) | |||
368 | G.telflags |= (UF_ECHO | UF_SGA); | 370 | G.telflags |= (UF_ECHO | UF_SGA); |
369 | setConMode(); | 371 | setConMode(); |
370 | 372 | ||
371 | putiac2(DO, TELOPT_ECHO); | 373 | put_iac2(DO, TELOPT_ECHO); |
372 | putiac2(DO, TELOPT_SGA); | 374 | put_iac2(DO, TELOPT_SGA); |
373 | iacflush(); | 375 | iac_flush(); |
374 | } | 376 | } |
375 | 377 | ||
376 | static void do_linemode(void) | 378 | static void do_linemode(void) |
@@ -379,24 +381,24 @@ static void do_linemode(void) | |||
379 | G.telflags &= ~(UF_ECHO | UF_SGA); | 381 | G.telflags &= ~(UF_ECHO | UF_SGA); |
380 | setConMode(); | 382 | setConMode(); |
381 | 383 | ||
382 | putiac2(DONT, TELOPT_ECHO); | 384 | put_iac2(DONT, TELOPT_ECHO); |
383 | putiac2(DONT, TELOPT_SGA); | 385 | put_iac2(DONT, TELOPT_SGA); |
384 | iacflush(); | 386 | iac_flush(); |
385 | } | 387 | } |
386 | 388 | ||
387 | static void to_notsup(char c) | 389 | static void to_notsup(char c) |
388 | { | 390 | { |
389 | if (G.telwish == WILL) | 391 | if (G.telwish == WILL) |
390 | putiac2(DONT, c); | 392 | put_iac2(DONT, c); |
391 | else if (G.telwish == DO) | 393 | else if (G.telwish == DO) |
392 | putiac2(WONT, c); | 394 | put_iac2(WONT, c); |
393 | } | 395 | } |
394 | 396 | ||
395 | static void to_echo(void) | 397 | static void to_echo(void) |
396 | { | 398 | { |
397 | /* if server requests ECHO, don't agree */ | 399 | /* if server requests ECHO, don't agree */ |
398 | if (G.telwish == DO) { | 400 | if (G.telwish == DO) { |
399 | putiac2(WONT, TELOPT_ECHO); | 401 | put_iac2(WONT, TELOPT_ECHO); |
400 | return; | 402 | return; |
401 | } | 403 | } |
402 | if (G.telwish == DONT) | 404 | if (G.telwish == DONT) |
@@ -412,9 +414,9 @@ static void to_echo(void) | |||
412 | G.telflags ^= UF_ECHO; | 414 | G.telflags ^= UF_ECHO; |
413 | 415 | ||
414 | if (G.telflags & UF_ECHO) | 416 | if (G.telflags & UF_ECHO) |
415 | putiac2(DO, TELOPT_ECHO); | 417 | put_iac2(DO, TELOPT_ECHO); |
416 | else | 418 | else |
417 | putiac2(DONT, TELOPT_ECHO); | 419 | put_iac2(DONT, TELOPT_ECHO); |
418 | 420 | ||
419 | setConMode(); | 421 | setConMode(); |
420 | write_str(1, "\r\n"); /* sudden modec */ | 422 | write_str(1, "\r\n"); /* sudden modec */ |
@@ -432,9 +434,9 @@ static void to_sga(void) | |||
432 | 434 | ||
433 | G.telflags ^= UF_SGA; /* toggle */ | 435 | G.telflags ^= UF_SGA; /* toggle */ |
434 | if (G.telflags & UF_SGA) | 436 | if (G.telflags & UF_SGA) |
435 | putiac2(DO, TELOPT_SGA); | 437 | put_iac2(DO, TELOPT_SGA); |
436 | else | 438 | else |
437 | putiac2(DONT, TELOPT_SGA); | 439 | put_iac2(DONT, TELOPT_SGA); |
438 | } | 440 | } |
439 | 441 | ||
440 | #if ENABLE_FEATURE_TELNET_TTYPE | 442 | #if ENABLE_FEATURE_TELNET_TTYPE |
@@ -443,9 +445,9 @@ static void to_ttype(void) | |||
443 | /* Tell server we will (or won't) do TTYPE */ | 445 | /* Tell server we will (or won't) do TTYPE */ |
444 | 446 | ||
445 | if (G.ttype) | 447 | if (G.ttype) |
446 | putiac2(WILL, TELOPT_TTYPE); | 448 | put_iac2(WILL, TELOPT_TTYPE); |
447 | else | 449 | else |
448 | putiac2(WONT, TELOPT_TTYPE); | 450 | put_iac2(WONT, TELOPT_TTYPE); |
449 | } | 451 | } |
450 | #endif | 452 | #endif |
451 | 453 | ||
@@ -455,9 +457,9 @@ static void to_new_environ(void) | |||
455 | /* Tell server we will (or will not) do AUTOLOGIN */ | 457 | /* Tell server we will (or will not) do AUTOLOGIN */ |
456 | 458 | ||
457 | if (G.autologin) | 459 | if (G.autologin) |
458 | putiac2(WILL, TELOPT_NEW_ENVIRON); | 460 | put_iac2(WILL, TELOPT_NEW_ENVIRON); |
459 | else | 461 | else |
460 | putiac2(WONT, TELOPT_NEW_ENVIRON); | 462 | put_iac2(WONT, TELOPT_NEW_ENVIRON); |
461 | } | 463 | } |
462 | #endif | 464 | #endif |
463 | 465 | ||
@@ -465,7 +467,7 @@ static void to_new_environ(void) | |||
465 | static void to_naws(void) | 467 | static void to_naws(void) |
466 | { | 468 | { |
467 | /* Tell server we will do NAWS */ | 469 | /* Tell server we will do NAWS */ |
468 | putiac2(WILL, TELOPT_NAWS); | 470 | put_iac2(WILL, TELOPT_NAWS); |
469 | } | 471 | } |
470 | #endif | 472 | #endif |
471 | 473 | ||
@@ -487,7 +489,7 @@ static void telopt(byte c) | |||
487 | #if ENABLE_FEATURE_AUTOWIDTH | 489 | #if ENABLE_FEATURE_AUTOWIDTH |
488 | case TELOPT_NAWS: | 490 | case TELOPT_NAWS: |
489 | to_naws(); | 491 | to_naws(); |
490 | putiac_naws(c, G.win_width, G.win_height); | 492 | put_iac_naws(c, G.win_width, G.win_height); |
491 | break; | 493 | break; |
492 | #endif | 494 | #endif |
493 | default: | 495 | default: |
@@ -506,12 +508,12 @@ static int subneg(byte c) | |||
506 | #if ENABLE_FEATURE_TELNET_TTYPE | 508 | #if ENABLE_FEATURE_TELNET_TTYPE |
507 | else | 509 | else |
508 | if (c == TELOPT_TTYPE) | 510 | if (c == TELOPT_TTYPE) |
509 | putiac_subopt(TELOPT_TTYPE, G.ttype); | 511 | put_iac_subopt(TELOPT_TTYPE, G.ttype); |
510 | #endif | 512 | #endif |
511 | #if ENABLE_FEATURE_TELNET_AUTOLOGIN | 513 | #if ENABLE_FEATURE_TELNET_AUTOLOGIN |
512 | else | 514 | else |
513 | if (c == TELOPT_NEW_ENVIRON) | 515 | if (c == TELOPT_NEW_ENVIRON) |
514 | putiac_subopt_autologin(); | 516 | put_iac_subopt_autologin(); |
515 | #endif | 517 | #endif |
516 | break; | 518 | break; |
517 | case TS_SUB2: | 519 | case TS_SUB2: |
@@ -611,7 +613,7 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) | |||
611 | case -1: | 613 | case -1: |
612 | /* error, ignore and/or log something, bay go to loop */ | 614 | /* error, ignore and/or log something, bay go to loop */ |
613 | if (bb_got_signal) | 615 | if (bb_got_signal) |
614 | conescape(); | 616 | con_escape(); |
615 | else | 617 | else |
616 | sleep(1); | 618 | sleep(1); |
617 | break; | 619 | break; |
@@ -627,7 +629,7 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) | |||
627 | if (len <= 0) | 629 | if (len <= 0) |
628 | doexit(EXIT_SUCCESS); | 630 | doexit(EXIT_SUCCESS); |
629 | TRACE(0, ("Read con: %d\n", len)); | 631 | TRACE(0, ("Read con: %d\n", len)); |
630 | handlenetoutput(len); | 632 | handle_net_output(len); |
631 | } | 633 | } |
632 | 634 | ||
633 | #ifdef USE_POLL | 635 | #ifdef USE_POLL |
@@ -642,7 +644,7 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) | |||
642 | doexit(EXIT_FAILURE); | 644 | doexit(EXIT_FAILURE); |
643 | } | 645 | } |
644 | TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); | 646 | TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); |
645 | handlenetinput(len); | 647 | handle_net_input(len); |
646 | } | 648 | } |
647 | } | 649 | } |
648 | } /* while (1) */ | 650 | } /* while (1) */ |
diff --git a/networking/telnetd.c b/networking/telnetd.c index 46dfb318f..f04b32f9e 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -74,9 +74,6 @@ static const char *issuefile = "/etc/issue.net"; | |||
74 | past (bf + len) then that IAC will be left unprocessed and *processed | 74 | past (bf + len) then that IAC will be left unprocessed and *processed |
75 | will be less than len. | 75 | will be less than len. |
76 | 76 | ||
77 | FIXME - if we mean to send 0xFF to the terminal then it will be escaped, | ||
78 | what is the escape character? We aren't handling that situation here. | ||
79 | |||
80 | CR-LF ->'s CR mapping is also done here, for convenience. | 77 | CR-LF ->'s CR mapping is also done here, for convenience. |
81 | 78 | ||
82 | NB: may fail to remove iacs which wrap around buffer! | 79 | NB: may fail to remove iacs which wrap around buffer! |
@@ -159,6 +156,47 @@ remove_iacs(struct tsession *ts, int *pnum_totty) | |||
159 | return memmove(ptr - num_totty, ptr0, num_totty); | 156 | return memmove(ptr - num_totty, ptr0, num_totty); |
160 | } | 157 | } |
161 | 158 | ||
159 | /* | ||
160 | * Converting single 0xff into double on output | ||
161 | */ | ||
162 | static size_t iac_safe_write(int fd, const char *buf, size_t count) | ||
163 | { | ||
164 | const char *oxff; | ||
165 | size_t wr, rc, total; | ||
166 | |||
167 | total = 0; | ||
168 | while (1) { | ||
169 | if (count == 0) | ||
170 | return total; | ||
171 | if (*buf == (char)0xff) { | ||
172 | rc = safe_write(fd, "\xff\xff", 2); | ||
173 | if (rc != 2) | ||
174 | break; | ||
175 | buf++; | ||
176 | total++; | ||
177 | count--; | ||
178 | continue; | ||
179 | } | ||
180 | /* count != 0, *buf != 0xff */ | ||
181 | oxff = memchr(buf, 0xff, count); | ||
182 | wr = count; | ||
183 | if (oxff) | ||
184 | wr = oxff - buf; | ||
185 | rc = safe_write(fd, buf, wr); | ||
186 | if (rc != wr) | ||
187 | break; | ||
188 | buf += rc; | ||
189 | total += rc; | ||
190 | count -= rc; | ||
191 | } | ||
192 | /* here: rc - result of last short write */ | ||
193 | if ((ssize_t)rc < 0) { /* error? */ | ||
194 | if (total == 0) | ||
195 | return rc; | ||
196 | rc = 0; | ||
197 | } | ||
198 | return total + rc; | ||
199 | } | ||
162 | 200 | ||
163 | static struct tsession * | 201 | static struct tsession * |
164 | make_new_session( | 202 | make_new_session( |
@@ -212,9 +250,15 @@ make_new_session( | |||
212 | IAC, WILL, TELOPT_ECHO, | 250 | IAC, WILL, TELOPT_ECHO, |
213 | IAC, WILL, TELOPT_SGA | 251 | IAC, WILL, TELOPT_SGA |
214 | }; | 252 | }; |
215 | memcpy(TS_BUF2, iacs_to_send, sizeof(iacs_to_send)); | 253 | /* This confuses iac_safe_write(), it will try to duplicate |
216 | ts->rdidx2 = sizeof(iacs_to_send); | 254 | * each IAC... */ |
217 | ts->size2 = sizeof(iacs_to_send); | 255 | //memcpy(TS_BUF2, iacs_to_send, sizeof(iacs_to_send)); |
256 | //ts->rdidx2 = sizeof(iacs_to_send); | ||
257 | //ts->size2 = sizeof(iacs_to_send); | ||
258 | /* So just stuff it into TCP buffer! */ | ||
259 | safe_write(sock, iacs_to_send, sizeof(iacs_to_send)); | ||
260 | /*ts->rdidx2 = 0; - xzalloc did it! */ | ||
261 | /*ts->size2 = 0;*/ | ||
218 | } | 262 | } |
219 | 263 | ||
220 | fflush(NULL); /* flush all streams */ | 264 | fflush(NULL); /* flush all streams */ |
@@ -538,7 +582,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) | |||
538 | if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) { | 582 | if (/*ts->size2 &&*/ FD_ISSET(ts->sockfd_write, &wrfdset)) { |
539 | /* Write to socket from buffer 2. */ | 583 | /* Write to socket from buffer 2. */ |
540 | count = MIN(BUFSIZE - ts->wridx2, ts->size2); | 584 | count = MIN(BUFSIZE - ts->wridx2, ts->size2); |
541 | count = safe_write(ts->sockfd_write, TS_BUF2 + ts->wridx2, count); | 585 | count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2 + ts->wridx2), count); |
542 | if (count < 0) { | 586 | if (count < 0) { |
543 | if (errno == EAGAIN) | 587 | if (errno == EAGAIN) |
544 | goto skip2; | 588 | goto skip2; |