📄 vl.c
字号:
} snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename); s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL); if (s->hcom == INVALID_HANDLE_VALUE) { fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError()); s->hcom = NULL; goto fail; } ZeroMemory(&ov, sizeof(ov)); ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); ret = ConnectNamedPipe(s->hcom, &ov); if (ret) { fprintf(stderr, "Failed ConnectNamedPipe\n"); goto fail; } ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE); if (!ret) { fprintf(stderr, "Failed GetOverlappedResult\n"); if (ov.hEvent) { CloseHandle(ov.hEvent); ov.hEvent = NULL; } goto fail; } if (ov.hEvent) { CloseHandle(ov.hEvent); ov.hEvent = NULL; } qemu_add_polling_cb(win_chr_pipe_poll, s); return 0; fail: win_chr_close2(s); return -1;}static CharDriverState *qemu_chr_open_win_pipe(const char *filename){ CharDriverState *chr; WinCharState *s; chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) return NULL; s = qemu_mallocz(sizeof(WinCharState)); if (!s) { free(chr); return NULL; } chr->opaque = s; chr->chr_write = win_chr_write; chr->chr_close = win_chr_close; if (win_chr_pipe_init(s, filename) < 0) { free(s); free(chr); return NULL; } qemu_chr_reset(chr); return chr;}static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out){ CharDriverState *chr; WinCharState *s; chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) return NULL; s = qemu_mallocz(sizeof(WinCharState)); if (!s) { free(chr); return NULL; } s->hcom = fd_out; chr->opaque = s; chr->chr_write = win_chr_write; qemu_chr_reset(chr); return chr;} static CharDriverState *qemu_chr_open_win_file_out(const char *file_out){ HANDLE fd_out; fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fd_out == INVALID_HANDLE_VALUE) return NULL; return qemu_chr_open_win_file(fd_out);}#endif/***********************************************************//* UDP Net console */typedef struct { 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 = qemu_chr_can_read(chr); /* If there were any stray characters in the queue process them * first */ while (s->max_size > 0 && s->bufptr < s->bufcnt) { qemu_chr_read(chr, &s->buf[s->bufptr], 1); s->bufptr++; s->max_size = qemu_chr_can_read(chr); } 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) { qemu_chr_read(chr, &s->buf[s->bufptr], 1); s->bufptr++; s->max_size = qemu_chr_can_read(chr); }}static void udp_chr_update_read_handler(CharDriverState *chr){ NetCharDriver *s = chr->opaque; if (s->fd >= 0) { 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);#ifndef _WIN32static int parse_unix_path(struct sockaddr_un *uaddr, const char *str);#endifint parse_host_src_port(struct sockaddr_in *haddr, struct sockaddr_in *saddr, const char *str);static CharDriverState *qemu_chr_open_udp(const char *def){ CharDriverState *chr = NULL; NetCharDriver *s = NULL; int fd = -1; struct sockaddr_in saddr; 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; } if (parse_host_src_port(&s->daddr, &saddr, def) < 0) { printf("Could not parse: %s\n", def); goto return_err; } if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 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_update_read_handler = udp_chr_update_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 { int fd, listen_fd; int connected; int max_size; int do_telnetopt; int do_nodelay; int is_unix;} 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 = qemu_chr_can_read(chr); return s->max_size;}#define IAC 255#define IAC_BREAK 243static void tcp_chr_process_IAC_bytes(CharDriverState *chr, TCPCharDriver *s, char *buf, int *size){ /* Handle any telnet client's basic IAC options to satisfy char by * char mode with no echo. All IAC options will be removed from * the buf and the do_telnetopt variable will be used to track the * state of the width of the IAC information. * * IAC commands come in sets of 3 bytes with the exception of the * "IAC BREAK" command and the double IAC. */ int i; int j = 0; for (i = 0; i < *size; i++) { if (s->do_telnetopt > 1) { if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) { /* Double IAC means send an IAC */ if (j != i) buf[j] = buf[i]; j++; s->do_telnetopt = 1; } else { if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) { /* Handle IAC break commands by sending a serial break */ qemu_chr_event(chr, CHR_EVENT_BREAK); s->do_telnetopt++; } s->do_telnetopt++; } if (s->do_telnetopt >= 4) { s->do_telnetopt = 1; } } else { if ((unsigned char)buf[i] == IAC) { s->do_telnetopt = 2; } else { if (j != i) buf[j] = buf[i]; j++; } } } *size = j;}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) { if (s->do_telnetopt) tcp_chr_process_IAC_bytes(chr, s, buf, &size); if (size > 0) qemu_chr_read(chr, buf, size); }}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); qemu_chr_reset(chr);}#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;static void tcp_chr_telnet_init(int fd){ char buf[3]; /* Send the telnet negotion to put telnet in binary, no echo, single char mode */ IACSET(buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */ send(fd, (char *)buf, 3, 0); IACSET(buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */ send(fd, (char *)buf, 3, 0); IACSET(buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */ send(fd, (char *)buf, 3, 0); IACSET(buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */ send(fd, (char *)buf, 3, 0);}static void socket_set_nodelay(int fd){ int val = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));}static void tcp_chr_accept(void *opaque){ CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; struct sockaddr_in saddr;#ifndef _WIN32 struct sockaddr_un uaddr;#endif struct sockaddr *addr; socklen_t len; int fd; for(;;) {#ifndef _WIN32 if (s->is_unix) { len = sizeof(uaddr); addr = (struct sockaddr *)&uaddr; } else#endif { len = sizeof(saddr); addr = (struct sockaddr *)&saddr; } fd = accept(s->listen_fd, addr, &len); if (fd < 0 && errno != EINTR) { return; } else if (fd >= 0) { if (s->do_telnetopt) tcp_chr_telnet_init(fd); break; } } socket_set_nonblock(fd); if (s->do_nodelay) socket_set_nodelay(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_telnet, int is_unix){ CharDriverState *chr = NULL; TCPCharDriver *s = NULL; int fd = -1, ret, err, val; int is_listen = 0; int is_waitconnect = 1; int do_nodelay = 0; const char *ptr; struct sockaddr_in saddr;#ifndef _WIN32 struct sockaddr_un uaddr;#endif struct sockaddr *addr; socklen_t addrlen;#ifndef _WIN32 if (is_unix) { addr = (struct sockaddr *)&uaddr; addrlen = sizeof(uaddr); if (parse_unix_path(&uaddr, host_str) < 0) goto fail; } else#endif { addr = (struct sockaddr *)&saddr; addrlen = sizeof(saddr); if (parse_host_port(&saddr, host_str) < 0) goto fail; } ptr = host_str; while((ptr = strchr(ptr,','))) { ptr++; if (!strncmp(ptr,"server",6)) { is_listen = 1; } else if (!strncmp(ptr,"nowait",6)) { is_waitconnect = 0; } else if (!strncmp(ptr,"nodelay",6)) { do_nodelay = 1; } else { printf("Unknown option: %s\n", ptr); goto fail; } } if (!is_listen) is_waitconnect = 0; chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) goto fail; s = qemu_mallocz(sizeof(TCPCharDriver)); if (!s) goto fail;#ifndef _WIN32 if (is_unix) fd = socket(PF_UNIX, SOCK_STREAM, 0); else#endif fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) goto fail; if (!is_waitconnect) socket_set_nonblock(fd); s->connected = 0; s->fd = -1; s->listen_fd = -1; s->is_unix = is_unix; s->do_nodelay = do_nodelay && !is_unix; chr->opaque = s; chr->chr_write = tcp_chr_write; chr->chr_close = tcp_chr_close; if (is_listen) { /* allow fast reuse */#ifndef _WIN32 if (is_unix) { char path[109]; strncpy(path, uaddr.sun_path, 108); path[108] = 0; unlink(path); } else#endif { val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); } ret = bind(fd, addr, addrlen); 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -