fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

char-tcp: Telnet support

Introduces support for negotiating telnet options, primarily to switch
the telnet client into character mode.

Based on a patch by Julien Oster

Hampa Hug 73080edf 6cc9dc14

+288 -19
+11
doc/char-drivers.txt
··· 118 118 port=<port> 119 119 Set the TCP port number. 120 120 121 + telnet=[0|1] 122 + If true, will handle option negotiation for telnet 123 + binary and character mode. Useful when the serial 124 + line is a tty, to provide proper terminal emulation. 125 + 126 + telnetinit=[0|1] 127 + If this and "telnet" are true, initiate telnet option 128 + negotiations immediately after accepting a connection. 129 + Common telnet clients need this when connecting to 130 + a port other than 23. Defaults to true. 131 + 121 132 tios: 122 133 file=<filename> 123 134 The character device to connect to
+1
src/arch/ibmpc/pce-ibmpc.cfg.in
··· 406 406 #driver = "pty:symlink=com1" 407 407 driver = "stdio:file=serport1.out:flush=1" 408 408 #driver = "tios:file=/dev/ttyS0" 409 + #driver = "tcp:port=5555:telnet=1:telnetinit=1" 409 410 410 411 # Log all traffic to this file. This is for debugging. 411 412 #log = "serport1.log"
+1
src/arch/macplus/pce-macplus.cfg.in
··· 317 317 #driver = "pty:symlink=ser_a" 318 318 driver = "stdio:file=ser_a.out:flush=1" 319 319 #driver = "tios:file=/dev/ttyS0" 320 + #driver = "tcp:port=5555:telnet=1:telnetinit=1" 320 321 } 321 322 322 323 serial {
+270 -18
src/drivers/char/char-tcp.c
··· 5 5 /***************************************************************************** 6 6 * File name: src/drivers/char/char-tcp.c * 7 7 * Created: 2009-03-06 by Hampa Hug <hampa@hampa.ch> * 8 - * Copyright: (C) 2009-2010 Hampa Hug <hampa@hampa.ch> * 8 + * Copyright: (C) 2009-2012 Hampa Hug <hampa@hampa.ch> * 9 9 *****************************************************************************/ 10 10 11 11 /***************************************************************************** ··· 42 42 #endif 43 43 44 44 45 + #define TELNET_SE 240 46 + #define TELNET_NOP 241 47 + #define TELNET_GA 249 48 + #define TELNET_WILL 251 49 + #define TELNET_WONT 252 50 + #define TELNET_DO 253 51 + #define TELNET_DONT 254 52 + #define TELNET_IAC 255 53 + 54 + 55 + #define TELNET_OPT_BINARY 0 56 + #define TELNET_OPT_ECHO 1 57 + #define TELNET_OPT_SUPPRESS_GO_AHEAD 3 58 + 59 + 60 + enum { 61 + CHAR_TCP_DATA, 62 + CHAR_TCP_IAC, 63 + CHAR_TCP_WILL, 64 + CHAR_TCP_WONT, 65 + CHAR_TCP_DO, 66 + CHAR_TCP_DONT, 67 + CHAR_TCP_OPTION 68 + }; 69 + 70 + 45 71 static 46 72 unsigned tcp_get_state (int fd, int t) 47 73 { ··· 76 102 } 77 103 78 104 static 105 + int tcp_set_nodelay (int fd, int val) 106 + { 107 + #ifdef HAVE_LINUX_TCP_H 108 + val = (val != 0); 109 + 110 + if (setsockopt (fd, TCP, TCP_NODELAY, &val, sizeof (int))) { 111 + return (1); 112 + } 113 + 114 + return (0); 115 + #else 116 + return (1); 117 + #endif 118 + } 119 + 120 + static 121 + int tcp_set_reuseaddr (int fd, int val) 122 + { 123 + val = (val != 0); 124 + 125 + if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (int))) { 126 + return (1); 127 + } 128 + 129 + return (0); 130 + } 131 + 132 + static 79 133 int tcp_connect (const char *host, unsigned short port) 80 134 { 81 135 int fd; ··· 128 182 return (-1); 129 183 } 130 184 185 + tcp_set_reuseaddr (fd, 1); 186 + 131 187 if (bind (fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) { 132 188 close (fd); 133 189 return (-1); ··· 160 216 return (ret); 161 217 } 162 218 163 - int tcp_nodelay (int fd, int val) 164 - { 165 - #ifdef HAVE_LINUX_TCP_H 166 - val = (val != 0); 167 - 168 - if (setsockopt (fd, 6, TCP_NODELAY, &val, sizeof (int))) { 169 - return (1); 170 - } 171 - 172 - return (0); 173 - #else 174 - return (1); 175 - #endif 176 - } 177 - 178 219 static 179 220 char *tcp_host_resolve (const char *str) 180 221 { ··· 196 237 return (ret); 197 238 } 198 239 240 + 241 + #define telnet_do(drv, option) telnet_send_request(drv, option, TELNET_DO) 242 + #define telnet_dont(drv, option) telnet_send_request(drv, option, TELNET_DONT) 243 + #define telnet_will(drv, option) telnet_send_request(drv, option, TELNET_WILL) 244 + #define telnet_wont(drv, option) telnet_send_request(drv, option, TELNET_WONT) 245 + 246 + static 247 + void telnet_send_request (char_tcp_t *drv, unsigned char option, unsigned char verb) 248 + { 249 + unsigned char buf[3]; 250 + 251 + buf[0] = TELNET_IAC; 252 + buf[1] = verb; 253 + buf[2] = option; 254 + 255 + write(drv->fd, buf, 3); 256 + } 257 + 258 + static 259 + void telnet_process_request (char_tcp_t *drv, unsigned option) 260 + { 261 + unsigned st; 262 + 263 + st = drv->telnet_state; 264 + 265 + switch (option) { 266 + case TELNET_OPT_BINARY: 267 + if ((st == CHAR_TCP_DO) || (st == CHAR_TCP_DONT)) { 268 + /* We insist on being binary. */ 269 + telnet_will (drv, TELNET_OPT_BINARY); 270 + } 271 + else if ((st == CHAR_TCP_WILL) || (st == CHAR_TCP_WONT)) { 272 + /* We insist on being binary. */ 273 + telnet_do (drv, TELNET_OPT_BINARY); 274 + } 275 + return; 276 + 277 + case TELNET_OPT_ECHO: 278 + if (st == CHAR_TCP_WILL) { 279 + /* We refuse that the client performs echoing itself. */ 280 + telnet_dont (drv, TELNET_OPT_ECHO); 281 + } 282 + else if (st == CHAR_TCP_DONT) { 283 + /* We insist on echoing. */ 284 + telnet_will (drv, TELNET_OPT_ECHO); 285 + } 286 + return; 287 + 288 + case TELNET_OPT_SUPPRESS_GO_AHEAD: 289 + if (st == CHAR_TCP_DONT) { 290 + /* We will never send go-aheads. */ 291 + telnet_will (drv, TELNET_OPT_SUPPRESS_GO_AHEAD); 292 + } 293 + else if ((st == CHAR_TCP_WILL) || (st == CHAR_TCP_WONT)) { 294 + /* The client may or may not suppress go-aheads at its own 295 + * volition. */ 296 + telnet_send_request (drv, TELNET_OPT_SUPPRESS_GO_AHEAD, 297 + (st == CHAR_TCP_WILL) ? CHAR_TCP_DO : CHAR_TCP_DONT 298 + ); 299 + } 300 + return; 301 + 302 + default: 303 + /* unknown option, refuse it. */ 304 + telnet_send_request (drv, option, 305 + (st == CHAR_TCP_WILL) ? TELNET_DONT : TELNET_WONT 306 + ); 307 + } 308 + } 309 + 310 + static 311 + unsigned telnet_filter_input (char_tcp_t *drv, unsigned char *buf, unsigned cnt) 312 + { 313 + unsigned i, j; 314 + 315 + j = 0; 316 + 317 + for (i = 0; i < cnt; i++) { 318 + switch (drv->telnet_state) { 319 + case CHAR_TCP_DATA: 320 + if (buf[i] == TELNET_IAC) { 321 + drv->telnet_state = CHAR_TCP_IAC; 322 + } 323 + else { 324 + buf[j++] = buf[i]; 325 + } 326 + break; 327 + 328 + case CHAR_TCP_IAC: 329 + switch (buf[i]) { 330 + case TELNET_NOP: 331 + case TELNET_GA: 332 + drv->telnet_state = CHAR_TCP_DATA; 333 + break; 334 + 335 + case TELNET_WILL: 336 + drv->telnet_state = CHAR_TCP_WILL; 337 + break; 338 + 339 + case TELNET_WONT: 340 + drv->telnet_state = CHAR_TCP_WONT; 341 + break; 342 + 343 + case TELNET_DO: 344 + drv->telnet_state = CHAR_TCP_DO; 345 + break; 346 + 347 + case TELNET_DONT: 348 + drv->telnet_state = CHAR_TCP_DONT; 349 + break; 350 + 351 + case TELNET_IAC: 352 + buf[j++] = buf[i]; 353 + drv->telnet_state = CHAR_TCP_DATA; 354 + break; 355 + 356 + default: 357 + fprintf (stderr, "char-tcp: " 358 + "ignoring unknown/unexptected IAC %u\n", 359 + buf[i] 360 + ); 361 + drv->telnet_state = CHAR_TCP_DATA; 362 + break; 363 + } 364 + break; 365 + 366 + case CHAR_TCP_WILL: 367 + case CHAR_TCP_DO: 368 + case CHAR_TCP_WONT: 369 + case CHAR_TCP_DONT: 370 + telnet_process_request (drv, buf[i]); 371 + drv->telnet_state = CHAR_TCP_DATA; 372 + break; 373 + 374 + default: 375 + fprintf (stderr, 376 + "unknown char-tcp state %u? resetting to DATA.\n", 377 + drv->telnet_state 378 + ); 379 + drv->telnet_state = CHAR_TCP_DATA; 380 + } 381 + } 382 + 383 + return (j); 384 + } 385 + 386 + static 387 + ssize_t telnet_write (char_tcp_t *drv, const void *buf, unsigned cnt) 388 + { 389 + unsigned i; 390 + ssize_t r; 391 + const unsigned char *tmp; 392 + unsigned char iac[2]; 393 + 394 + if (cnt == 0) { 395 + return (0); 396 + } 397 + 398 + tmp = buf; 399 + 400 + i = 0; 401 + while ((i < cnt) && (tmp[i] != TELNET_IAC)) { 402 + i += 1; 403 + } 404 + 405 + if (i == 0) { 406 + iac[0] = TELNET_IAC; 407 + iac[1] = TELNET_IAC; 408 + 409 + r = write (drv->fd, iac, 2); 410 + 411 + if (r == 2) { 412 + r = 1; 413 + } 414 + } 415 + else { 416 + r = write (drv->fd, buf, i); 417 + } 418 + 419 + return (r); 420 + } 421 + 422 + 423 + static 424 + void chr_tcp_init_connection (char_tcp_t *drv) 425 + { 426 + tcp_set_nodelay (drv->fd, 1); 427 + 428 + drv->telnet_state = CHAR_TCP_DATA; 429 + 430 + if (drv->telnet && drv->telnetinit) { 431 + /* Instruct telnet client to switch to character mode. */ 432 + telnet_do (drv, TELNET_OPT_BINARY); 433 + telnet_will (drv, TELNET_OPT_ECHO); 434 + telnet_will (drv, TELNET_OPT_SUPPRESS_GO_AHEAD); 435 + } 436 + } 199 437 200 438 static 201 439 void chr_tcp_close (char_drv_t *cdrv) ··· 240 478 return (1); 241 479 } 242 480 243 - tcp_nodelay (drv->fd, 1); 481 + chr_tcp_init_connection (drv); 244 482 245 483 return (0); 246 484 } ··· 298 536 return (0); 299 537 } 300 538 539 + if (drv->telnet) { 540 + r = telnet_filter_input (drv, buf, r); 541 + } 542 + 301 543 return (r); 302 544 } 303 545 ··· 331 573 } 332 574 #endif 333 575 334 - r = write (drv->fd, buf, cnt); 576 + if (drv->telnet) { 577 + r = telnet_write (drv, buf, cnt); 578 + } 579 + else { 580 + r = write (drv->fd, buf, cnt); 581 + } 335 582 336 583 if (r <= 0) { 337 584 chr_tcp_shutdown (drv); ··· 359 606 drv->connect = drv_get_option_bool (name, "connect", 0); 360 607 drv->port = drv_get_option_uint (name, "port", 5555); 361 608 609 + drv->telnet = drv_get_option_bool (name, "telnet", 0); 610 + drv->telnetinit = drv_get_option_bool (name, "telnetinit", 1); 611 + 362 612 if (drv->host != NULL) { 363 613 str = tcp_host_resolve (drv->host); 364 614 ··· 377 627 if (drv->fd < 0) { 378 628 return (1); 379 629 } 630 + 631 + chr_tcp_init_connection (drv); 380 632 } 381 633 else { 382 634 drv->listen_fd = tcp_listen (NULL, drv->port, 1);
+5 -1
src/drivers/char/char-tcp.h
··· 5 5 /***************************************************************************** 6 6 * File name: src/drivers/char/char-tcp.h * 7 7 * Created: 2009-03-06 by Hampa Hug <hampa@hampa.ch> * 8 - * Copyright: (C) 2009 Hampa Hug <hampa@hampa.ch> * 8 + * Copyright: (C) 2009-2012 Hampa Hug <hampa@hampa.ch> * 9 9 *****************************************************************************/ 10 10 11 11 /***************************************************************************** ··· 33 33 char_drv_t cdrv; 34 34 35 35 int connect; 36 + int telnet; 37 + int telnetinit; 36 38 37 39 char *host; 38 40 unsigned port; 39 41 40 42 int listen_fd; 41 43 int fd; 44 + 45 + unsigned telnet_state; 42 46 } char_tcp_t; 43 47 44 48