aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2009-01-08 19:18:21 +0000
committeraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2009-01-08 19:18:21 +0000
commit8a83e031bcc60c0fbfee518a265ee8b7c12c1e36 (patch)
tree1f00bc88e1b58a29934a5b60294d6bac832c7566
parent383589c12e3f2e0e34058be7901ba080dd73722c (diff)
downloadslirp-8a83e031bcc60c0fbfee518a265ee8b7c12c1e36.zip
slirp-8a83e031bcc60c0fbfee518a265ee8b7c12c1e36.tar.gz
slirp-8a83e031bcc60c0fbfee518a265ee8b7c12c1e36.tar.bz2
Redirect slirp traffic to/from qemu character device (Gleb Natapov)
Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6240 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--libslirp.h5
-rw-r--r--main.h1
-rw-r--r--misc.c2
-rw-r--r--sbuf.c2
-rw-r--r--slirp.c61
-rw-r--r--socket.c99
-rw-r--r--socket.h2
-rw-r--r--tcp_subr.c5
8 files changed, 153 insertions, 24 deletions
diff --git a/libslirp.h b/libslirp.h
index 792c9a8..24cc8b0 100644
--- a/libslirp.h
+++ b/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/main.h b/main.h
index 7c87c10..b02c879 100644
--- a/main.h
+++ b/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/misc.c b/misc.c
index f516929..152f416 100644
--- a/misc.c
+++ b/misc.c
@@ -157,7 +157,7 @@ int 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/sbuf.c b/sbuf.c
index ac2fbd8..ab6d270 100644
--- a/sbuf.c
+++ b/sbuf.c
@@ -100,7 +100,7 @@ struct mbuf *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.c b/slirp.c
index 96a8c2d..490ab26 100644
--- a/slirp.c
+++ b/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 */
@@ -738,9 +739,67 @@ int slirp_redir(int is_udp, int host_port, struct in_addr guest_addr,
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/socket.c b/socket.c
index 74560d7..f627eb0 100644
--- a/socket.c
+++ b/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);
@@ -83,29 +83,21 @@ void sofree(so) struct socket *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;
@@ -147,6 +139,31 @@ int soread(so) struct socket *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);
@@ -195,6 +212,48 @@ int soread(so) struct socket *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
*
@@ -244,8 +303,8 @@ int sosendoob(so) struct socket *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,
@@ -270,7 +329,7 @@ int sosendoob(so) struct socket *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"));
@@ -345,7 +404,7 @@ int sowrite(so) struct socket *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))
@@ -363,7 +422,7 @@ int sowrite(so) struct socket *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/socket.h b/socket.h
index 9645577..3c5d625 100644
--- a/socket.h
+++ b/socket.h
@@ -95,5 +95,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/tcp_subr.c b/tcp_subr.c
index d41ef44..86946a9 100644
--- a/tcp_subr.c
+++ b/tcp_subr.c
@@ -1271,6 +1271,11 @@ int tcp_ctl(so) struct socket *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;
}