Next set of updates from libslirp.

- Started implementing guest forwarding feature.
- Updated most of socket.h.
- Added if_mtu / if_mru handling.
- Cleaned up MIN / MAX defines.
This commit is contained in:
Volker Ruppert 2024-05-05 12:27:12 +02:00
parent b84ebf5dfc
commit a684734975
16 changed files with 445 additions and 333 deletions

View File

@ -35,5 +35,8 @@
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#endif

View File

@ -224,11 +224,15 @@ void slirp_pollfds_poll(Slirp *slirp, int select_error,
* guest network, to be interpreted by slirp. */
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
/* This is called by the application when a timer expires, if it provides
* the timer_new_opaque callback. It is not needed if the application only
* uses timer_new. */
void slirp_handle_timer(Slirp *slirp, SlirpTimerId id, void *cb_opaque);
/* These set up / remove port forwarding between a host port in the real world
* and the guest network. */
int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port, struct in_addr guest_addr, int guest_port);
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port);
@ -237,6 +241,14 @@ int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int slirp_add_exec(Slirp *slirp, const char *cmdline,
struct in_addr *guest_addr, int guest_port);
/* Set up port forwarding between a port in the guest network and a
* callback that will receive the data coming from the port */
int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
struct in_addr *guest_addr, int guest_port);
/* TODO: rather identify a guestfwd through an opaque pointer instead of through
* the guest_addr */
/* This is called by the application for a guestfwd, to determine how much data
* can be received by the forwarded port through a call to slirp_socket_recv. */
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
@ -246,10 +258,14 @@ size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
const uint8_t *buf, int size);
/* Remove entries added by slirp_add_exec, slirp_add_unix or slirp_add_guestfwd */
int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr,
int guest_port);
/* Return the version of the slirp implementation */
const char *slirp_version_string(void);
/* you must provide the following functions: */
void slirp_warning(const char *, void *);
#endif
#endif /* LIBSLIRP_H */

View File

@ -91,7 +91,7 @@ m_get(Slirp *slirp)
m->m_len = 0;
m->m_nextpkt = NULL;
m->m_prevpkt = NULL;
m->arp_requested = false;
m->resolution_requested = false;
m->expiration_date = (uint64_t)-1;
end_error:
DEBUG_ARG("m = %lx", (long )m);

View File

@ -79,14 +79,14 @@ struct mbuf {
char *m_data; /* Location of data */
int m_len; /* Amount of data in this mbuf */
Slirp *slirp;
bool arp_requested;
uint64_t expiration_date;
/* start of dynamic buffer area, must be last element */
union {
char m_dat[1]; /* ANSI don't like 0 sized arrays */
char *m_ext;
};
Slirp *slirp;
bool resolution_requested;
uint64_t expiration_date;
/* start of dynamic buffer area, must be last element */
union {
char m_dat[1]; /* ANSI don't like 0 sized arrays */
char *m_ext;
};
};
#define ifq_prev m_prev

View File

