Commit e1c5a2b33409b9795fa58bf389eac855981330a5
1 parent
4dda4063
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
Showing
8 changed files
with
156 additions
and
25 deletions
slirp/libslirp.h
| @@ -20,13 +20,16 @@ void slirp_output(const uint8_t *pkt, int pkt_len); | @@ -20,13 +20,16 @@ void slirp_output(const uint8_t *pkt, int pkt_len); | ||
| 20 | 20 | ||
| 21 | int slirp_redir(int is_udp, int host_port, | 21 | int slirp_redir(int is_udp, int host_port, |
| 22 | struct in_addr guest_addr, int guest_port); | 22 | struct in_addr guest_addr, int guest_port); |
| 23 | -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, | 23 | +int slirp_add_exec(int do_pty, const void *args, int addr_low_byte, |
| 24 | int guest_port); | 24 | int guest_port); |
| 25 | 25 | ||
| 26 | extern const char *tftp_prefix; | 26 | extern const char *tftp_prefix; |
| 27 | extern char slirp_hostname[33]; | 27 | extern char slirp_hostname[33]; |
| 28 | 28 | ||
| 29 | void slirp_stats(void); | 29 | void slirp_stats(void); |
| 30 | +void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf, | ||
| 31 | + int size); | ||
| 32 | +size_t slirp_socket_can_recv(int addr_low_byte, int guest_port); | ||
| 30 | 33 | ||
| 31 | #ifdef __cplusplus | 34 | #ifdef __cplusplus |
| 32 | } | 35 | } |
slirp/main.h
| @@ -51,3 +51,4 @@ extern uint8_t client_ethaddr[6]; | @@ -51,3 +51,4 @@ extern uint8_t client_ethaddr[6]; | ||
| 51 | #endif | 51 | #endif |
| 52 | 52 | ||
| 53 | void if_encap(const uint8_t *ip_data, int ip_data_len); | 53 | void if_encap(const uint8_t *ip_data, int ip_data_len); |
| 54 | +ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags); |
slirp/misc.c
| @@ -169,7 +169,7 @@ add_exec(ex_ptr, do_pty, exec, addr, port) | @@ -169,7 +169,7 @@ add_exec(ex_ptr, do_pty, exec, addr, port) | ||
| 169 | (*ex_ptr)->ex_fport = port; | 169 | (*ex_ptr)->ex_fport = port; |
| 170 | (*ex_ptr)->ex_addr = addr; | 170 | (*ex_ptr)->ex_addr = addr; |
| 171 | (*ex_ptr)->ex_pty = do_pty; | 171 | (*ex_ptr)->ex_pty = do_pty; |
| 172 | - (*ex_ptr)->ex_exec = strdup(exec); | 172 | + (*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec); |
| 173 | (*ex_ptr)->ex_next = tmp_ptr; | 173 | (*ex_ptr)->ex_next = tmp_ptr; |
| 174 | return 0; | 174 | return 0; |
| 175 | } | 175 | } |
slirp/sbuf.c
| @@ -108,7 +108,7 @@ sbappend(so, m) | @@ -108,7 +108,7 @@ sbappend(so, m) | ||
| 108 | * ottherwise it'll arrive out of order, and hence corrupt | 108 | * ottherwise it'll arrive out of order, and hence corrupt |
| 109 | */ | 109 | */ |
| 110 | if (!so->so_rcv.sb_cc) | 110 | if (!so->so_rcv.sb_cc) |
| 111 | - ret = send(so->s, m->m_data, m->m_len, 0); | 111 | + ret = slirp_send(so, m->m_data, m->m_len, 0); |
| 112 | 112 | ||
| 113 | if (ret <= 0) { | 113 | if (ret <= 0) { |
| 114 | /* | 114 | /* |
slirp/slirp.c
| @@ -21,6 +21,7 @@ | @@ -21,6 +21,7 @@ | ||
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 22 | * THE SOFTWARE. | 22 | * THE SOFTWARE. |
| 23 | */ | 23 | */ |
| 24 | +#include "qemu-common.h" | ||
| 24 | #include "slirp.h" | 25 | #include "slirp.h" |
| 25 | 26 | ||
| 26 | /* host address */ | 27 | /* host address */ |
| @@ -736,9 +737,69 @@ int slirp_redir(int is_udp, int host_port, | @@ -736,9 +737,69 @@ int slirp_redir(int is_udp, int host_port, | ||
| 736 | return 0; | 737 | return 0; |
| 737 | } | 738 | } |
| 738 | 739 | ||
| 739 | -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, | 740 | +int slirp_add_exec(int do_pty, const void *args, int addr_low_byte, |
| 740 | int guest_port) | 741 | int guest_port) |
| 741 | { | 742 | { |
| 742 | return add_exec(&exec_list, do_pty, (char *)args, | 743 | return add_exec(&exec_list, do_pty, (char *)args, |
| 743 | addr_low_byte, htons(guest_port)); | 744 | addr_low_byte, htons(guest_port)); |
| 744 | } | 745 | } |
| 746 | + | ||
| 747 | +ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags) | ||
| 748 | +{ | ||
| 749 | + if (so->s == -1 && so->extra) { | ||
| 750 | + qemu_chr_write(so->extra, buf, len); | ||
| 751 | + return len; | ||
| 752 | + } | ||
| 753 | + | ||
| 754 | + return send(so->s, buf, len, flags); | ||
| 755 | +} | ||
| 756 | + | ||
| 757 | +static struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port) | ||
| 758 | +{ | ||
| 759 | + struct socket *so; | ||
| 760 | + | ||
| 761 | + for (so = tcb.so_next; so != &tcb; so = so->so_next) { | ||
| 762 | + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == | ||
| 763 | + special_addr.s_addr | ||
| 764 | + && (ntohl(so->so_faddr.s_addr) & 0xff) == | ||
| 765 | + addr_low_byte | ||
| 766 | + && htons(so->so_fport) == guest_port) | ||
| 767 | + return so; | ||
| 768 | + } | ||
| 769 | + | ||
| 770 | + return NULL; | ||
| 771 | +} | ||
| 772 | + | ||
| 773 | +size_t slirp_socket_can_recv(int addr_low_byte, int guest_port) | ||
| 774 | +{ | ||
| 775 | + struct iovec iov[2]; | ||
| 776 | + struct socket *so; | ||
| 777 | + | ||
| 778 | + if (!link_up) | ||
| 779 | + return 0; | ||
| 780 | + | ||
| 781 | + so = slirp_find_ctl_socket(addr_low_byte, guest_port); | ||
| 782 | + | ||
| 783 | + if (!so || so->so_state & SS_NOFDREF) | ||
| 784 | + return 0; | ||
| 785 | + | ||
| 786 | + if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) | ||
| 787 | + return 0; | ||
| 788 | + | ||
| 789 | + return sopreprbuf(so, iov, NULL); | ||
| 790 | +} | ||
| 791 | + | ||
| 792 | +void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf, | ||
| 793 | + int size) | ||
| 794 | +{ | ||
| 795 | + int ret; | ||
| 796 | + struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port); | ||
| 797 | + | ||
| 798 | + if (!so) | ||
| 799 | + return; | ||
| 800 | + | ||
| 801 | + ret = soreadbuf(so, buf, size); | ||
| 802 | + | ||
| 803 | + if (ret > 0) | ||
| 804 | + tcp_output(sototcpcb(so)); | ||
| 805 | +} |
slirp/socket.c
| @@ -5,13 +5,13 @@ | @@ -5,13 +5,13 @@ | ||
| 5 | * terms and conditions of the copyright. | 5 | * terms and conditions of the copyright. |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | +#include "qemu-common.h" | ||
| 8 | #define WANT_SYS_IOCTL_H | 9 | #define WANT_SYS_IOCTL_H |
| 9 | #include <slirp.h> | 10 | #include <slirp.h> |
| 10 | #include "ip_icmp.h" | 11 | #include "ip_icmp.h" |
| 11 | #ifdef __sun__ | 12 | #ifdef __sun__ |
| 12 | #include <sys/filio.h> | 13 | #include <sys/filio.h> |
| 13 | #endif | 14 | #endif |
| 14 | -#include "qemu-common.h" | ||
| 15 | 15 | ||
| 16 | static void sofcantrcvmore(struct socket *so); | 16 | static void sofcantrcvmore(struct socket *so); |
| 17 | static void sofcantsendmore(struct socket *so); | 17 | static void sofcantsendmore(struct socket *so); |
| @@ -91,31 +91,21 @@ sofree(so) | @@ -91,31 +91,21 @@ sofree(so) | ||
| 91 | free(so); | 91 | free(so); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | -/* | ||
| 95 | - * Read from so's socket into sb_snd, updating all relevant sbuf fields | ||
| 96 | - * NOTE: This will only be called if it is select()ed for reading, so | ||
| 97 | - * a read() of 0 (or less) means it's disconnected | ||
| 98 | - */ | ||
| 99 | -int | ||
| 100 | -soread(so) | ||
| 101 | - struct socket *so; | 94 | +size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np) |
| 102 | { | 95 | { |
| 103 | - int n, nn, lss, total; | 96 | + int n, lss, total; |
| 104 | struct sbuf *sb = &so->so_snd; | 97 | struct sbuf *sb = &so->so_snd; |
| 105 | int len = sb->sb_datalen - sb->sb_cc; | 98 | int len = sb->sb_datalen - sb->sb_cc; |
| 106 | - struct iovec iov[2]; | ||
| 107 | int mss = so->so_tcpcb->t_maxseg; | 99 | int mss = so->so_tcpcb->t_maxseg; |
| 108 | 100 | ||
| 109 | - DEBUG_CALL("soread"); | 101 | + DEBUG_CALL("sopreprbuf"); |
| 110 | DEBUG_ARG("so = %lx", (long )so); | 102 | DEBUG_ARG("so = %lx", (long )so); |
| 111 | 103 | ||
| 112 | - /* | ||
| 113 | - * No need to check if there's enough room to read. | ||
| 114 | - * soread wouldn't have been called if there weren't | ||
| 115 | - */ | ||
| 116 | - | ||
| 117 | len = sb->sb_datalen - sb->sb_cc; | 104 | len = sb->sb_datalen - sb->sb_cc; |
| 118 | 105 | ||
| 106 | + if (len <= 0) | ||
| 107 | + return 0; | ||
| 108 | + | ||
| 119 | iov[0].iov_base = sb->sb_wptr; | 109 | iov[0].iov_base = sb->sb_wptr; |
| 120 | iov[1].iov_base = NULL; | 110 | iov[1].iov_base = NULL; |
| 121 | iov[1].iov_len = 0; | 111 | iov[1].iov_len = 0; |
| @@ -156,6 +146,33 @@ soread(so) | @@ -156,6 +146,33 @@ soread(so) | ||
| 156 | n = 1; | 146 | n = 1; |
| 157 | } | 147 | } |
| 158 | } | 148 | } |
| 149 | + if (np) | ||
| 150 | + *np = n; | ||
| 151 | + | ||
| 152 | + return iov[0].iov_len + (n - 1) * iov[1].iov_len; | ||
| 153 | +} | ||
| 154 | + | ||
| 155 | +/* | ||
| 156 | + * Read from so's socket into sb_snd, updating all relevant sbuf fields | ||
| 157 | + * NOTE: This will only be called if it is select()ed for reading, so | ||
| 158 | + * a read() of 0 (or less) means it's disconnected | ||
| 159 | + */ | ||
| 160 | +int | ||
| 161 | +soread(so) | ||
| 162 | + struct socket *so; | ||
| 163 | +{ | ||
| 164 | + int n, nn; | ||
| 165 | + struct sbuf *sb = &so->so_snd; | ||
| 166 | + struct iovec iov[2]; | ||
| 167 | + | ||
| 168 | + DEBUG_CALL("soread"); | ||
| 169 | + DEBUG_ARG("so = %lx", (long )so); | ||
| 170 | + | ||
| 171 | + /* | ||
| 172 | + * No need to check if there's enough room to read. | ||
| 173 | + * soread wouldn't have been called if there weren't | ||
| 174 | + */ | ||
| 175 | + sopreprbuf(so, iov, &n); | ||
| 159 | 176 | ||
| 160 | #ifdef HAVE_READV | 177 | #ifdef HAVE_READV |
| 161 | nn = readv(so->s, (struct iovec *)iov, n); | 178 | nn = readv(so->s, (struct iovec *)iov, n); |
| @@ -202,6 +219,48 @@ soread(so) | @@ -202,6 +219,48 @@ soread(so) | ||
| 202 | return nn; | 219 | return nn; |
| 203 | } | 220 | } |
| 204 | 221 | ||
| 222 | +int soreadbuf(struct socket *so, const char *buf, int size) | ||
| 223 | +{ | ||
| 224 | + int n, nn, copy = size; | ||
| 225 | + struct sbuf *sb = &so->so_snd; | ||
| 226 | + struct iovec iov[2]; | ||
| 227 | + | ||
| 228 | + DEBUG_CALL("soreadbuf"); | ||
| 229 | + DEBUG_ARG("so = %lx", (long )so); | ||
| 230 | + | ||
| 231 | + /* | ||
| 232 | + * No need to check if there's enough room to read. | ||
| 233 | + * soread wouldn't have been called if there weren't | ||
| 234 | + */ | ||
| 235 | + if (sopreprbuf(so, iov, &n) < size) | ||
| 236 | + goto err; | ||
| 237 | + | ||
| 238 | + nn = MIN(iov[0].iov_len, copy); | ||
| 239 | + memcpy(iov[0].iov_base, buf, nn); | ||
| 240 | + | ||
| 241 | + copy -= nn; | ||
| 242 | + buf += nn; | ||
| 243 | + | ||
| 244 | + if (copy == 0) | ||
| 245 | + goto done; | ||
| 246 | + | ||
| 247 | + memcpy(iov[1].iov_base, buf, copy); | ||
| 248 | + | ||
| 249 | +done: | ||
| 250 | + /* Update fields */ | ||
| 251 | + sb->sb_cc += size; | ||
| 252 | + sb->sb_wptr += size; | ||
| 253 | + if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) | ||
| 254 | + sb->sb_wptr -= sb->sb_datalen; | ||
| 255 | + return size; | ||
| 256 | +err: | ||
| 257 | + | ||
| 258 | + sofcantrcvmore(so); | ||
| 259 | + tcp_sockclosed(sototcpcb(so)); | ||
| 260 | + fprintf(stderr, "soreadbuf buffer to small"); | ||
| 261 | + return -1; | ||
| 262 | +} | ||
| 263 | + | ||
| 205 | /* | 264 | /* |
| 206 | * Get urgent data | 265 | * Get urgent data |
| 207 | * | 266 | * |
| @@ -255,7 +314,7 @@ sosendoob(so) | @@ -255,7 +314,7 @@ sosendoob(so) | ||
| 255 | 314 | ||
| 256 | if (sb->sb_rptr < sb->sb_wptr) { | 315 | if (sb->sb_rptr < sb->sb_wptr) { |
| 257 | /* We can send it directly */ | 316 | /* We can send it directly */ |
| 258 | - n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ | 317 | + n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ |
| 259 | so->so_urgc -= n; | 318 | so->so_urgc -= n; |
| 260 | 319 | ||
| 261 | DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); | 320 | DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); |
| @@ -276,7 +335,7 @@ sosendoob(so) | @@ -276,7 +335,7 @@ sosendoob(so) | ||
| 276 | so->so_urgc -= n; | 335 | so->so_urgc -= n; |
| 277 | len += n; | 336 | len += n; |
| 278 | } | 337 | } |
| 279 | - n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ | 338 | + n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ |
| 280 | #ifdef DEBUG | 339 | #ifdef DEBUG |
| 281 | if (n != len) | 340 | if (n != len) |
| 282 | DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); | 341 | DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); |
| @@ -348,7 +407,7 @@ sowrite(so) | @@ -348,7 +407,7 @@ sowrite(so) | ||
| 348 | 407 | ||
| 349 | DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); | 408 | DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); |
| 350 | #else | 409 | #else |
| 351 | - nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0); | 410 | + nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0); |
| 352 | #endif | 411 | #endif |
| 353 | /* This should never happen, but people tell me it does *shrug* */ | 412 | /* This should never happen, but people tell me it does *shrug* */ |
| 354 | if (nn < 0 && (errno == EAGAIN || errno == EINTR)) | 413 | if (nn < 0 && (errno == EAGAIN || errno == EINTR)) |
| @@ -365,7 +424,7 @@ sowrite(so) | @@ -365,7 +424,7 @@ sowrite(so) | ||
| 365 | #ifndef HAVE_READV | 424 | #ifndef HAVE_READV |
| 366 | if (n == 2 && nn == iov[0].iov_len) { | 425 | if (n == 2 && nn == iov[0].iov_len) { |
| 367 | int ret; | 426 | int ret; |
| 368 | - ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0); | 427 | + ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0); |
| 369 | if (ret > 0) | 428 | if (ret > 0) |
| 370 | nn += ret; | 429 | nn += ret; |
| 371 | } | 430 | } |
slirp/socket.h
| @@ -87,5 +87,7 @@ void soisfconnecting _P((register struct socket *)); | @@ -87,5 +87,7 @@ void soisfconnecting _P((register struct socket *)); | ||
| 87 | void soisfconnected _P((register struct socket *)); | 87 | void soisfconnected _P((register struct socket *)); |
| 88 | void soisfdisconnected _P((struct socket *)); | 88 | void soisfdisconnected _P((struct socket *)); |
| 89 | void sofwdrain _P((struct socket *)); | 89 | void sofwdrain _P((struct socket *)); |
| 90 | +size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np); | ||
| 91 | +int soreadbuf(struct socket *so, const char *buf, int size); | ||
| 90 | 92 | ||
| 91 | #endif /* _SOCKET_H_ */ | 93 | #endif /* _SOCKET_H_ */ |
slirp/tcp_subr.c
| @@ -1281,6 +1281,11 @@ tcp_ctl(so) | @@ -1281,6 +1281,11 @@ tcp_ctl(so) | ||
| 1281 | for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { | 1281 | for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { |
| 1282 | if (ex_ptr->ex_fport == so->so_fport && | 1282 | if (ex_ptr->ex_fport == so->so_fport && |
| 1283 | command == ex_ptr->ex_addr) { | 1283 | command == ex_ptr->ex_addr) { |
| 1284 | + if (ex_ptr->ex_pty == 3) { | ||
| 1285 | + so->s = -1; | ||
| 1286 | + so->extra = ex_ptr->ex_exec; | ||
| 1287 | + return 1; | ||
| 1288 | + } | ||
| 1284 | do_pty = ex_ptr->ex_pty; | 1289 | do_pty = ex_ptr->ex_pty; |
| 1285 | goto do_exec; | 1290 | goto do_exec; |
| 1286 | } | 1291 | } |