Commit 0bab00f30f798bd8ae4366a4516d2149174aa714

Authored by bellard
1 parent 3532fa74

UDP char device (initial patch by Jason Wessel) - TCP char device


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2007 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 426 additions and 9 deletions
qemu-doc.texi
... ... @@ -496,8 +496,14 @@ Debug/Expert options:
496 496 @table @option
497 497  
498 498 @item -serial dev
499   -Redirect the virtual serial port to host device @var{dev}. Available
500   -devices are:
  499 +Redirect the virtual serial port to host character device
  500 +@var{dev}. The default device is @code{vc} in graphical mode and
  501 +@code{stdio} in non graphical mode.
  502 +
  503 +This option can be used several times to simulate up to 4 serials
  504 +ports.
  505 +
  506 +Available character devices are:
501 507 @table @code
502 508 @item vc
503 509 Virtual console
... ... @@ -516,13 +522,47 @@ Write output to filename. No character can be read.
516 522 @item stdio
517 523 [Unix only] standard input/output
518 524 @item pipe:filename
519   -[Unix only] name pipe @var{filename}
  525 +name pipe @var{filename}
  526 +@item COMn
  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.
  540 +
  541 +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
  543 +source port each time by using something like @code{-serial
  544 +udp:4556:localhost:4555} to qemu. Another approach is to use a patched
  545 +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
  547 +activates telnet remote echo and single char transfer, then you can
  548 +use the following options to step up a netcat redirector to allow
  549 +telnet on port 5555 to access the qemu port.
  550 +@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
520 555 @end table
521   -The default device is @code{vc} in graphical mode and @code{stdio} in
522   -non graphical mode.
523 556  
524   -This option can be used several times to simulate up to 4 serials
525   -ports.
  557 +
  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
