Commit 951f13516a50383cd462c9150e643cc9f9566267

Authored by bellard
1 parent 1f6e24e7

telnet protocol and more consistent syntax (Jason Wessel)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2030 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 191 additions and 82 deletions
qemu-doc.texi
@@ -525,43 +525,60 @@ Write output to filename. No character can be read. @@ -525,43 +525,60 @@ Write output to filename. No character can be read.
525 name pipe @var{filename} 525 name pipe @var{filename}
526 @item COMn 526 @item COMn
527 [Windows only] Use host serial port @var{n} 527 [Windows only] Use host serial port @var{n}
528 -@item udp:remote_port  
529 -UDP Net Console sent to locahost at remote_port  
530 -@item udp:remote_host:remote_port  
531 -UDP Net Console sent to remote_host at remote_port  
532 -@item udp:src_port:remote_host:remote_port  
533 -UDP Net Console sent from src_port to remote_host at the remote_port.  
534 -  
535 -The udp:* sub options are primary intended for netconsole. If you  
536 -just want a simple readonly console you can use @code{netcat} or  
537 -@code{nc}, by starting qemu with: @code{-serial udp:4555} and nc as:  
538 -@code{nc -u -l -p 4555}. Any time qemu writes something to that port  
539 -it will appear in the netconsole session. 528 +@item udp:[remote_host]:remote_port[@@[src_ip]:src_port]
  529 +This implements UDP Net Console. When @var{remote_host} or @var{src_ip} are not specified they default to @code{0.0.0.0}. When not using a specifed @var{src_port} a random port is automatically chosen.
  530 +
  531 +If you just want a simple readonly console you can use @code{netcat} or
  532 +@code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as:
  533 +@code{nc -u -l -p 4555}. Any time qemu writes something to that port it
  534 +will appear in the netconsole session.
540 535
541 If you plan to send characters back via netconsole or you want to stop 536 If you plan to send characters back via netconsole or you want to stop
542 and start qemu a lot of times, you should have qemu use the same 537 and start qemu a lot of times, you should have qemu use the same
543 source port each time by using something like @code{-serial 538 source port each time by using something like @code{-serial
544 -udp:4556:localhost:4555} to qemu. Another approach is to use a patched 539 +udp::4555@@:4556} to qemu. Another approach is to use a patched
545 version of netcat which can listen to a TCP port and send and receive 540 version of netcat which can listen to a TCP port and send and receive
546 characters via udp. If you have a patched version of netcat which 541 characters via udp. If you have a patched version of netcat which
547 activates telnet remote echo and single char transfer, then you can 542 activates telnet remote echo and single char transfer, then you can
548 use the following options to step up a netcat redirector to allow 543 use the following options to step up a netcat redirector to allow
549 telnet on port 5555 to access the qemu port. 544 telnet on port 5555 to access the qemu port.
550 @table @code 545 @table @code
551 -@item Qemu Options  
552 --serial udp:4556:localhost:4555  
553 -@item netcat options  
554 --u -P 4555 -L localhost:4556 -t -p 5555 -I -T 546 +@item Qemu Options:
  547 +-serial udp::4555@@:4556
  548 +@item netcat options:
  549 +-u -P 4555 -L 0.0.0.0:4556 -t -p 5555 -I -T
  550 +@item telnet options:
  551 +localhost 5555
  552 +@end table
  553 +
  554 +
  555 +@item tcp:[host]:port[,server][,nowait]
  556 +The TCP Net Console has two modes of operation. It can send the serial
  557 +I/O to a location or wait for a connection from a location. By default
  558 +the TCP Net Console is sent to @var{host} at the @var{port}. If you use
  559 +the @var{,server} option QEMU will wait for a client socket application
  560 +to connect to the port before continuing, unless the @code{,nowait}
  561 +option was specified. If @var{host} is omitted, 0.0.0.0 is assumed. Only
  562 +one TCP connection at a time is accepted. You can use @code{telnet} to
  563 +connect to the corresponding character device.
  564 +@table @code
  565 +@item Example to send tcp console to 192.168.0.2 port 4444
  566 +-serial tcp:192.168.0.2:4444
  567 +@item Example to listen and wait on port 4444 for connection
  568 +-serial tcp::4444,server
  569 +@item Example to not wait and listen on ip 192.168.0.100 port 4444
  570 +-serial tcp:192.168.0.100:4444,server,nowait