@ -4,16 +4,10 @@
*/
#include "slirp.h"
#include "libslirp.h"
#ifndef _WIN32
#include <dirent.h>
#endif
#if BX_NETWORKING && BX_NETMOD_SLIRP
#ifdef DEBUG
int slirp_debug = DBG_CALL|DBG_MISC|DBG_ERROR;
#ifndef _WIN32
#include <sys/un.h>
#endif
void slirp_insque(void *a, void *b)
@ -35,187 +29,66 @@ void slirp_remque(void *a)
element->qh_rlink = NULL;
}
int add_exec(struct gfwd_list **ex_ptr, const char *exec, struct in_addr addr, int port)
/* TODO: IPv6 */
struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb,
void *opaque, struct in_addr addr, int port)
{
struct gfwd_list *tmp_ptr;
struct gfwd_list *f = (struct gfwd_list *)malloc(sizeof(struct gfwd_list));
/* First, check if the port is "bound" */
for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
if (port == tmp_ptr->ex_fport &&
addr.s_addr == tmp_ptr->ex_addr.s_addr)
return -1;
}
f->write_cb = write_cb;
f->opaque = opaque;
f->ex_fport = port;
f->ex_addr = addr;
f->ex_next = *ex_ptr;
*ex_ptr = f;
tmp_ptr = *ex_ptr;
*ex_ptr = (struct gfwd_list *)malloc(sizeof(struct gfwd_list));
(*ex_ptr)->ex_fport = port;
(*ex_ptr)->ex_addr = addr;
(*ex_ptr)->ex_exec = strdup(exec);
(*ex_ptr)->ex_next = tmp_ptr;
return 0;
return f;
}
#ifdef _WIN32
struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
struct in_addr addr, int port)
{
struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
int
fork_exec(struct socket *so, const char *ex, int do_pty)
f->ex_exec = strdup(cmdline);
return f;
}
struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock,
struct in_addr addr, int port)
{
struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
f->ex_unix = strdup(unixsock);
return f;
}
int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port)
{
for (; *ex_ptr != NULL; ex_ptr = &((*ex_ptr)->ex_next)) {
struct gfwd_list *f = *ex_ptr;
if (f->ex_addr.s_addr == addr.s_addr && f->ex_fport == port) {
*ex_ptr = f->ex_next;
free(f->ex_exec);
free(f);
return 0;
}
}
return -1;
}
int fork_exec(struct socket *so, const char *ex)
{
/* not implemented */
return 0;
}
#else
/*
* XXX This is ugly
* We create and bind a socket, then fork off to another
* process, which connects to this socket, after which we
* exec the wanted program. If something (strange) happens,
* the accept() call could block us forever.
*
* do_pty = 0 Fork/exec inetd style
* do_pty = 1 Fork/exec using slirp.telnetd
* do_ptr = 2 Fork/exec using pty
*/
int
fork_exec(struct socket *so, const char *ex, int do_pty)
int open_unix(struct socket *so, const char *unixpath)
{
int s;
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
int opt;
const char *argv[256];
/* don't want to clobber the original */
char *bptr;
const char *curarg;
int c, i, ret;
pid_t pid;
DEBUG_CALL("fork_exec");
DEBUG_ARG("so = %lx", (long)so);
DEBUG_ARG("ex = %lx", (long)ex);
DEBUG_ARG("do_pty = %lx", (long)do_pty);
if (do_pty == 2) {
return 0;
} else {
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr.s_addr = INADDR_ANY;
if ((s = slirp_socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
listen(s, 1) < 0) {
#ifdef DEBUG
printf("Error: inet socket: %s\n", strerror(errno));
#endif
closesocket(s);
return 0;
}
}
pid = fork();
switch(pid) {
case -1:
#ifdef DEBUG
printf("Error: fork failed: %s\n", strerror(errno));
#endif
close(s);
return 0;
case 0:
setsid();
/* Set the DISPLAY */
getsockname(s, (struct sockaddr *)&addr, &addrlen);
close(s);
/*
* Connect to the socket
* XXX If any of these fail, we're in trouble!
*/
s = slirp_socket(AF_INET, SOCK_STREAM, 0);
addr.sin_addr = loopback_addr;
do {
ret = connect(s, (struct sockaddr *)&addr, addrlen);
} while (ret < 0 && errno == EINTR);
dup2(s, 0);
dup2(s, 1);
dup2(s, 2);
#ifdef __ANDROID__
{
/* No getdtablesize() on Android, we will use /proc/XXX/fd/ Linux virtual FS instead */
char proc_fd_path[256];
sprintf(proc_fd_path, "/proc/%u/fd", (unsigned)getpid());
DIR *proc_dir = opendir(proc_fd_path);
if (proc_dir) {
for (struct dirent *fd = readdir(proc_dir); fd != NULL; fd = readdir(proc_dir)) {
if (atoi(fd->d_name) >= 3 && fd->d_name[0] != '.') /* ".." and "." will return 0 anyway */
close(atoi(fd->d_name));
}
closedir(proc_dir);
}
}
#else
for (s = getdtablesize() - 1; s >= 3; s--)
close(s);
#endif
i = 0;
bptr = strdup(ex); /* No need to free() this */
if (do_pty == 1) {
/* Setup "slirp.telnetd -x" */
argv[i++] = "slirp.telnetd";
argv[i++] = "-x";
argv[i++] = bptr;
} else
do {
/* Change the string into argv[] */
curarg = bptr;
while (*bptr != ' ' && *bptr != (char)0)
bptr++;
c = *bptr;
*bptr++ = (char)0;
argv[i++] = strdup(curarg);
} while (c);
argv[i] = NULL;
execvp(argv[0], (char **)argv);
/* Ooops, failed, let's tell the user why */
fprintf(stderr, "Error: execvp of %s failed: %s\n",
argv[0], strerror(errno));
close(0); close(1); close(2); /* XXX */
exit(1);
default:
slirp_warning("qemu_add_child_watch(pid) not implemented", so->slirp->opaque);
/*
* XXX this could block us...
* XXX Should set a timer here, and if accept() doesn't
* return after X seconds, declare it a failure
* The only reason this will block forever is if socket()
* of connect() fail in the child process
*/
do {
so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
} while (so->s < 0 && errno == EINTR);
closesocket(s);
slirp_socket_set_fast_reuse(so->s);
opt = 1;
setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
slirp_set_nonblock(so->s);
/* Append the telnet options now */
if (so->so_m != NULL && do_pty == 1) {
sbappend(so, so->so_m);
so->so_m = NULL;
}
return 1;
}
/* not implemented */
return 0;
}
#endif
#endif

View File

@ -6,10 +6,15 @@
#ifndef MISC_H
#define MISC_H
#include "libslirp.h"
struct gfwd_list {
struct in_addr ex_addr; /* Server address */
int ex_fport; /* Port to telnet to */
const char *ex_exec; /* Command line of what to exec */
SlirpWriteCb write_cb;
void *opaque;
struct in_addr ex_addr; /* Server address */
int ex_fport; /* Port to telnet to */
char *ex_exec; /* Command line of what to exec */
char *ex_unix; /* unix socket */
struct gfwd_list *ex_next;
};
@ -53,7 +58,28 @@ void slirp_insque(void *a, void *b);
/* Remove element a from its queue */
void slirp_remque(void *a);
int add_exec(struct gfwd_list **, const char *, struct in_addr, int);
int fork_exec(struct socket *so, const char *ex, int do_pty);
/* Run the given command in the background, and expose its output as a socket */
int fork_exec(struct socket *so, const char *ex);
/* Create a Unix socket, and expose it as a socket */
int open_unix(struct socket *so, const char *unixsock);
/* Add a guest forward on the given address and port, with guest data being
* forwarded by calling write_cb */
struct gfwd_list *add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb,
void *opaque, struct in_addr addr, int port);
/* Run the given command in the backaground, and send its output to the guest on
* the given address and port */
struct gfwd_list *add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
struct in_addr addr, int port);
/* Create a Unix socket, and expose it to the guest on the given address and
* port */
struct gfwd_list *add_unix(struct gfwd_list **ex_ptr, const char *unixsock,
struct in_addr addr, int port);
/* Remove the guest forward bound to the given address and port */
int remove_guestfwd(struct gfwd_list **ex_ptr, struct in_addr addr, int port);
#endif

