diff options
author | aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162> | 2009-01-08 19:18:21 +0000 |
---|---|---|
committer | aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162> | 2009-01-08 19:18:21 +0000 |
commit | 8a83e031bcc60c0fbfee518a265ee8b7c12c1e36 (patch) | |
tree | 1f00bc88e1b58a29934a5b60294d6bac832c7566 | |
parent | 383589c12e3f2e0e34058be7901ba080dd73722c (diff) | |
download | slirp-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.h | 5 | ||||
-rw-r--r-- | main.h | 1 | ||||
-rw-r--r-- | misc.c | 2 | ||||
-rw-r--r-- | sbuf.c | 2 | ||||
-rw-r--r-- | slirp.c | 61 | ||||
-rw-r--r-- | socket.c | 99 | ||||
-rw-r--r-- | socket.h | 2 | ||||
-rw-r--r-- | tcp_subr.c | 5 |
8 files changed, 153 insertions, 24 deletions
@@ -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 } @@ -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); @@ -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; } @@ -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) { /* @@ -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)); +} @@ -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; } @@ -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_ */ @@ -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; } |