526 566  
527 567 @item -parallel dev
528 568 Redirect the virtual parallel port to host device @var{dev} (same
... ...
... ... @@ -2130,6 +2130,373 @@ CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
2130 2130 }
2131 2131 #endif
2132 2132  
  2133 +/***********************************************************/
  2134 +/* UDP Net console */
  2135 +
  2136 +typedef struct {
  2137 + IOCanRWHandler *fd_can_read;
  2138 + IOReadHandler *fd_read;
  2139 + void *fd_opaque;
  2140 + int fd;
  2141 + struct sockaddr_in daddr;
  2142 + char buf[1024];
  2143 + int bufcnt;
  2144 + int bufptr;
  2145 + int max_size;
  2146 +} NetCharDriver;
  2147 +
  2148 +static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
  2149 +{
  2150 + NetCharDriver *s = chr->opaque;
  2151 +
  2152 + return sendto(s->fd, buf, len, 0,
  2153 + (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in));
  2154 +}
  2155 +
  2156 +static int udp_chr_read_poll(void *opaque)
  2157 +{
  2158 + CharDriverState *chr = opaque;
  2159 + NetCharDriver *s = chr->opaque;
  2160 +
  2161 + s->max_size = s->fd_can_read(s->fd_opaque);
  2162 +
  2163 + /* If there were any stray characters in the queue process them
  2164 + * first
  2165 + */
  2166 + while (s->max_size > 0 && s->bufptr < s->bufcnt) {
  2167 + s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
  2168 + s->bufptr++;
  2169 + s->max_size = s->fd_can_read(s->fd_opaque);
  2170 + }
  2171 + return s->max_size;
  2172 +}
  2173 +
  2174 +static void udp_chr_read(void *opaque)
  2175 +{
  2176 + CharDriverState *chr = opaque;
  2177 + NetCharDriver *s = chr->opaque;
  2178 +
  2179 + if (s->max_size == 0)
  2180 + return;
  2181 + s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0);
  2182 + s->bufptr = s->bufcnt;
  2183 + if (s->bufcnt <= 0)
  2184 + return;
  2185 +
  2186 + s->bufptr = 0;
  2187 + while (s->max_size > 0 && s->bufptr < s->bufcnt) {
  2188 + s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
  2189 + s->bufptr++;
  2190 + s->max_size = s->fd_can_read(s->fd_opaque);
  2191 + }
  2192 +}
  2193 +
  2194 +static void udp_chr_add_read_handler(CharDriverState *chr,
  2195 + IOCanRWHandler *fd_can_read,
  2196 + IOReadHandler *fd_read, void *opaque)
  2197 +{
  2198 + NetCharDriver *s = chr->opaque;
  2199 +
  2200 + if (s->fd >= 0) {
  2201 + s->fd_can_read = fd_can_read;
  2202 + s->fd_read = fd_read;
  2203 + s->fd_opaque = opaque;
  2204 + qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
  2205 + udp_chr_read, NULL, chr);
  2206 + }
  2207 +}
  2208 +
  2209 +int parse_host_port(struct sockaddr_in *saddr, const char *str);
  2210 +
  2211 +CharDriverState *qemu_chr_open_udp(const char *def)
  2212 +{
  2213 + CharDriverState *chr = NULL;
  2214 + NetCharDriver *s = NULL;
  2215 + int fd = -1;
  2216 + int con_type;
  2217 + struct sockaddr_in addr;
  2218 + const char *p, *r;
  2219 + int port;
  2220 +
  2221 + chr = qemu_mallocz(sizeof(CharDriverState));
  2222 + if (!chr)
  2223 + goto return_err;
  2224 + s = qemu_mallocz(sizeof(NetCharDriver));
  2225 + if (!s)
  2226 + goto return_err;
  2227 +
  2228 + fd = socket(PF_INET, SOCK_DGRAM, 0);
  2229 + if (fd < 0) {
  2230 + perror("socket(PF_INET, SOCK_DGRAM)");
  2231 + goto return_err;
  2232 + }
  2233 +
  2234 + /* There are three types of port definitions
  2235 + * 1) udp:remote_port
  2236 + * Juse use 0.0.0.0 for the IP and send to remote
  2237 + * 2) udp:remote_host:port
  2238 + * Use a IP and send traffic to remote
  2239 + * 3) udp:local_port:remote_host:remote_port
  2240 + * Use local_port as the originator + #2
  2241 + */
  2242 + con_type = 0;
  2243 + p = def;
  2244 + while ((p = strchr(p, ':'))) {
  2245 + p++;
  2246 + con_type++;
  2247 + }
  2248 +
  2249 + p = def;
  2250 + memset(&addr,0,sizeof(addr));
  2251 + addr.sin_family = AF_INET;
  2252 + addr.sin_addr.s_addr = htonl(INADDR_ANY);
  2253 + s->daddr.sin_family = AF_INET;
  2254 + s->daddr.sin_addr.s_addr = htonl(INADDR_ANY);
  2255 +
  2256 + switch (con_type) {
  2257 + case 0:
  2258 + port = strtol(p, (char **)&r, 0);
  2259 + if (r == p) {
  2260 + fprintf(stderr, "Error parsing port number\n");
  2261 + goto return_err;
  2262 + }
  2263 + s->daddr.sin_port = htons((short)port);
  2264 + break;
  2265 + case 2:
  2266 + port = strtol(p, (char **)&r, 0);
  2267 + if (r == p) {
  2268 + fprintf(stderr, "Error parsing port number\n");
  2269 + goto return_err;
  2270 + }
  2271 + addr.sin_port = htons((short)port);
  2272 + p = r + 1;
  2273 + /* Fall through to case 1 now that we have the local port */
  2274 + case 1:
  2275 + if (parse_host_port(&s->daddr, p) < 0) {
  2276 + fprintf(stderr, "Error parsing host name and port\n");
  2277 + goto return_err;
  2278 + }
  2279 + break;
  2280 + default:
  2281 + fprintf(stderr, "Too many ':' characters\n");
  2282 + goto return_err;
  2283 + }
  2284 +
  2285 + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
  2286 + {
  2287 + perror("bind");
  2288 + goto return_err;
  2289 + }
  2290 +
  2291 + s->fd = fd;
  2292 + s->bufcnt = 0;
  2293 + s->bufptr = 0;
  2294 + chr->opaque = s;
  2295 + chr->chr_write = udp_chr_write;
  2296 + chr->chr_add_read_handler = udp_chr_add_read_handler;
  2297 + return chr;
  2298 +
  2299 +return_err:
  2300 + if (chr)
  2301 + free(chr);
  2302 + if (s)
  2303 + free(s);
  2304 + if (fd >= 0)
  2305 + closesocket(fd);
  2306 + return NULL;
  2307 +}
  2308 +
  2309 +/***********************************************************/
  2310 +/* TCP Net console */
  2311 +
  2312 +typedef struct {
  2313 + IOCanRWHandler *fd_can_read;
  2314 + IOReadHandler *fd_read;
  2315 + void *fd_opaque;
  2316 + int fd, listen_fd;
  2317 + int connected;
  2318 + int max_size;
  2319 +} TCPCharDriver;
  2320 +
  2321 +static void tcp_chr_accept(void *opaque);
  2322 +
  2323 +static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
  2324 +{
  2325 + TCPCharDriver *s = chr->opaque;
  2326 + if (s->connected) {
  2327 + return send_all(s->fd, buf, len);
  2328 + } else {
  2329 + /* XXX: indicate an error ? */
  2330 + return len;
  2331 + }
  2332 +}
  2333 +
  2334 +static int tcp_chr_read_poll(void *opaque)
  2335 +{
  2336 + CharDriverState *chr = opaque;
  2337 + TCPCharDriver *s = chr->opaque;
  2338 + if (!s->connected)
  2339 + return 0;
  2340 + s->max_size = s->fd_can_read(s->fd_opaque);
  2341 + return s->max_size;
  2342 +}
  2343 +
  2344 +static void tcp_chr_read(void *opaque)
  2345 +{
  2346 + CharDriverState *chr = opaque;
  2347 + TCPCharDriver *s = chr->opaque;
  2348 + uint8_t buf[1024];
  2349 + int len, size;
  2350 +
  2351 + if (!s->connected || s->max_size <= 0)
  2352 + return;
  2353 + len = sizeof(buf);
  2354 + if (len > s->max_size)
  2355 + len = s->max_size;
  2356 + size = recv(s->fd, buf, len, 0);
  2357 + if (size == 0) {
  2358 + /* connection closed */
  2359 + s->connected = 0;
  2360 + if (s->listen_fd >= 0) {
  2361 + qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
  2362 + }
  2363 + qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
  2364 + closesocket(s->fd);
  2365 + s->fd = -1;
  2366 + } else if (size > 0) {
  2367 + s->fd_read(s->fd_opaque, buf, size);
  2368 + }
  2369 +}
  2370 +
  2371 +static void tcp_chr_add_read_handler(CharDriverState *chr,
  2372 + IOCanRWHandler *fd_can_read,
  2373 + IOReadHandler *fd_read, void *opaque)
  2374 +{
  2375 + TCPCharDriver *s = chr->opaque;
  2376 +
  2377 + s->fd_can_read = fd_can_read;
  2378 + s->fd_read = fd_read;
  2379 + s->fd_opaque = opaque;
  2380 +}
  2381 +
  2382 +static void tcp_chr_connect(void *opaque)
  2383 +{
  2384 + CharDriverState *chr = opaque;
  2385 + TCPCharDriver *s = chr->opaque;
  2386 +
  2387 + s->connected = 1;
  2388 + qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
  2389 + tcp_chr_read, NULL, chr);
  2390 +}
  2391 +
  2392 +static void tcp_chr_accept(void *opaque)
  2393 +{
  2394 + CharDriverState *chr = opaque;
  2395 + TCPCharDriver *s = chr->opaque;
  2396 + struct sockaddr_in saddr;
  2397 + socklen_t len;
  2398 + int fd;
  2399 +
  2400 + for(;;) {
  2401 + len = sizeof(saddr);
  2402 + fd = accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
  2403 + if (fd < 0 && errno != EINTR) {
  2404 + return;
  2405 + } else if (fd >= 0) {
  2406 + break;
  2407 + }
  2408 + }
  2409 + socket_set_nonblock(fd);
  2410 + s->fd = fd;
  2411 + qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
  2412 + tcp_chr_connect(chr);
  2413 +}
  2414 +
  2415 +static void tcp_chr_close(CharDriverState *chr)
  2416 +{
  2417 + TCPCharDriver *s = chr->opaque;
  2418 + if (s->fd >= 0)
  2419 + closesocket(s->fd);
  2420 + if (s->listen_fd >= 0)
  2421 + closesocket(s->listen_fd);
  2422 + qemu_free(s);
  2423 +}
  2424 +
  2425 +static CharDriverState *qemu_chr_open_tcp(const char *host_str,
  2426 + int is_listen)
  2427 +{
  2428 + CharDriverState *chr = NULL;
  2429 + TCPCharDriver *s = NULL;
  2430 + int fd = -1, ret, err, val;
  2431 + struct sockaddr_in saddr;
  2432 +
  2433 + if (parse_host_port(&saddr, host_str) < 0)
  2434 + goto fail;
  2435 +
  2436 + chr = qemu_mallocz(sizeof(CharDriverState));
  2437 + if (!chr)
  2438 + goto fail;
  2439 + s = qemu_mallocz(sizeof(TCPCharDriver));
  2440 + if (!s)
  2441 + goto fail;
  2442 +
  2443 + fd = socket(PF_INET, SOCK_STREAM, 0);
  2444 + if (fd < 0)
  2445 + goto fail;
  2446 + socket_set_nonblock(fd);
  2447 +
  2448 + s->connected = 0;
  2449 + s->fd = -1;
  2450 + s->listen_fd = -1;
  2451 + if (is_listen) {
  2452 + /* allow fast reuse */
  2453 + val = 1;
  2454 + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
  2455 +
  2456 + ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
  2457 + if (ret < 0)
  2458 + goto fail;
  2459 + ret = listen(fd, 0);
  2460 + if (ret < 0)
  2461 + goto fail;
  2462 + s->listen_fd = fd;
  2463 + qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
  2464 + } else {
  2465 + for(;;) {
  2466 + ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
  2467 + if (ret < 0) {
  2468 + err = socket_error();
  2469 + if (err == EINTR || err == EWOULDBLOCK) {
  2470 + } else if (err == EINPROGRESS) {
  2471 + break;
  2472 + } else {
  2473 + goto fail;
  2474 + }
  2475 + } else {
  2476 + s->connected = 1;
  2477 + break;
  2478 + }
  2479 + }
  2480 + s->fd = fd;
  2481 + if (s->connected)
  2482 + tcp_chr_connect(chr);
  2483 + else
  2484 + qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr);
  2485 + }
  2486 +
  2487 + chr->opaque = s;
  2488 + chr->chr_write = tcp_chr_write;
  2489 + chr->chr_add_read_handler = tcp_chr_add_read_handler;
  2490 + chr->chr_close = tcp_chr_close;
  2491 + return chr;
  2492 + fail:
  2493 + if (fd >= 0)
  2494 + closesocket(fd);
  2495 + qemu_free(s);
  2496 + qemu_free(chr);
  2497 + return NULL;
  2498 +}
  2499 +