555 @end table 571 @end table
556 572
  573 +@item telnet:host:port[,server][,nowait]
  574 +The telnet protocol is used instead of raw tcp sockets. The options
  575 +work the same as if you had specified @code{-serial tcp}. The
  576 +difference is that the port acts like a telnet server or client using
  577 +telnet option negotiation. This will also allow you to send the
  578 +MAGIC_SYSRQ sequence if you use a telnet that supports sending the break
  579 +sequence. Typically in unix telnet you do it with Control-] and then
  580 +type "send break" followed by pressing the enter key.
557 581
558 -@item tcp:remote_host:remote_port  
559 -TCP Net Console sent to remote_host at the remote_port  
560 -@item tcpl:host:port  
561 -TCP Net Console: wait for connection on @var{host} on the local port  
562 -@var{port}. If host is omitted, 0.0.0.0 is assumed. Only one TCP  
563 -connection at a time is accepted. You can use @code{telnet} to connect  
564 -to the corresponding character device.  
565 @end table 582 @end table
566 583
567 @item -parallel dev 584 @item -parallel dev
@@ -2203,16 +2203,16 @@ static void udp_chr_add_read_handler(CharDriverState *chr, @@ -2203,16 +2203,16 @@ static void udp_chr_add_read_handler(CharDriverState *chr,
2203 } 2203 }
2204 2204
2205 int parse_host_port(struct sockaddr_in *saddr, const char *str); 2205 int parse_host_port(struct sockaddr_in *saddr, const char *str);
  2206 +int parse_host_src_port(struct sockaddr_in *haddr,
  2207 + struct sockaddr_in *saddr,
  2208 + const char *str);
