mirror of https://github.com/xemu-project/xemu.git
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
This commit is contained in:
parent
4dda406337
commit
e1c5a2b334
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
/*
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
101
slirp/socket.c
101
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;
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue