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
This commit is contained in:
		
							parent
							
								
									3532fa7402
								
							
						
					
					
						commit
						0bab00f30f
					
				@ -496,8 +496,14 @@ Debug/Expert options:
 | 
				
			|||||||
@table @option
 | 
					@table @option
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item -serial dev
 | 
					@item -serial dev
 | 
				
			||||||
Redirect the virtual serial port to host device @var{dev}. Available
 | 
					Redirect the virtual serial port to host character device
 | 
				
			||||||
devices are:
 | 
					@var{dev}. The default device is @code{vc} in graphical mode and
 | 
				
			||||||
 | 
					@code{stdio} in non graphical mode.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This option can be used several times to simulate up to 4 serials
 | 
				
			||||||
 | 
					ports.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Available character devices are:
 | 
				
			||||||
@table @code
 | 
					@table @code
 | 
				
			||||||
@item vc
 | 
					@item vc
 | 
				
			||||||
Virtual console
 | 
					Virtual console
 | 
				
			||||||
@ -516,13 +522,47 @@ Write output to filename. No character can be read.
 | 
				
			|||||||
@item stdio
 | 
					@item stdio
 | 
				
			||||||
[Unix only] standard input/output
 | 
					[Unix only] standard input/output
 | 
				
			||||||
@item pipe:filename
 | 
					@item pipe:filename
 | 
				
			||||||
[Unix only] name pipe @var{filename}
 | 
					name pipe @var{filename}
 | 
				
			||||||
@end table
 | 
					@item COMn
 | 
				
			||||||
The default device is @code{vc} in graphical mode and @code{stdio} in
 | 
					[Windows only] Use host serial port @var{n}
 | 
				
			||||||
non graphical mode.
 | 
					@item udp:remote_port
 | 
				
			||||||
 | 
					UDP Net Console sent to locahost at remote_port
 | 
				
			||||||
 | 
					@item udp:remote_host:remote_port
 | 
				
			||||||
 | 
					UDP Net Console sent to remote_host at remote_port
 | 
				
			||||||
 | 
					@item udp:src_port:remote_host:remote_port
 | 
				
			||||||
 | 
					UDP Net Console sent from src_port to remote_host at the remote_port.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This option can be used several times to simulate up to 4 serials
 | 
					The udp:* sub options are primary intended for netconsole.  If you
 | 
				
			||||||
ports.
 | 
					just want a simple readonly console you can use @code{netcat} or
 | 
				
			||||||
 | 
					@code{nc}, by starting qemu with: @code{-serial udp:4555} and nc as:
 | 
				
			||||||
 | 
					@code{nc -u -l -p 4555}. Any time qemu writes something to that port
 | 
				
			||||||
 | 
					it will appear in the netconsole session.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you plan to send characters back via netconsole or you want to stop
 | 
				
			||||||
 | 
					and start qemu a lot of times, you should have qemu use the same
 | 
				
			||||||
 | 
					source port each time by using something like @code{-serial
 | 
				
			||||||
 | 
					udp:4556:localhost:4555} to qemu. Another approach is to use a patched
 | 
				
			||||||
 | 
					version of netcat which can listen to a TCP port and send and receive
 | 
				
			||||||
 | 
					characters via udp.  If you have a patched version of netcat which
 | 
				
			||||||
 | 
					activates telnet remote echo and single char transfer, then you can
 | 
				
			||||||
 | 
					use the following options to step up a netcat redirector to allow
 | 
				
			||||||
 | 
					telnet on port 5555 to access the qemu port.
 | 
				
			||||||
 | 
					@table @code
 | 
				
			||||||
 | 
					@item Qemu Options
 | 
				
			||||||
 | 
					-serial udp:4556:localhost:4555
 | 
				
			||||||
 | 
					@item netcat options
 | 
				
			||||||
 | 
					-u -P 4555 -L localhost:4556  -t -p 5555 -I -T
 | 
				
			||||||
 | 
					@end table
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item tcp:remote_host:remote_port
 | 
				
			||||||
 | 
					TCP Net Console sent to remote_host at the remote_port
 | 
				
			||||||
 | 
					@item tcpl:host:port
 | 
				
			||||||
 | 
					TCP Net Console: wait for connection on @var{host} on the local port
 | 
				
			||||||
 | 
					@var{port}. If host is omitted, 0.0.0.0 is assumed. Only one TCP
 | 
				
			||||||
 | 
					connection at a time is accepted. You can use @code{telnet} to connect
 | 
				
			||||||
 | 
					to the corresponding character device.
 | 
				
			||||||
 | 
					@end table
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item -parallel dev
 | 
					@item -parallel dev
 | 
				
			||||||
