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 | 20 | |
21 | 21 | int slirp_redir(int is_udp, int host_port, |
22 | 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 | 24 | int guest_port); |
25 | 25 | |
26 | 26 | extern const char *tftp_prefix; |
27 | 27 | extern char slirp_hostname[33]; |
28 | 28 | |
29 | 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 | 34 | #ifdef __cplusplus |
32 | 35 | } | ... | ... |
slirp/main.h
slirp/misc.c
... | ... | @@ -169,7 +169,7 @@ add_exec(ex_ptr, do_pty, exec, addr, port) |
169 | 169 | (*ex_ptr)->ex_fport = port; |
170 | 170 | (*ex_ptr)->ex_addr = addr; |
171 | 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 | 173 | (*ex_ptr)->ex_next = tmp_ptr; |
174 | 174 | return 0; |
175 | 175 | } | ... | ... |
slirp/sbuf.c
... | ... | @@ -108,7 +108,7 @@ sbappend(so, m) |
108 | 108 | * ottherwise it'll arrive out of order, and hence corrupt |
109 | 109 | */ |
110 | 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 | 113 | if (ret <= 0) { |
114 | 114 | /* | ... | ... |
slirp/slirp.c
... | ... | @@ -21,6 +21,7 @@ |
21 | 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | 22 | * THE SOFTWARE. |
23 | 23 | */ |
24 | +#include "qemu-common.h" | |
24 | 25 | #include "slirp.h" |
25 | 26 | |
26 | 27 | /* host address */ |
... | ... | @@ -736,9 +737,69 @@ int slirp_redir(int is_udp, int host_port, |
736 | 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 | 741 | int guest_port) |
741 | 742 | { |
742 | 743 | return add_exec(&exec_list, do_pty, (char *)args, |
743 | 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 | 5 | * terms and conditions of the copyright. |
6 | 6 | */ |
7 | 7 | |
8 | +#include "qemu-common.h" | |
8 | 9 | #define WANT_SYS_IOCTL_H |
9 | 10 | #include <slirp.h> |
10 | 11 | #include "ip_icmp.h" |
11 | 12 | #ifdef __sun__ |
12 | 13 | #include <sys/filio.h> |
13 | 14 | #endif |
14 | -#include "qemu-common.h" | |
15 | 15 | |
16 | 16 | static void sofcantrcvmore(struct socket *so); |
17 | 17 | static void sofcantsendmore(struct socket *so); |
... | ... | @@ -91,31 +91,21 @@ sofree(so) |
91 | 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 | 97 | struct sbuf *sb = &so->so_snd; |
105 | 98 | int len = sb->sb_datalen - sb->sb_cc; |
106 | - struct iovec iov[2]; | |
107 | 99 | int mss = so->so_tcpcb->t_maxseg; |
108 | 100 | |
109 | - DEBUG_CALL("soread"); | |
101 | + DEBUG_CALL("sopreprbuf"); | |
110 | 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 | 104 | len = sb->sb_datalen - sb->sb_cc; |
118 | 105 | |
106 | + if (len <= 0) | |
107 | + return 0; | |
108 | + | |
119 | 109 | iov[0].iov_base = sb->sb_wptr; |
120 | 110 | iov[1].iov_base = NULL; |
121 | 111 | iov[1].iov_len = 0; |
... | ... | @@ -156,6 +146,33 @@ soread(so) |
156 | 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 | 177 | #ifdef HAVE_READV |
161 | 178 | nn = readv(so->s, (struct iovec *)iov, n); |
... | ... | @@ -202,6 +219,48 @@ soread(so) |
202 | 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 | 265 | * Get urgent data |
207 | 266 | * |
... | ... | @@ -255,7 +314,7 @@ sosendoob(so) |
255 | 314 | |
256 | 315 | if (sb->sb_rptr < sb->sb_wptr) { |
257 | 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 | 318 | so->so_urgc -= n; |
260 | 319 | |
261 | 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 | 335 | so->so_urgc -= n; |
277 | 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 | 339 | #ifdef DEBUG |
281 | 340 | if (n != len) |
282 | 341 | DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); |
... | ... | @@ -348,7 +407,7 @@ sowrite(so) |
348 | 407 | |
349 | 408 | DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); |
350 | 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 | 411 | #endif |
353 | 412 | /* This should never happen, but people tell me it does *shrug* */ |
354 | 413 | if (nn < 0 && (errno == EAGAIN || errno == EINTR)) |
... | ... | @@ -365,7 +424,7 @@ sowrite(so) |
365 | 424 | #ifndef HAVE_READV |
366 | 425 | if (n == 2 && nn == iov[0].iov_len) { |
367 | 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 | 428 | if (ret > 0) |
370 | 429 | nn += ret; |
371 | 430 | } | ... | ... |
slirp/socket.h
... | ... | @@ -87,5 +87,7 @@ void soisfconnecting _P((register struct socket *)); |
87 | 87 | void soisfconnected _P((register struct socket *)); |
88 | 88 | void soisfdisconnected _P((struct socket *)); |
89 | 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 | 93 | #endif /* _SOCKET_H_ */ | ... | ... |
slirp/tcp_subr.c
... | ... | @@ -1281,6 +1281,11 @@ tcp_ctl(so) |
1281 | 1281 | for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { |
1282 | 1282 | if (ex_ptr->ex_fport == so->so_fport && |
1283 | 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 | 1289 | do_pty = ex_ptr->ex_pty; |
1285 | 1290 | goto do_exec; |
1286 | 1291 | } | ... | ... |