From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LHJGF-0005xP-PW for qemu-devel@nongnu.org; Mon, 29 Dec 2008 09:38:27 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LHJGF-0005x0-CK for qemu-devel@nongnu.org; Mon, 29 Dec 2008 09:38:27 -0500 Received: from [199.232.76.173] (port=55401 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LHJGE-0005wu-TJ for qemu-devel@nongnu.org; Mon, 29 Dec 2008 09:38:26 -0500 Received: from mx2.redhat.com ([66.187.237.31]:51873) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LHJGE-0003XL-Ac for qemu-devel@nongnu.org; Mon, 29 Dec 2008 09:38:26 -0500 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id mBTEcPkd002046 for ; Mon, 29 Dec 2008 09:38:25 -0500 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id mBTEcOl5026273 for ; Mon, 29 Dec 2008 09:38:24 -0500 Received: from dhcp-1-237.tlv.redhat.com (dhcp-1-237.tlv.redhat.com [10.35.1.237]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id mBTEcNsn012066 for ; Mon, 29 Dec 2008 09:38:23 -0500 Received: from dhcp-1-237.tlv.redhat.com (localhost [127.0.0.1]) by dhcp-1-237.tlv.redhat.com (Postfix) with ESMTP id 60C2018D43A for ; Mon, 29 Dec 2008 16:39:28 +0200 (IST) From: Gleb Natapov Date: Mon, 29 Dec 2008 16:39:28 +0200 Message-ID: <20081229143928.24671.98759.stgit@dhcp-1-237.tlv.redhat.com> In-Reply-To: <20081229143922.24671.86727.stgit@dhcp-1-237.tlv.redhat.com> References: <20081229143922.24671.86727.stgit@dhcp-1-237.tlv.redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] [PATCH 1/2] Redirect slirp traffic to/from qemu character device. Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Signed-off-by: Gleb Natapov --- slirp/libslirp.h | 5 ++- slirp/main.h | 1 + slirp/misc.c | 2 + slirp/sbuf.c | 2 + slirp/slirp.c | 57 +++++++++++++++++++++++++++++++ slirp/socket.c | 99 +++++++++++++++++++++++++++++++++++++++++++----------- slirp/socket.h | 2 + slirp/tcp_subr.c | 5 +++ 8 files changed, 149 insertions(+), 24 deletions(-) diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 7e4cfa9..16a817a 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -20,13 +20,16 @@ void slirp_output(const uint8_t *pkt, int pkt_len); int slirp_redir(int is_udp, int host_port, struct in_addr guest_addr, int guest_port); -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, +int slirp_add_exec(int do_pty, const void *args, int addr_low_byte, int guest_port); extern const char *tftp_prefix; extern char slirp_hostname[33]; void slirp_stats(void); +void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf, + int size); +size_t slirp_socket_can_recv(int addr_low_byte, int guest_port); #ifdef __cplusplus } diff --git a/slirp/main.h b/slirp/main.h index c01adda..3ef2996 100644 --- a/slirp/main.h +++ b/slirp/main.h @@ -51,3 +51,4 @@ extern uint8_t client_ethaddr[6]; #endif void if_encap(const uint8_t *ip_data, int ip_data_len); +ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags); diff --git a/slirp/misc.c b/slirp/misc.c index 9ff3176..1ec8b55 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -169,7 +169,7 @@ add_exec(ex_ptr, do_pty, exec, addr, port) (*ex_ptr)->ex_fport = port; (*ex_ptr)->ex_addr = addr; (*ex_ptr)->ex_pty = do_pty; - (*ex_ptr)->ex_exec = strdup(exec); + (*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec); (*ex_ptr)->ex_next = tmp_ptr; return 0; } diff --git a/slirp/sbuf.c b/slirp/sbuf.c index b0e0838..2e6e2b2 100644 --- a/slirp/sbuf.c +++ b/slirp/sbuf.c @@ -108,7 +108,7 @@ sbappend(so, m) * ottherwise it'll arrive out of order, and hence corrupt */ if (!so->so_rcv.sb_cc) - ret = send(so->s, m->m_data, m->m_len, 0); + ret = slirp_send(so, m->m_data, m->m_len, 0); if (ret <= 0) { /* diff --git a/slirp/slirp.c b/slirp/slirp.c index 17b40e2..378d3e8 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -736,9 +736,64 @@ int slirp_redir(int is_udp, int host_port, return 0; } -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, +int slirp_add_exec(int do_pty, const void *args, int addr_low_byte, int guest_port) { return add_exec(&exec_list, do_pty, (char *)args, addr_low_byte, htons(guest_port)); } + +ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags) +{ + if (so->s == -1) { + qemu_chr_write(so->extra, buf, len); + return len; + } + + return send(so->s, buf, len, flags); +} + +static struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port) +{ + struct socket *so; + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == + special_addr.s_addr + && (ntohl(so->so_faddr.s_addr) & 0xff) == + addr_low_byte + && htons(so->so_fport) == guest_port) + return so; + } + + return NULL; +} + +size_t slirp_socket_can_recv(int addr_low_byte, int guest_port) +{ + struct iovec iov[2]; + struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port); + + if (!so || so->so_state & SS_NOFDREF) + return 0; + + if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) + return 0; + + return sopreprbuf(so, iov, NULL); +} + +void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf, + int size) +{ + int ret; + struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port); + + if (!so) + return; + + ret = soreadbuf(so, buf, size); + + if (ret > 0) + tcp_output(sototcpcb(so)); +} diff --git a/slirp/socket.c b/slirp/socket.c index 00694e2..a45be82 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -91,31 +91,21 @@ sofree(so) free(so); } -/* - * Read from so's socket into sb_snd, updating all relevant sbuf fields - * NOTE: This will only be called if it is select()ed for reading, so - * a read() of 0 (or less) means it's disconnected - */ -int -soread(so) - struct socket *so; +size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np) { - int n, nn, lss, total; + int n, lss, total; struct sbuf *sb = &so->so_snd; int len = sb->sb_datalen - sb->sb_cc; - struct iovec iov[2]; int mss = so->so_tcpcb->t_maxseg; - DEBUG_CALL("soread"); + DEBUG_CALL("sopreprbuf"); DEBUG_ARG("so = %lx", (long )so); - /* - * No need to check if there's enough room to read. - * soread wouldn't have been called if there weren't - */ - len = sb->sb_datalen - sb->sb_cc; + if (len <= 0) + return 0; + iov[0].iov_base = sb->sb_wptr; iov[1].iov_base = NULL; iov[1].iov_len = 0; @@ -156,6 +146,33 @@ soread(so) n = 1; } } + if (np) + *np = n; + + return iov[0].iov_len + (n - 1) * iov[1].iov_len; +} + +/* + * Read from so's socket into sb_snd, updating all relevant sbuf fields + * NOTE: This will only be called if it is select()ed for reading, so + * a read() of 0 (or less) means it's disconnected + */ +int +soread(so) + struct socket *so; +{ + int n, nn; + struct sbuf *sb = &so->so_snd; + struct iovec iov[2]; + + DEBUG_CALL("soread"); + DEBUG_ARG("so = %lx", (long )so); + + /* + * No need to check if there's enough room to read. + * soread wouldn't have been called if there weren't + */ + sopreprbuf(so, iov, &n); #ifdef HAVE_READV nn = readv(so->s, (struct iovec *)iov, n); @@ -202,6 +219,48 @@ soread(so) return nn; } +int soreadbuf(struct socket *so, const char *buf, int size) +{ + int n, nn, copy = size; + struct sbuf *sb = &so->so_snd; + struct iovec iov[2]; + + DEBUG_CALL("soreadbuf"); + DEBUG_ARG("so = %lx", (long )so); + + /* + * No need to check if there's enough room to read. + * soread wouldn't have been called if there weren't + */ + if (sopreprbuf(so, iov, &n) < size) + goto err; + + nn = MIN(iov[0].iov_len, copy); + memcpy(iov[0].iov_base, buf, nn); + + copy -= nn; + buf += nn; + + if (copy == 0) + goto done; + + memcpy(iov[1].iov_base, buf, copy); + +done: + /* Update fields */ + sb->sb_cc += size; + sb->sb_wptr += size; + if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_wptr -= sb->sb_datalen; + return size; +err: + + sofcantrcvmore(so); + tcp_sockclosed(sototcpcb(so)); + fprintf(stderr, "soreadbuf buffer to small"); + return -1; +} + /* * Get urgent data * @@ -255,7 +314,7 @@ sosendoob(so) if (sb->sb_rptr < sb->sb_wptr) { /* We can send it directly */ - n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ + n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ so->so_urgc -= n; DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); @@ -276,7 +335,7 @@ sosendoob(so) so->so_urgc -= n; len += n; } - n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ + n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ #ifdef DEBUG if (n != len) DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); @@ -348,7 +407,7 @@ sowrite(so) DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #else - nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0); + nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0); #endif /* This should never happen, but people tell me it does *shrug* */ if (nn < 0 && (errno == EAGAIN || errno == EINTR)) @@ -365,7 +424,7 @@ sowrite(so) #ifndef HAVE_READV if (n == 2 && nn == iov[0].iov_len) { int ret; - ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0); + ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0); if (ret > 0) nn += ret; } diff --git a/slirp/socket.h b/slirp/socket.h index 5edea90..72b473d 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -87,5 +87,7 @@ void soisfconnecting _P((register struct socket *)); void soisfconnected _P((register struct socket *)); void soisfdisconnected _P((struct socket *)); void sofwdrain _P((struct socket *)); +size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np); +int soreadbuf(struct socket *so, const char *buf, int size); #endif /* _SOCKET_H_ */ diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index bce07a6..12abebe 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -1281,6 +1281,11 @@ tcp_ctl(so) for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if (ex_ptr->ex_fport == so->so_fport && command == ex_ptr->ex_addr) { + if (ex_ptr->ex_pty == 3) { + so->s = -1; + so->extra = ex_ptr->ex_exec; + return 1; + } do_pty = ex_ptr->ex_pty; goto do_exec; }