2133 2500 CharDriverState *qemu_chr_open(const char *filename)
2134 2501 {
2135 2502 const char *p;
... ... @@ -2139,6 +2506,15 @@ CharDriverState *qemu_chr_open(const char *filename)
2139 2506 } else if (!strcmp(filename, "null")) {
2140 2507 return qemu_chr_open_null();
2141 2508 } else
  2509 + if (strstart(filename, "tcp:", &p)) {
  2510 + return qemu_chr_open_tcp(p, 0);
  2511 + } else
  2512 + if (strstart(filename, "tcpl:", &p)) {
  2513 + return qemu_chr_open_tcp(p, 1);
  2514 + } else
  2515 + if (strstart(filename, "udp:", &p)) {
  2516 + return qemu_chr_open_udp(p);
  2517 + } else
2142 2518 #ifndef _WIN32
2143 2519 if (strstart(filename, "file:", &p)) {
2144 2520 return qemu_chr_open_file_out(p);
... ... @@ -2844,7 +3220,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
2844 3220 socket_set_nonblock(fd);
2845 3221 return fd;
2846 3222 fail:
2847   - if (fd>=0) close(fd);
  3223 + if (fd >= 0)
  3224 + closesocket(fd);
2848 3225 return -1;
2849 3226 }
2850 3227  
... ... @@ -2972,7 +3349,7 @@ static void net_socket_accept(void *opaque)
2972 3349 }
2973 3350 s1 = net_socket_fd_init(s->vlan, fd, 1);
2974 3351 if (!s1) {
2975   - close(fd);
  3352 + closesocket(fd);
2976 3353 } else {
2977 3354 snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
2978 3355 "socket: connection from %s:%d",
... ...