View File

@ -28,6 +28,15 @@
#if BX_NETWORKING && BX_NETMOD_SLIRP
#ifndef _WIN32
#include <net/if.h>
#endif
/* https://gitlab.freedesktop.org/slirp/libslirp/issues/18 */
#if defined(__NetBSD__) && defined(if_mtu)
#undef if_mtu
#endif
int slirp_debug;
/* host loopback address */
@ -250,7 +259,8 @@ Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque)
if (cfg->vdnssearch) {
translate_dnssearch(slirp, cfg->vdnssearch);
}
slirp->if_mtu = cfg->if_mtu == 0 ? IF_MTU_DEFAULT : cfg->if_mtu;
slirp->if_mru = cfg->if_mru == 0 ? IF_MRU_DEFAULT : cfg->if_mru;
slirp->disable_host_loopback = cfg->disable_host_loopback;
slirp->enable_emu = cfg->enable_emu;
@ -679,7 +689,7 @@ void slirp_pollfds_poll(Slirp *slirp, int select_error,
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
{
struct slirp_arphdr *ah = (struct slirp_arphdr *)(pkt + ETH_HLEN);
uint8_t arp_reply[max(ETH_HLEN + sizeof(struct slirp_arphdr), 64)];
uint8_t arp_reply[MAX(ETH_HLEN + sizeof(struct slirp_arphdr), 64)];
struct ethhdr *reh = (struct ethhdr *)arp_reply;
struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN);
int ar_op;
@ -774,26 +784,21 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
}
}
/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
* re-queued.
/* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no
* packet should be sent, 0 if the packet must be re-queued, 2 if the packet
* is ready to go.
*/
int if_encap(Slirp *slirp, struct mbuf *ifm)
static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
uint8_t ethaddr[ETH_ALEN])
{
uint8_t buf[1600];
struct ethhdr *eh = (struct ethhdr *)buf;
uint8_t ethaddr[ETH_ALEN];
const struct ip *iph = (const struct ip *)ifm->m_data;
if (ifm->m_len + ETH_HLEN > (int)sizeof(buf)) {
return 1;
}
if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
uint8_t arp_req[ETH_HLEN + sizeof(struct slirp_arphdr)];
struct ethhdr *reh = (struct ethhdr *)arp_req;
struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + ETH_HLEN);
uint8_t arp_req[2 + ETH_HLEN + sizeof(struct slirp_arphdr)];
struct ethhdr *reh = (struct ethhdr *)(arp_req + 2);
struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + 2 + ETH_HLEN);
if (!ifm->arp_requested) {
if (!ifm->resolution_requested) {
/* If the client addr is not known, send an ARP request */
memset(reh->h_dest, 0xff, ETH_ALEN);
memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
@ -818,23 +823,79 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
/* target IP */
rah->ar_tip = iph->ip_dst.s_addr;
slirp->client_ipaddr = iph->ip_dst;
slirp_send_packet_all(slirp, arp_req, sizeof(arp_req));
ifm->arp_requested = true;
slirp_send_packet_all(slirp, arp_req + 2, sizeof(arp_req) - 2);
ifm->resolution_requested = true;
/* Expire request and drop outgoing packet after 1 second */
ifm->expiration_date = slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
ifm->expiration_date =
slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
}
return 0;
} else {
memcpy(eh->h_dest, ethaddr, ETH_ALEN);
memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
/* XXX: not correct */
memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
eh->h_proto = htons(ETH_P_IP);
memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN);
/* Send this */
return 2;
}
}
/* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no
* packet should be sent, 0 if the packet must be re-queued, 2 if the packet
* is ready to go.
*/
static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
uint8_t ethaddr[ETH_ALEN])
{
slirp_warning("IPv6 packet not supported yet", slirp->opaque);
return 0;
}
/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
* re-queued.
*/
int if_encap(Slirp *slirp, struct mbuf *ifm)
{
uint8_t buf[IF_MTU_MAX + 100];
struct ethhdr *eh = (struct ethhdr *)(buf + 2);
uint8_t ethaddr[ETH_ALEN];
const struct ip *iph = (const struct ip *)ifm->m_data;
int ret;
// char ethaddr_str[ETH_ADDRSTRLEN];
if (ifm->m_len + ETH_HLEN > (int)sizeof(buf) - 2) {
return 1;
}
switch (iph->ip_v) {
case IPVERSION:
ret = if_encap4(slirp, ifm, eh, ethaddr);
if (ret < 2) {
return ret;
}
break;
case IP6VERSION:
ret = if_encap6(slirp, ifm, eh, ethaddr);
if (ret < 2) {
return ret;
}
break;
default:
slirp_warning("unknown protocol", slirp->opaque);
}
memcpy(eh->h_dest, ethaddr, ETH_ALEN);
DEBUG_ARG("src = %s", slirp_ether_ntoa(eh->h_source, ethaddr_str,
sizeof(ethaddr_str)));
DEBUG_ARG("dst = %s", slirp_ether_ntoa(eh->h_dest, ethaddr_str,
sizeof(ethaddr_str)));
memcpy(buf + 2 + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
slirp_send_packet_all(slirp, buf + 2, ifm->m_len + ETH_HLEN);
return 1;
}
/* Drop host forwarding rule, return 0 if found. */
@ -880,32 +941,99 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
return 0;
}
/* TODO: IPv6 */
static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr,
int guest_port)
{
struct gfwd_list *tmp_ptr;
if (!guest_addr->s_addr) {
guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
(htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
}
if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
slirp->vnetwork_addr.s_addr ||
guest_addr->s_addr == slirp->vhost_addr.s_addr ||
guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
return false;
}
/* check if the port is "bound" */
for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
if (guest_port == tmp_ptr->ex_fport &&
guest_addr->s_addr == tmp_ptr->ex_addr.s_addr)
return false;
}
return true;
}
int slirp_add_exec(Slirp *slirp, const char *cmdline,
struct in_addr *guest_addr, int guest_port)
{
if (!guest_addr->s_addr) {
guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
(htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
}
if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
slirp->vnetwork_addr.s_addr ||
guest_addr->s_addr == slirp->vhost_addr.s_addr ||
guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
if (!check_guestfwd(slirp, guest_addr, guest_port)) {
return -1;
}
return add_exec(&slirp->guestfwd_list, cmdline, *guest_addr,
htons(guest_port));
add_exec(&slirp->guestfwd_list, cmdline, *guest_addr, htons(guest_port));
return 0;
}
int slirp_add_unix(Slirp *slirp, const char *unixsock,
struct in_addr *guest_addr, int guest_port)
{
#ifndef _WIN32
if (!check_guestfwd(slirp, guest_addr, guest_port)) {
return -1;
}
add_unix(&slirp->guestfwd_list, unixsock, *guest_addr, htons(guest_port));
return 0;
#else
return -1;
#endif
}
int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
struct in_addr *guest_addr, int guest_port)
{
if (!check_guestfwd(slirp, guest_addr, guest_port)) {
return -1;
}
add_guestfwd(&slirp->guestfwd_list, write_cb, opaque, *guest_addr,
htons(guest_port));
return 0;
}
int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr,
int guest_port)
{
return remove_guestfwd(&slirp->guestfwd_list, guest_addr,
htons(guest_port));
}
slirp_ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
{
if (so->s == -1 && so->extra) {
Slirp *slirp = so->slirp;
slirp_warning("slirp_send(): so->extra not supported", slirp->opaque);
if (so->s == -1 && so->guestfwd) {
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
so->guestfwd->write_cb(buf, len, so->guestfwd->opaque);
return len;
}
return send(so->s, (const char*)buf, len, flags);
if (so->s == -1) {
/*
* This should in theory not happen but it is hard to be
* sure because some code paths will end up with so->s == -1
* on a failure but don't dispose of the struct socket.
* Check specifically, so we don't pass -1 to send().
*/
errno = EBADF;
return -1;
}
return send(so->s, buf, len, flags);
}
struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr,

View File

@ -110,6 +110,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr,
bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
uint8_t out_ethaddr[ETH_ALEN]);
/* Slirp configuration, specified by the application */
struct Slirp {
int cfg_version;
@ -137,6 +138,9 @@ struct Slirp {
int restricted;
struct gfwd_list *guestfwd_list;
int if_mtu;
int if_mru;
bool disable_host_loopback;
/* mbuf states */
@ -244,16 +248,4 @@ struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
/* Send a frame to the virtual Ethernet board, i.e. call the application send_packet callback */
void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len);
#ifndef min
#define min(x,y) ((x) < (y) ? (x) : (y))
#endif
#ifndef max
#define max(x,y) ((x) > (y) ? (x) : (y))
#endif
#ifdef _WIN32
#undef errno
#define errno (WSAGetLastError())
#endif
#endif

View File

@ -29,12 +29,6 @@
#define HAVE_SYS_SELECT_H
#endif
/* Define to whatever your compiler thinks inline should be */
//#define inline inline
/* Define to whatever your compiler thinks const should be */
//#define const const
/* Define to sizeof(char) */
#define SIZEOF_CHAR 1

View File

@ -62,12 +62,13 @@ socreate(Slirp *slirp)
void
sofree(struct socket *so)
{
Slirp *slirp = so->slirp;
if (so->so_emu==EMU_RSH && so->extra) {
sofree((struct socket*)so->extra);
so->extra=NULL;
}
Slirp *slirp = so->slirp;
/*
if (so->so_emu==EMU_RSH && so->extra) {
sofree((struct socket*)so->extra);
so->extra=NULL;
}
*/
if (so == slirp->tcp_last_so) {
slirp->tcp_last_so = &slirp->tcb;
} else if (so == slirp->udp_last_so) {
@ -316,12 +317,12 @@ sosendoob(struct socket *so)
* send it all
*/
len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
if (len > so->so_urgc) len = so->so_urgc;
if (len > (int)so->so_urgc) len = so->so_urgc;
memcpy(buff, sb->sb_rptr, len);
so->so_urgc -= len;
if (so->so_urgc) {
n = sb->sb_wptr - sb->sb_data;
if (n > so->so_urgc) n = so->so_urgc;
if (n > (int)so->so_urgc) n = so->so_urgc;
memcpy((buff + len), sb->sb_data, n);
so->so_urgc -= n;
len += n;

View File

@ -3,58 +3,89 @@
* Copyright (c) 1995 Danny Gasparovski.
*/
#ifndef SLIRP_SOCKET_H
#define SLIRP_SOCKET_H
#include <string.h>
#ifndef _WIN32
#include <sys/un.h>
#endif
#ifndef SLIRP_SOCKET_H
#define SLIRP_SOCKET_H
#include "misc.h"
#include "sbuf.h"
#define SO_EXPIRE 240000
#define SO_EXPIREFAST 10000
/* Helps unify some in/in6 routines. */
union in4or6_addr {
struct in_addr addr4;
struct in6_addr addr6;
};
typedef union in4or6_addr in4or6_addr;
/*
* Our socket structure
*/
union slirp_sockaddr {
struct sockaddr sa;
struct sockaddr_storage ss;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
};
struct socket {
struct socket *so_next,*so_prev; /* For a linked list of sockets */
struct socket *so_next, *so_prev; /* For a linked list of sockets */
int s; /* The actual socket */
int s; /* The actual socket */
int s_aux; /* An auxiliary socket for miscellaneous use. Currently used to
* reserve OS ports in UNIX-to-inet translation. */
struct gfwd_list *guestfwd;
int pollfds_idx;
int pollfds_idx;
Slirp *slirp; /* managing slirp instance */
Slirp *slirp; /* managing slirp instance */
/* XXX union these with not-yet-used sbuf params */
struct mbuf *so_m; /* Pointer to the original SYN packet,
* for non-blocking connect()'s, and
* PING reply's */
struct tcpiphdr *so_ti; /* Pointer to the original ti within
* so_mconn, for non-blocking connections */
int so_urgc;
struct in_addr so_faddr; /* foreign host table entry */
struct in_addr so_laddr; /* local host table entry */
uint16_t so_fport; /* foreign port */
uint16_t so_lport; /* local port */
/* XXX union these with not-yet-used sbuf params */
struct mbuf *so_m; /* Pointer to the original SYN packet,
* for non-blocking connect()'s, and
* PING reply's */
struct tcpiphdr *so_ti; /* Pointer to the original ti within
* so_mconn, for non-blocking connections */
uint32_t so_urgc;
union slirp_sockaddr fhost; /* Foreign host */
#define so_faddr fhost.sin.sin_addr
#define so_fport fhost.sin.sin_port
#define so_faddr6 fhost.sin6.sin6_addr
#define so_fport6 fhost.sin6.sin6_port
#define so_ffamily fhost.ss.ss_family
uint8_t so_iptos; /* Type of service */
uint8_t so_emu; /* Is the socket emulated? */
union slirp_sockaddr lhost; /* Local host */
#define so_laddr lhost.sin.sin_addr
#define so_lport lhost.sin.sin_port
#define so_laddr6 lhost.sin6.sin6_addr
#define so_lport6 lhost.sin6.sin6_port
#define so_lfamily lhost.ss.ss_family
u_char so_type; /* Type of socket, UDP or TCP */
int so_state; /* internal state flags SS_*, below */
uint8_t so_iptos; /* Type of service */
uint8_t so_emu; /* Is the socket emulated? */
struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */
u_int so_expire; /* When the socket will expire */
uint8_t so_type; /* Protocol of the socket. May be 0 if loading old
* states. */
int32_t so_state; /* internal state flags SS_*, below */
int so_queued; /* Number of packets queued from this socket */
int so_nqueued; /* Number of packets queued in a row
* Used to determine when to "downgrade" a session
* from fastq to batchq */
struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */
unsigned so_expire; /* When the socket will expire */
struct sbuf so_rcv; /* Receive buffer */
struct sbuf so_snd; /* Send buffer */
void * extra; /* Extra pointer */
int so_queued; /* Number of packets queued from this socket */
int so_nqueued; /* Number of packets queued in a row
* Used to determine when to "downgrade" a session
* from fastq to batchq */
struct sbuf so_rcv; /* Receive buffer */
struct sbuf so_snd; /* Send buffer */
};
@ -62,21 +93,29 @@ struct socket {
* Socket state bits. (peer means the host on the Internet,
* local host means the host on the other end of the modem)
*/
#define SS_NOFDREF 0x001 /* No fd reference */
#define SS_NOFDREF 0x001 /* No fd reference */
#define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */
#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */
#define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */
#define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */
#define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */
#define SS_ISFCONNECTING \
0x002 /* Socket is connecting to peer (non-blocking connect()'s) */
#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */
#define SS_FCANTRCVMORE \
0x008 /* Socket can't receive more from peer (for half-closes) */
#define SS_FCANTSENDMORE \
0x010 /* Socket can't send more to peer (for half-closes) */
#define SS_FWDRAIN \
0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */
#define SS_CTL 0x080
#define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */
#define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */
#define SS_FACCEPTCONN \
0x100 /* Socket is accepting connections from a host on the internet */
#define SS_FACCEPTONCE \
0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */
#define SS_PERSISTENT_MASK 0xf000 /* Unremovable state bits */
#define SS_HOSTFWD 0x1000 /* Socket describes host->guest forwarding */
#define SS_INCOMING 0x2000 /* Connection was initiated by a host on the internet */
#define SS_PERSISTENT_MASK 0xf000 /* Unremovable state bits */
#define SS_HOSTFWD 0x1000 /* Socket describes host->guest forwarding */
#define SS_INCOMING \
0x2000 /* Connection was initiated by a host on the internet */
#define SS_HOSTFWD_V6ONLY 0x4000 /* Only bind on v6 addresses */
/* Check that two addresses are equal */
static inline int sockaddr_equal(const struct sockaddr_storage *a,
@ -132,22 +171,56 @@ static inline socklen_t sockaddr_size(const struct sockaddr_storage *a)
return 0;
}
struct socket * solookup(struct socket *, struct in_addr, u_int, struct in_addr, u_int);
struct socket * socreate(Slirp *);
/* Copy an address */
static inline void sockaddr_copy(struct sockaddr *dst, socklen_t dstlen, const struct sockaddr *src, socklen_t srclen)
{
socklen_t len = sockaddr_size((const struct sockaddr_storage *) src);
assert(len <= srclen);
assert(len <= dstlen);
memcpy(dst, src, len);
}
/* Find the socket corresponding to lhost & fhost, trying last as a guess */
struct socket *solookup(struct socket *, struct in_addr, u_int, struct in_addr, u_int);
/* Create a new socket */
struct socket *socreate(Slirp *);
/* Release a socket */
void sofree(struct socket *);
/* Receive the available data from the Internet socket and queue it on the sb */
int soread(struct socket *);
/* Receive the available OOB data from the Internet socket and try to send it immediately */
int sorecvoob(struct socket *);
/* Send OOB data to the Internet socket */
int sosendoob(struct socket *);
/* Send data to the Internet socket */
int sowrite(struct socket *);
/* Receive the available data from the Internet UDP socket, and send it to the guest */
void sorecvfrom(struct socket *);
/* Send data to the Internet UDP socket */
int sosendto(struct socket *, struct mbuf *);
struct socket * tcp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
int);
/* Listen for incoming TCPv4 connections on this haddr+hport */
struct socket * tcp_listen(Slirp *, uint32_t haddr, unsigned hport, uint32_t laddr, unsigned lport, int flags);
/*
* Listen for incoming TCP connections on this haddr
* On failure errno contains the reason.
*/
struct socket * tcpx_listen(Slirp *slirp,
const struct sockaddr *haddr, socklen_t haddrlen,
const struct sockaddr *laddr, socklen_t laddrlen,
int flags);
/* Note that the socket is connecting */
void soisfconnecting(struct socket *);
/* Note that the socket is connected */
void soisfconnected(struct socket *);
/*
* Set write drain mode
* Set CANTSENDMORE once all data has been write()n
*/
void sofwdrain(struct socket *);
struct iovec; /* For win32 */
/* Prepare iov for storing into the sb */
size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
/* Get data from the buffer and queue it on the sb */
int soreadbuf(struct socket *so, const char *buf, int size);
#endif /* SLIRP_SOCKET_H */

View File

@ -36,11 +36,12 @@
typedef uint32_t tcp_seq;
#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */
#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */
#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */
#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */
#define TCP_SNDSPACE 8192
#define TCP_RCVSPACE 8192
#define TCP_SNDSPACE 1024 * 128
#define TCP_RCVSPACE 1024 * 128
#define TCP_MAXSEG_MAX 32768
/*
* TCP header.

View File

@ -526,7 +526,7 @@ findso:
win = sbspace(&so->so_rcv);
if (win < 0)
win = 0;
tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));
tp->rcv_wnd = MAX(win, (int)(tp->rcv_adv - tp->rcv_nxt));
}
switch (tp->t_state) {
@ -952,7 +952,7 @@ trimthenstep6:
else if (++tp->t_dupacks == TCPREXMTTHRESH) {
tcp_seq onxt = tp->snd_nxt;
u_int win =
min(tp->snd_wnd, tp->snd_cwnd) / 2 /
MIN(tp->snd_wnd, tp->snd_cwnd) / 2 /
tp->t_maxseg;
if (win < 2)
@ -1025,7 +1025,7 @@ trimthenstep6:
if (cw > tp->snd_ssthresh)
incr = incr * incr / cw;
tp->snd_cwnd = min((int)(cw + incr), TCP_MAXWIN<<tp->snd_scale);
tp->snd_cwnd = MIN((int)(cw + incr), TCP_MAXWIN<<tp->snd_scale);
}
if (acked > (int)so->so_snd.sb_cc) {
tp->snd_wnd -= so->so_snd.sb_cc;
@ -1471,10 +1471,11 @@ tcp_mss(struct tcpcb *tp, u_int offer)
DEBUG_ARG("tp = %lx", (long)tp);
DEBUG_ARG("offer = %d", offer);
mss = min(IF_MTU_DEFAULT, IF_MRU_DEFAULT) - sizeof(struct tcpiphdr);
mss = MIN(so->slirp->if_mtu, so->slirp->if_mru) -
sizeof(struct tcphdr) - sizeof(struct ip);
if (offer)
mss = min(mss, (int)offer);
mss = max(mss, 32);
mss = MIN(mss, (int)offer);
mss = MAX(mss, 32);
if (mss < tp->t_maxseg || offer != 0)
tp->t_maxseg = mss;

View File

@ -88,7 +88,7 @@ tcp_output(struct tcpcb *tp)
again:
sendalot = 0;
off = tp->snd_nxt - tp->snd_una;
win = min(tp->snd_wnd, tp->snd_cwnd);
win = MIN(tp->snd_wnd, tp->snd_cwnd);
flags = tcp_outflags[tp->t_state];
@ -127,7 +127,7 @@ again:
}
}
len = min((long)so->so_snd.sb_cc, win) - off;
len = MIN((long)so->so_snd.sb_cc, win) - off;
if (len < 0) {
/*
@ -193,7 +193,7 @@ again:
* taking into account that we are limited by
* TCP_MAXWIN << tp->rcv_scale.
*/
long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) -
long adv = MIN(win, (long)TCP_MAXWIN << tp->rcv_scale) -
(tp->rcv_adv - tp->rcv_nxt);
if (adv >= (long) (2 * tp->t_maxseg))

View File

@ -181,21 +181,26 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
* empty reassembly queue and hooking it to the argument
* protocol control block.
*/
struct tcpcb *
tcp_newtcpcb(struct socket *so)
struct tcpcb *tcp_newtcpcb(struct socket *so)
{
struct tcpcb *tp;
struct tcpcb *tp;
tp = (struct tcpcb *)malloc(sizeof(*tp));
if (tp == NULL)
return ((struct tcpcb *)0);
tp = (struct tcpcb *)malloc(sizeof(*tp));
if (tp == NULL)
return ((struct tcpcb *)0);
memset((char *) tp, 0, sizeof(struct tcpcb));
tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
tp->t_maxseg = TCP_MSS;
memset((char *) tp, 0, sizeof(struct tcpcb));
tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
/*
* 40: length of IPv4 header (20) + TCP header (20)
* 60: length of IPv6 header (40) + TCP header (20)
*/
tp->t_maxseg =
MIN(so->slirp->if_mtu - 40,
TCP_MAXSEG_MAX);
tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
tp->t_socket = so;
tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
tp->t_socket = so;
/*
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
@ -900,7 +905,6 @@ int tcp_ctl(struct socket *so)
Slirp *slirp = so->slirp;
struct sbuf *sb = &so->so_snd;
struct gfwd_list *ex_ptr;
int do_pty;
DEBUG_CALL("tcp_ctl");
DEBUG_ARG("so = %lx", (long )so);
@ -910,16 +914,16 @@ int tcp_ctl(struct socket *so)
for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
if (ex_ptr->ex_fport == so->so_fport &&
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
/*
if (ex_ptr->ex_pty == 3) {
if (ex_ptr->write_cb) {
so->s = -1;
so->extra = (void *)ex_ptr->ex_exec;
so->guestfwd = ex_ptr;
return 1;
}
do_pty = ex_ptr->ex_pty;
*/
DEBUG_MISC((dfd, " executing %s\n", ex_ptr->ex_exec));
return fork_exec(so, ex_ptr->ex_exec, do_pty);
DEBUG_MISC((dfd, " executing %s", ex_ptr->ex_exec));
if (ex_ptr->ex_unix)
return open_unix(so, ex_ptr->ex_unix);
else
return fork_exec(so, ex_ptr->ex_exec);
}
}
}

View File

@ -235,7 +235,7 @@ tcp_timers(struct tcpcb *tp, int timer)
* to go below this.)
*/
{
u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
u_int win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
if (win < 2)
win = 2;
tp->snd_cwnd = tp->t_maxseg;