Redirect the virtual parallel port to host device @var{dev} (same
 | 
					Redirect the virtual parallel port to host device @var{dev} (same
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										381
									
								
								vl.c
									
									
									
									
									
								
							
							
						
						
									
										381
									
								
								vl.c
									
									
									
									
									
								
							@ -2130,6 +2130,373 @@ CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***********************************************************/
 | 
				
			||||||
 | 
					/* UDP Net console */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    IOCanRWHandler *fd_can_read;
 | 
				
			||||||
 | 
					    IOReadHandler *fd_read;
 | 
				
			||||||
 | 
					    void *fd_opaque;
 | 
				
			||||||
 | 
					    int fd;
 | 
				
			||||||
 | 
					    struct sockaddr_in daddr;
 | 
				
			||||||
 | 
					    char buf[1024];
 | 
				
			||||||
 | 
					    int bufcnt;
 | 
				
			||||||
 | 
					    int bufptr;
 | 
				
			||||||
 | 
					    int max_size;
 | 
				
			||||||
 | 
					} NetCharDriver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NetCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return sendto(s->fd, buf, len, 0,
 | 
				
			||||||
 | 
					                  (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int udp_chr_read_poll(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CharDriverState *chr = opaque;
 | 
				
			||||||
 | 
					    NetCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->max_size = s->fd_can_read(s->fd_opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* If there were any stray characters in the queue process them
 | 
				
			||||||
 | 
					     * first
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
 | 
				
			||||||
 | 
					        s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
 | 
				
			||||||
 | 
					        s->bufptr++;
 | 
				
			||||||
 | 
					        s->max_size = s->fd_can_read(s->fd_opaque);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return s->max_size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void udp_chr_read(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CharDriverState *chr = opaque;
 | 
				
			||||||
 | 
					    NetCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->max_size == 0)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0);
 | 
				
			||||||
 | 
					    s->bufptr = s->bufcnt;
 | 
				
			||||||
 | 
					    if (s->bufcnt <= 0)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->bufptr = 0;
 | 
				
			||||||
 | 
					    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
 | 
				
			||||||
 | 
					        s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
 | 
				
			||||||
 | 
					        s->bufptr++;
 | 
				
			||||||
 | 
					        s->max_size = s->fd_can_read(s->fd_opaque);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void udp_chr_add_read_handler(CharDriverState *chr,
 | 
				
			||||||
 | 
					                                    IOCanRWHandler *fd_can_read,
 | 
				
			||||||
 | 
					                                    IOReadHandler *fd_read, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    NetCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->fd >= 0) {
 | 
				
			||||||
 | 
					        s->fd_can_read = fd_can_read;
 | 
				
			||||||
 | 
					        s->fd_read = fd_read;
 | 
				
			||||||
 | 
					        s->fd_opaque = opaque;
 | 
				
			||||||
 | 
					        qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
 | 
				
			||||||
 | 
					                             udp_chr_read, NULL, chr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int parse_host_port(struct sockaddr_in *saddr, const char *str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CharDriverState *qemu_chr_open_udp(const char *def)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CharDriverState *chr = NULL;
 | 
				
			||||||
 | 
					    NetCharDriver *s = NULL;
 | 
				
			||||||
 | 
					    int fd = -1;
 | 
				
			||||||
 | 
					    int con_type;
 | 
				
			||||||
 | 
					    struct sockaddr_in addr;
 | 
				
			||||||
 | 
					    const char *p, *r;
 | 
				
			||||||
 | 
					    int port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    chr = qemu_mallocz(sizeof(CharDriverState));
 | 
				
			||||||
 | 
					    if (!chr)
 | 
				
			||||||
 | 
					        goto return_err;
 | 
				
			||||||
 | 
					    s = qemu_mallocz(sizeof(NetCharDriver));
 | 
				
			||||||
 | 
					    if (!s)
 | 
				
			||||||
 | 
					        goto return_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fd = socket(PF_INET, SOCK_DGRAM, 0);
 | 
				
			||||||
 | 
					    if (fd < 0) {
 | 
				
			||||||
 | 
					        perror("socket(PF_INET, SOCK_DGRAM)");
 | 
				
			||||||
 | 
					        goto return_err;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* There are three types of port definitions
 | 
				
			||||||
 | 
					     * 1) udp:remote_port
 | 
				
			||||||
 | 
					     *    Juse use 0.0.0.0 for the IP and send to remote
 | 
				
			||||||
 | 
					     * 2) udp:remote_host:port
 | 
				
			||||||
 | 
					     *    Use a IP and send traffic to remote
 | 
				
			||||||
 | 
					     * 3) udp:local_port:remote_host:remote_port
 | 
				
			||||||
 | 
					     *    Use local_port as the originator + #2
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    con_type = 0;
 | 
				
			||||||
 | 
					    p = def;
 | 
				
			||||||
 | 
					    while ((p = strchr(p, ':'))) {
 | 
				
			||||||
 | 
					        p++;
 | 
				
			||||||
 | 
					        con_type++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    p = def;
 | 
				
			||||||
 | 
					    memset(&addr,0,sizeof(addr));
 | 
				
			||||||
 | 
					    addr.sin_family = AF_INET;
 | 
				
			||||||
 | 
					    addr.sin_addr.s_addr = htonl(INADDR_ANY);
 | 
				
			||||||
 | 
					    s->daddr.sin_family = AF_INET;
 | 
				
			||||||
 | 
					    s->daddr.sin_addr.s_addr = htonl(INADDR_ANY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (con_type) {
 | 
				
			||||||
 | 
					        case 0:
 | 
				
			||||||
 | 
					            port = strtol(p, (char **)&r, 0);
 | 
				
			||||||
 | 
					            if (r == p) {
 | 
				
			||||||
 | 
					                fprintf(stderr, "Error parsing port number\n");
 | 
				
			||||||
 | 
					                goto return_err;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            s->daddr.sin_port = htons((short)port);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case 2:
 | 
				
			||||||
 | 
					            port = strtol(p, (char **)&r, 0);
 | 
				
			||||||
 | 
					            if (r == p) {
 | 
				
			||||||
 | 
					                fprintf(stderr, "Error parsing port number\n");
 | 
				
			||||||
 | 
					                goto return_err;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            addr.sin_port = htons((short)port);
 | 
				
			||||||
 | 
					            p = r + 1;
 | 
				
			||||||
 | 
					            /* Fall through to case 1 now that we have the local port */
 | 
				
			||||||
 | 
					        case 1:
 | 
				
			||||||
 | 
					            if (parse_host_port(&s->daddr, p) < 0) {
 | 
				
			||||||
 | 
					                fprintf(stderr, "Error parsing host name and port\n");
 | 
				
			||||||
 | 
					                goto return_err;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            fprintf(stderr, "Too many ':' characters\n");
 | 
				
			||||||
 | 
					            goto return_err;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        perror("bind");
 | 
				
			||||||
 | 
					        goto return_err;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->fd = fd;
 | 
				
			||||||
 | 
					    s->bufcnt = 0;
 | 
				
			||||||
 | 
					    s->bufptr = 0;
 | 
				
			||||||
 | 
					    chr->opaque = s;
 | 
				
			||||||
 | 
					    chr->chr_write = udp_chr_write;
 | 
				
			||||||
 | 
					    chr->chr_add_read_handler = udp_chr_add_read_handler;
 | 
				
			||||||
 | 
					    return chr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return_err:
 | 
				
			||||||
 | 
					    if (chr)
 | 
				
			||||||
 | 
					        free(chr);
 | 
				
			||||||
 | 
					    if (s)
 | 
				
			||||||
 | 
					        free(s);
 | 
				
			||||||
 | 
					    if (fd >= 0)
 | 
				
			||||||
 | 
					        closesocket(fd);
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***********************************************************/
 | 
				
			||||||
 | 
					/* TCP Net console */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    IOCanRWHandler *fd_can_read;
 | 
				
			||||||
 | 
					    IOReadHandler *fd_read;
 | 
				
			||||||
 | 
					    void *fd_opaque;
 | 
				
			||||||
 | 
					    int fd, listen_fd;
 | 
				
			||||||
 | 
					    int connected;
 | 
				
			||||||
 | 
					    int max_size;
 | 
				
			||||||
 | 
					} TCPCharDriver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tcp_chr_accept(void *opaque);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    TCPCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					    if (s->connected) {
 | 
				
			||||||
 | 
					        return send_all(s->fd, buf, len);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        /* XXX: indicate an error ? */
 | 
				
			||||||
 | 
					        return len;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tcp_chr_read_poll(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CharDriverState *chr = opaque;
 | 
				
			||||||
 | 
					    TCPCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					    if (!s->connected)
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    s->max_size = s->fd_can_read(s->fd_opaque);
 | 
				
			||||||
 | 
					    return s->max_size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tcp_chr_read(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CharDriverState *chr = opaque;
 | 
				
			||||||
 | 
					    TCPCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					    uint8_t buf[1024];
 | 
				
			||||||
 | 
					    int len, size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!s->connected || s->max_size <= 0)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    len = sizeof(buf);
 | 
				
			||||||
 | 
					    if (len > s->max_size)
 | 
				
			||||||
 | 
					        len = s->max_size;
 | 
				
			||||||
 | 
					    size = recv(s->fd, buf, len, 0);
 | 
				
			||||||
 | 
					    if (size == 0) {
 | 
				
			||||||
 | 
					        /* connection closed */
 | 
				
			||||||
 | 
					        s->connected = 0;
 | 
				
			||||||
 | 
					        if (s->listen_fd >= 0) {
 | 
				
			||||||
 | 
					            qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
 | 
				
			||||||
 | 
					        closesocket(s->fd);
 | 
				
			||||||
 | 
					        s->fd = -1;
 | 
				
			||||||
 | 
					    } else if (size > 0) {
 | 
				
			||||||
 | 
					        s->fd_read(s->fd_opaque, buf, size);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tcp_chr_add_read_handler(CharDriverState *chr,
 | 
				
			||||||
 | 
					                                     IOCanRWHandler *fd_can_read,
 | 
				
			||||||
 | 
					                                    IOReadHandler *fd_read, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    TCPCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->fd_can_read = fd_can_read;
 | 
				
			||||||
 | 
					    s->fd_read = fd_read;
 | 
				
			||||||
 | 
					    s->fd_opaque = opaque;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tcp_chr_connect(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CharDriverState *chr = opaque;
 | 
				
			||||||
 | 
					    TCPCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->connected = 1;
 | 
				
			||||||
 | 
					    qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
 | 
				
			||||||
 | 
					                         tcp_chr_read, NULL, chr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tcp_chr_accept(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CharDriverState *chr = opaque;
 | 
				
			||||||
 | 
					    TCPCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					    struct sockaddr_in saddr;
 | 
				
			||||||
 | 
					    socklen_t len;
 | 
				
			||||||
 | 
					    int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(;;) {
 | 
				
			||||||
 | 
					        len = sizeof(saddr);
 | 
				
			||||||
 | 
					        fd = accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
 | 
				
			||||||
 | 
					        if (fd < 0 && errno != EINTR) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        } else if (fd >= 0) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    socket_set_nonblock(fd);
 | 
				
			||||||
 | 
					    s->fd = fd;
 | 
				
			||||||
 | 
					    qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
 | 
				
			||||||
 | 
					    tcp_chr_connect(chr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tcp_chr_close(CharDriverState *chr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    TCPCharDriver *s = chr->opaque;
 | 
				
			||||||
 | 
					    if (s->fd >= 0)
 | 
				
			||||||
 | 
					        closesocket(s->fd);
 | 
				
			||||||
 | 
					    if (s->listen_fd >= 0)
 | 
				
			||||||
 | 
					        closesocket(s->listen_fd);
 | 
				
			||||||
 | 
					    qemu_free(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static CharDriverState *qemu_chr_open_tcp(const char *host_str, 
 | 
				
			||||||
 | 
					                                          int is_listen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CharDriverState *chr = NULL;
 | 
				
			||||||
 | 
					    TCPCharDriver *s = NULL;
 | 
				
			||||||
 | 
					    int fd = -1, ret, err, val;
 | 
				
			||||||
 | 
					    struct sockaddr_in saddr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (parse_host_port(&saddr, host_str) < 0)
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    chr = qemu_mallocz(sizeof(CharDriverState));
 | 
				
			||||||
 | 
					    if (!chr)
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    s = qemu_mallocz(sizeof(TCPCharDriver));
 | 
				
			||||||
 | 
					    if (!s)
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    fd = socket(PF_INET, SOCK_STREAM, 0);
 | 
				
			||||||
 | 
					    if (fd < 0) 
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    socket_set_nonblock(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->connected = 0;
 | 
				
			||||||
 | 
					    s->fd = -1;
 | 
				
			||||||
 | 
					    s->listen_fd = -1;
 | 
				
			||||||
 | 
					    if (is_listen) {
 | 
				
			||||||
 | 
					        /* allow fast reuse */
 | 
				
			||||||
 | 
					        val = 1;
 | 
				
			||||||
 | 
					        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
 | 
				
			||||||
 | 
					        if (ret < 0) 
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        ret = listen(fd, 0);
 | 
				
			||||||
 | 
					        if (ret < 0)
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        s->listen_fd = fd;
 | 
				
			||||||
 | 
					        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        for(;;) {
 | 
				
			||||||
 | 
					            ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
 | 
				
			||||||
 | 
					            if (ret < 0) {
 | 
				
			||||||
 | 
					                err = socket_error();
 | 
				
			||||||
 | 
					                if (err == EINTR || err == EWOULDBLOCK) {
 | 
				
			||||||
 | 
					                } else if (err == EINPROGRESS) {
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    goto fail;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                s->connected = 1;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        s->fd = fd;
 | 
				
			||||||
 | 
					        if (s->connected)
 | 
				
			||||||
 | 
					            tcp_chr_connect(chr);
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    chr->opaque = s;
 | 
				
			||||||
 | 
					    chr->chr_write = tcp_chr_write;
 | 
				
			||||||
 | 
					    chr->chr_add_read_handler = tcp_chr_add_read_handler;
 | 
				
			||||||
 | 
					    chr->chr_close = tcp_chr_close;
 | 
				
			||||||
 | 
					    return chr;
 | 
				
			||||||
 | 
					 fail:
 | 
				
			||||||
 | 
					    if (fd >= 0)
 | 
				
			||||||
 | 
					        closesocket(fd);
 | 
				
			||||||
 | 
					    qemu_free(s);
 | 
				
			||||||
 | 
					    qemu_free(chr);
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CharDriverState *qemu_chr_open(const char *filename)
 | 
					CharDriverState *qemu_chr_open(const char *filename)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const char *p;
 | 
					    const char *p;
 | 
				
			||||||
@ -2139,6 +2506,15 @@ CharDriverState *qemu_chr_open(const char *filename)
 | 
				
			|||||||
    } else if (!strcmp(filename, "null")) {
 | 
					    } else if (!strcmp(filename, "null")) {
 | 
				
			||||||
        return qemu_chr_open_null();
 | 
					        return qemu_chr_open_null();
 | 
				
			||||||
    } else 
 | 
					    } else 
 | 
				
			||||||
 | 
					    if (strstart(filename, "tcp:", &p)) {
 | 
				
			||||||
 | 
					        return qemu_chr_open_tcp(p, 0);
 | 
				
			||||||
 | 
					    } else
 | 
				
			||||||
 | 
					    if (strstart(filename, "tcpl:", &p)) {
 | 
				
			||||||
 | 
					        return qemu_chr_open_tcp(p, 1);
 | 
				
			||||||
 | 
					    } else
 | 
				
			||||||
 | 
					    if (strstart(filename, "udp:", &p)) {
 | 
				
			||||||
 | 
					        return qemu_chr_open_udp(p);
 | 
				
			||||||
 | 
					    } else
 | 
				
			||||||
#ifndef _WIN32
 | 
					#ifndef _WIN32
 | 
				
			||||||
    if (strstart(filename, "file:", &p)) {
 | 
					    if (strstart(filename, "file:", &p)) {
 | 
				
			||||||
        return qemu_chr_open_file_out(p);
 | 
					        return qemu_chr_open_file_out(p);
 | 
				
			||||||
@ -2844,7 +3220,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
 | 
				
			|||||||
    socket_set_nonblock(fd);
 | 
					    socket_set_nonblock(fd);
 | 
				
			||||||
    return fd;
 | 
					    return fd;
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
    if (fd>=0) close(fd);
 | 
					    if (fd >= 0) 
 | 
				
			||||||
 | 
					        closesocket(fd);
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2972,7 +3349,7 @@ static void net_socket_accept(void *opaque)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    s1 = net_socket_fd_init(s->vlan, fd, 1); 
 | 
					    s1 = net_socket_fd_init(s->vlan, fd, 1); 
 | 
				
			||||||
    if (!s1) {
 | 
					    if (!s1) {
 | 
				
			||||||
        close(fd);
 | 
					        closesocket(fd);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
 | 
					        snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
 | 
				
			||||||
                 "socket: connection from %s:%d", 
 | 
					                 "socket: connection from %s:%d", 
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user