2206 2209
2207 CharDriverState *qemu_chr_open_udp(const char *def) 2210 CharDriverState *qemu_chr_open_udp(const char *def)
2208 { 2211 {
2209 CharDriverState *chr = NULL; 2212 CharDriverState *chr = NULL;
2210 NetCharDriver *s = NULL; 2213 NetCharDriver *s = NULL;
2211 int fd = -1; 2214 int fd = -1;
2212 - int con_type;  
2213 - struct sockaddr_in addr;  
2214 - const char *p, *r;  
2215 - int port; 2215 + struct sockaddr_in saddr;
2216 2216
2217 chr = qemu_mallocz(sizeof(CharDriverState)); 2217 chr = qemu_mallocz(sizeof(CharDriverState));
2218 if (!chr) 2218 if (!chr)
@@ -2227,58 +2227,12 @@ CharDriverState *qemu_chr_open_udp(const char *def) @@ -2227,58 +2227,12 @@ CharDriverState *qemu_chr_open_udp(const char *def)
2227 goto return_err; 2227 goto return_err;
2228 } 2228 }
2229 2229
2230 - /* There are three types of port definitions  
2231 - * 1) udp:remote_port  
2232 - * Juse use 0.0.0.0 for the IP and send to remote  
2233 - * 2) udp:remote_host:port  
2234 - * Use a IP and send traffic to remote  
2235 - * 3) udp:local_port:remote_host:remote_port  
2236 - * Use local_port as the originator + #2  
2237 - */  
2238 - con_type = 0;  
2239 - p = def;  
2240 - while ((p = strchr(p, ':'))) {  
2241 - p++;  
2242 - con_type++;  
2243 - }  
2244 -  
2245 - p = def;  
2246 - memset(&addr,0,sizeof(addr));  
2247 - addr.sin_family = AF_INET;  
2248 - addr.sin_addr.s_addr = htonl(INADDR_ANY);  
2249 - s->daddr.sin_family = AF_INET;  
2250 - s->daddr.sin_addr.s_addr = htonl(INADDR_ANY);  
2251 -  
2252 - switch (con_type) {  
2253 - case 0:  
2254 - port = strtol(p, (char **)&r, 0);  
2255 - if (r == p) {  
2256 - fprintf(stderr, "Error parsing port number\n");  
2257 - goto return_err;  
2258 - }  
2259 - s->daddr.sin_port = htons((short)port);  
2260 - break;  
2261 - case 2:  
2262 - port = strtol(p, (char **)&r, 0);  
2263 - if (r == p) {  
2264 - fprintf(stderr, "Error parsing port number\n");  
2265 - goto return_err;  
2266 - }  
2267 - addr.sin_port = htons((short)port);  
2268 - p = r + 1;  
2269 - /* Fall through to case 1 now that we have the local port */  
2270 - case 1:  
2271 - if (parse_host_port(&s->daddr, p) < 0) {  
2272 - fprintf(stderr, "Error parsing host name and port\n");  
2273 - goto return_err;  
2274 - }  
2275 - break;  
2276 - default:  
2277 - fprintf(stderr, "Too many ':' characters\n");  
2278 - goto return_err; 2230 + if (parse_host_src_port(&s->daddr, &saddr, def) < 0) {
  2231 + printf("Could not parse: %s\n", def);
  2232 + goto return_err;
2279 } 2233 }
2280 2234
2281 - if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) 2235 + if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
2282 { 2236 {
2283 perror("bind"); 2237 perror("bind");
2284 goto return_err; 2238 goto return_err;
@@ -2312,6 +2266,7 @@ typedef struct { @@ -2312,6 +2266,7 @@ typedef struct {
2312 int fd, listen_fd; 2266 int fd, listen_fd;
2313 int connected; 2267 int connected;
2314 int max_size; 2268 int max_size;
  2269 + int do_telnetopt;
2315 } TCPCharDriver; 2270 } TCPCharDriver;
2316 2271
2317 static void tcp_chr_accept(void *opaque); 2272 static void tcp_chr_accept(void *opaque);
@@ -2337,6 +2292,56 @@ static int tcp_chr_read_poll(void *opaque) @@ -2337,6 +2292,56 @@ static int tcp_chr_read_poll(void *opaque)
2337 return s->max_size; 2292 return s->max_size;
2338 } 2293 }
2339 2294
  2295 +#define IAC 255
  2296 +#define IAC_BREAK 243
  2297 +static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
  2298 + TCPCharDriver *s,
  2299 + char *buf, int *size)
  2300 +{
  2301 + /* Handle any telnet client's basic IAC options to satisfy char by
  2302 + * char mode with no echo. All IAC options will be removed from
  2303 + * the buf and the do_telnetopt variable will be used to track the
  2304 + * state of the width of the IAC information.
  2305 + *
  2306 + * IAC commands come in sets of 3 bytes with the exception of the
  2307 + * "IAC BREAK" command and the double IAC.
  2308 + */
  2309 +
  2310 + int i;
  2311 + int j = 0;
  2312 +
  2313 + for (i = 0; i < *size; i++) {
  2314 + if (s->do_telnetopt > 1) {
  2315 + if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
  2316 + /* Double IAC means send an IAC */
  2317 + if (j != i)
  2318 + buf[j] = buf[i];
  2319 + j++;
  2320 + s->do_telnetopt = 1;
  2321 + } else {
  2322 + if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
  2323 + /* Handle IAC break commands by sending a serial break */
  2324 + chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK);
  2325 + s->do_telnetopt++;
  2326 + }
  2327 + s->do_telnetopt++;
  2328 + }
  2329 + if (s->do_telnetopt >= 4) {
  2330 + s->do_telnetopt = 1;
  2331 + }
  2332 + } else {
  2333 + if ((unsigned char)buf[i] == IAC) {
  2334 + s->do_telnetopt = 2;
  2335 + } else {
  2336 + if (j != i)
  2337 + buf[j] = buf[i];
  2338 + j++;
  2339 + }
  2340 + }
  2341 + }
  2342 + *size = j;
  2343 +}
  2344 +
