qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Gleb Natapov <gleb@redhat.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH v3 1/5] Redirect slirp traffic to/from qemu character device.
Date: Thu, 08 Jan 2009 11:55:39 +0200	[thread overview]
Message-ID: <20090108095538.12548.13695.stgit@dhcp-1-237.tlv.redhat.com> (raw)
In-Reply-To: <20090108095533.12548.8211.stgit@dhcp-1-237.tlv.redhat.com>

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---

 slirp/libslirp.h |    5 ++-
 slirp/main.h     |    1 +
 slirp/misc.c     |    2 +
 slirp/sbuf.c     |    2 +
 slirp/slirp.c    |   63 +++++++++++++++++++++++++++++++++-
 slirp/socket.c   |  101 +++++++++++++++++++++++++++++++++++++++++++-----------
 slirp/socket.h   |    2 +
 slirp/tcp_subr.c |    5 +++
 8 files changed, 156 insertions(+), 25 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..f6f94e4 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -21,6 +21,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include "qemu-common.h"
 #include "slirp.h"
 
 /* host address */
@@ -736,9 +737,69 @@ 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 && so->extra) {
+		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;
+
+    if (!link_up)
+        return 0;
+
+	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..9def541 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -5,13 +5,13 @@
  * terms and conditions of the copyright.
  */
 
+#include "qemu-common.h"
 #define WANT_SYS_IOCTL_H
 #include <slirp.h>
 #include "ip_icmp.h"
 #ifdef __sun__
 #include <sys/filio.h>
 #endif
-#include "qemu-common.h"
 
 static void sofcantrcvmore(struct socket *so);
 static void sofcantsendmore(struct socket *so);
@@ -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;
 			}

  reply	other threads:[~2009-01-08  9:54 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-08  9:55 [Qemu-devel] [PATCH v3 0/5] Marry slirp and qemu character device Gleb Natapov
2009-01-08  9:55 ` Gleb Natapov [this message]
2009-01-08  9:55 ` [Qemu-devel] [PATCH v3 2/5] Add vmchannel command line option Gleb Natapov
2009-01-08 19:21   ` Anthony Liguori
2009-01-08 19:35     ` Daniel P. Berrange
2009-01-08 19:55       ` Anthony Liguori
2009-01-08  9:55 ` [Qemu-devel] [PATCH v3 3/5] Add slirp_restrict option Gleb Natapov
2009-01-08  9:55 ` [Qemu-devel] [PATCH v3 4/5] Add "restrict" and "ip" option to "user" net option Gleb Natapov
2009-01-08  9:55 ` [Qemu-devel] [PATCH v3 5/5] Add support for vmchannel socket migration Gleb Natapov
2009-01-08 19:27 ` [Qemu-devel] [PATCH v3 0/5] Marry slirp and qemu character device Anthony Liguori
2009-01-08 21:14   ` Gleb Natapov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090108095538.12548.13695.stgit@dhcp-1-237.tlv.redhat.com \
    --to=gleb@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).