2340 static void tcp_chr_read(void *opaque) 2345 static void tcp_chr_read(void *opaque)
2341 { 2346 {
2342 CharDriverState *chr = opaque; 2347 CharDriverState *chr = opaque;
@@ -2360,7 +2365,10 @@ static void tcp_chr_read(void *opaque) @@ -2360,7 +2365,10 @@ static void tcp_chr_read(void *opaque)
2360 closesocket(s->fd); 2365 closesocket(s->fd);
2361 s->fd = -1; 2366 s->fd = -1;
2362 } else if (size > 0) { 2367 } else if (size > 0) {
2363 - s->fd_read(s->fd_opaque, buf, size); 2368 + if (s->do_telnetopt)
  2369 + tcp_chr_process_IAC_bytes(chr, s, buf, &size);
  2370 + if (size > 0)
  2371 + s->fd_read(s->fd_opaque, buf, size);
2364 } 2372 }
2365 } 2373 }
2366 2374
@@ -2385,6 +2393,21 @@ static void tcp_chr_connect(void *opaque) @@ -2385,6 +2393,21 @@ static void tcp_chr_connect(void *opaque)
2385 tcp_chr_read, NULL, chr); 2393 tcp_chr_read, NULL, chr);
2386 } 2394 }
2387 2395
  2396 +#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
  2397 +static void tcp_chr_telnet_init(int fd)
  2398 +{
  2399 + char buf[3];
  2400 + /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
  2401 + IACSET(buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
  2402 + send(fd, (char *)buf, 3, 0);
  2403 + IACSET(buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
  2404 + send(fd, (char *)buf, 3, 0);
  2405 + IACSET(buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
  2406 + send(fd, (char *)buf, 3, 0);
  2407 + IACSET(buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
  2408 + send(fd, (char *)buf, 3, 0);
  2409 +}
  2410 +
2388 static void tcp_chr_accept(void *opaque) 2411 static void tcp_chr_accept(void *opaque)
2389 { 2412 {
2390 CharDriverState *chr = opaque; 2413 CharDriverState *chr = opaque;
@@ -2399,6 +2422,8 @@ static void tcp_chr_accept(void *opaque) @@ -2399,6 +2422,8 @@ static void tcp_chr_accept(void *opaque)
2399 if (fd < 0 && errno != EINTR) { 2422 if (fd < 0 && errno != EINTR) {
2400 return; 2423 return;
2401 } else if (fd >= 0) { 2424 } else if (fd >= 0) {
  2425 + if (s->do_telnetopt)
  2426 + tcp_chr_telnet_init(fd);
2402 break; 2427 break;
2403 } 2428 }
2404 } 2429 }
@@ -2419,16 +2444,34 @@ static void tcp_chr_close(CharDriverState *chr) @@ -2419,16 +2444,34 @@ static void tcp_chr_close(CharDriverState *chr)
2419 } 2444 }
2420 2445
2421 static CharDriverState *qemu_chr_open_tcp(const char *host_str, 2446 static CharDriverState *qemu_chr_open_tcp(const char *host_str,
2422 - int is_listen) 2447 + int is_telnet)
2423 { 2448 {
2424 CharDriverState *chr = NULL; 2449 CharDriverState *chr = NULL;
2425 TCPCharDriver *s = NULL; 2450 TCPCharDriver *s = NULL;
2426 int fd = -1, ret, err, val; 2451 int fd = -1, ret, err, val;
  2452 + int is_listen = 0;
  2453 + int is_waitconnect = 1;
  2454 + const char *ptr;
2427 struct sockaddr_in saddr; 2455 struct sockaddr_in saddr;
2428 2456
2429 if (parse_host_port(&saddr, host_str) < 0) 2457 if (parse_host_port(&saddr, host_str) < 0)
2430 goto fail; 2458 goto fail;
2431 2459
  2460 + ptr = host_str;
  2461 + while((ptr = strchr(ptr,','))) {
  2462 + ptr++;
  2463 + if (!strncmp(ptr,"server",6)) {
  2464 + is_listen = 1;
  2465 + } else if (!strncmp(ptr,"nowait",6)) {
  2466 + is_waitconnect = 0;
  2467 + } else {
  2468 + printf("Unknown option: %s\n", ptr);
  2469 + goto fail;
  2470 + }
  2471 + }
  2472 + if (!is_listen)
  2473 + is_waitconnect = 0;
  2474 +
2432 chr = qemu_mallocz(sizeof(CharDriverState)); 2475 chr = qemu_mallocz(sizeof(CharDriverState));
2433 if (!chr) 2476 if (!chr)
2434 goto fail; 2477 goto fail;
@@ -2439,7 +2482,9 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, @@ -2439,7 +2482,9 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
2439 fd = socket(PF_INET, SOCK_STREAM, 0); 2482 fd = socket(PF_INET, SOCK_STREAM, 0);
2440 if (fd < 0) 2483 if (fd < 0)
2441 goto fail; 2484 goto fail;
2442 - socket_set_nonblock(fd); 2485 +
  2486 + if (!is_waitconnect)
  2487 + socket_set_nonblock(fd);
2443 2488
2444 s->connected = 0; 2489 s->connected = 0;
2445 s->fd = -1; 2490 s->fd = -1;
@@ -2457,6 +2502,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, @@ -2457,6 +2502,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
2457 goto fail; 2502 goto fail;
2458 s->listen_fd = fd; 2503 s->listen_fd = fd;
2459 qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); 2504 qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
  2505 + if (is_telnet)
  2506 + s->do_telnetopt = 1;
2460 } else { 2507 } else {
2461 for(;;) { 2508 for(;;) {
2462 ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); 2509 ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
@@ -2484,6 +2531,12 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, @@ -2484,6 +2531,12 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
2484 chr->chr_write = tcp_chr_write; 2531 chr->chr_write = tcp_chr_write;
2485 chr->chr_add_read_handler = tcp_chr_add_read_handler; 2532 chr->chr_add_read_handler = tcp_chr_add_read_handler;
2486 chr->chr_close = tcp_chr_close; 2533 chr->chr_close = tcp_chr_close;
  2534 + if (is_listen && is_waitconnect) {
  2535 + printf("QEMU waiting for connection on: %s\n", host_str);
  2536 + tcp_chr_accept(chr);
  2537 + socket_set_nonblock(s->listen_fd);
  2538 + }
  2539 +
2487 return chr; 2540 return chr;
2488 fail: 2541 fail:
2489 if (fd >= 0) 2542 if (fd >= 0)
@@ -2505,7 +2558,7 @@ CharDriverState *qemu_chr_open(const char *filename) @@ -2505,7 +2558,7 @@ CharDriverState *qemu_chr_open(const char *filename)
2505 if (strstart(filename, "tcp:", &p)) { 2558 if (strstart(filename, "tcp:", &p)) {
2506 return qemu_chr_open_tcp(p, 0); 2559 return qemu_chr_open_tcp(p, 0);
2507 } else 2560 } else
2508 - if (strstart(filename, "tcpl:", &p)) { 2561 + if (strstart(filename, "telnet:", &p)) {
2509 return qemu_chr_open_tcp(p, 1); 2562 return qemu_chr_open_tcp(p, 1);
2510 } else 2563 } else
2511 if (strstart(filename, "udp:", &p)) { 2564 if (strstart(filename, "udp:", &p)) {
@@ -2618,6 +2671,45 @@ static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) @@ -2618,6 +2671,45 @@ static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
2618 return 0; 2671 return 0;
2619 } 2672 }
2620 2673
  2674 +int parse_host_src_port(struct sockaddr_in *haddr,
  2675 + struct sockaddr_in *saddr,
  2676 + const char *input_str)
  2677 +{
  2678 + char *str = strdup(input_str);
  2679 + char *host_str = str;
  2680 + char *src_str;
  2681 + char *ptr;
  2682 +
  2683 + /*
  2684 + * Chop off any extra arguments at the end of the string which
  2685 + * would start with a comma, then fill in the src port information
  2686 + * if it was provided else use the "any address" and "any port".
  2687 + */
  2688 + if ((ptr = strchr(str,',')))
  2689 + *ptr = '\0';
  2690 +
  2691 + if ((src_str = strchr(input_str,'@'))) {
  2692 + *src_str = '\0';
  2693 + src_str++;
  2694 + }
  2695 +
  2696 + if (parse_host_port(haddr, host_str) < 0)
  2697 + goto fail;
  2698 +
  2699 + if (!src_str || *src_str == '\0')
  2700 + src_str = ":0";
  2701 +
  2702 + if (parse_host_port(saddr, src_str) < 0)
  2703 + goto fail;
  2704 +
  2705 + free(str);
  2706 + return(0);
  2707 +
  2708 +fail:
  2709 + free(str);
  2710 + return -1;
  2711 +}
  2712 +
2621 int parse_host_port(struct sockaddr_in *saddr, const char *str) 2713 int parse_host_port(struct sockaddr_in *saddr, const char *str)
2622 { 2714 {
2623 char buf[512]; 2715 char buf[512];