Slirp: reduce differences to latest Qemu sources
This commit is contained in:
parent
0a1b4f1c7e
commit
6b39b6971f
@ -137,10 +137,9 @@ void bx_slirp_new_pktmover_c::rx_timer_handler(void *this_ptr)
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
FD_ZERO(&xfds);
|
||||
slirp_update_timeout(&timeout);
|
||||
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
|
||||
slirp_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
|
||||
slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
|
||||
}
|
||||
|
@ -25,6 +25,10 @@ typedef Bit64s ssize_t;
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof(((type *) 0)->member) *__mptr = (ptr); \
|
||||
|
@ -15,9 +15,8 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
|
||||
struct in_addr vnameserver, void *opaque);
|
||||
void slirp_cleanup(Slirp *slirp);
|
||||
|
||||
void slirp_update_timeout(uint32_t *timeout);
|
||||
void slirp_select_fill(int *pnfds,
|
||||
fd_set *readfds, fd_set *writefds, fd_set *xfds);
|
||||
void slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *xfds, uint32_t *timeout);
|
||||
|
||||
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
|
||||
int select_error);
|
||||
|
@ -33,6 +33,7 @@ extern char *exec_shell;
|
||||
extern Bit64u curtime;
|
||||
extern fd_set *global_readfds, *global_writefds, *global_xfds;
|
||||
extern struct in_addr loopback_addr;
|
||||
extern unsigned long loopback_mask;
|
||||
extern char *username;
|
||||
extern char *socket_path;
|
||||
extern int towrite_max;
|
||||
|
@ -49,22 +49,6 @@
|
||||
* free the m_ext. This is inefficient memory-wise, but who cares.
|
||||
*/
|
||||
|
||||
/* XXX should union some of these! */
|
||||
/* header at beginning of each mbuf: */
|
||||
struct m_hdr {
|
||||
struct mbuf *mh_next; /* Linked list of mbufs */
|
||||
struct mbuf *mh_prev;
|
||||
struct mbuf *mh_nextpkt; /* Next packet in queue/record */
|
||||
struct mbuf *mh_prevpkt; /* Flags aren't used in the output queue */
|
||||
int mh_flags; /* Misc flags */
|
||||
|
||||
int mh_size; /* Size of data */
|
||||
struct socket *mh_so;
|
||||
|
||||
caddr_t mh_data; /* Location of data */
|
||||
int mh_len; /* Amount of data in this mbuf */
|
||||
};
|
||||
|
||||
/*
|
||||
* How much room is in the mbuf, from m_data to the end of the mbuf
|
||||
*/
|
||||
@ -80,29 +64,30 @@ struct m_hdr {
|
||||
#define M_TRAILINGSPACE M_FREEROOM
|
||||
|
||||
struct mbuf {
|
||||
struct m_hdr m_hdr;
|
||||
/* XXX should union some of these! */
|
||||
/* header at beginning of each mbuf: */
|
||||
struct mbuf *m_next; /* Linked list of mbufs */
|
||||
struct mbuf *m_prev;
|
||||
struct mbuf *m_nextpkt; /* Next packet in queue/record */
|
||||
struct mbuf *m_prevpkt; /* Flags aren't used in the output queue */
|
||||
int m_flags; /* Misc flags */
|
||||
|
||||
int m_size; /* Size of data */
|
||||
struct socket *m_so;
|
||||
|
||||
caddr_t 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 M_dat {
|
||||
char m_dat_[1]; /* ANSI don't like 0 sized arrays */
|
||||
char *m_ext_;
|
||||
} M_dat;
|
||||
union {
|
||||
char m_dat[1]; /* ANSI don't like 0 sized arrays */
|
||||
char *m_ext;
|
||||
};
|
||||
};
|
||||
|
||||
#define m_next m_hdr.mh_next
|
||||
#define m_prev m_hdr.mh_prev
|
||||
#define m_nextpkt m_hdr.mh_nextpkt
|
||||
#define m_prevpkt m_hdr.mh_prevpkt
|
||||
#define m_flags m_hdr.mh_flags
|
||||
#define m_len m_hdr.mh_len
|
||||
#define m_data m_hdr.mh_data
|
||||
#define m_size m_hdr.mh_size
|
||||
#define m_dat M_dat.m_dat_
|
||||
#define m_ext M_dat.m_ext_
|
||||
#define m_so m_hdr.mh_so
|
||||
|
||||
#define ifq_prev m_prev
|
||||
#define ifq_next m_next
|
||||
#define ifs_prev m_prevpkt
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
/* host loopback address */
|
||||
struct in_addr loopback_addr;
|
||||
/* host loopback network mask */
|
||||
unsigned long loopback_mask;
|
||||
|
||||
/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
|
||||
static const uint8_t special_ethaddr[ETH_ALEN] = {
|
||||
@ -40,8 +42,6 @@ static const uint8_t zero_ethaddr[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
|
||||
fd_set *global_readfds, *global_writefds, *global_xfds;
|
||||
|
||||
Bit64u curtime;
|
||||
static Bit64u time_fasttimo, last_slowtimo;
|
||||
static int do_slowtimo;
|
||||
|
||||
static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
|
||||
QTAILQ_HEAD_INITIALIZER(slirp_instances);
|
||||
@ -49,6 +49,11 @@ static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
|
||||
static struct in_addr dns_addr;
|
||||
static u_int dns_addr_time;
|
||||
|
||||
#define TIMEOUT_FAST 2 /* milliseconds */
|
||||
#define TIMEOUT_SLOW 499 /* milliseconds */
|
||||
/* for the aging of certain requests like DNS */
|
||||
#define TIMEOUT_DEFAULT 1000 /* milliseconds */
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include <iphlpapi.h>
|
||||
@ -61,7 +66,7 @@ int get_dns_addr(struct in_addr *pdns_addr)
|
||||
IP_ADDR_STRING *pIPAddr;
|
||||
struct in_addr tmp_addr;
|
||||
|
||||
if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < 1000) {
|
||||
if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < TIMEOUT_DEFAULT) {
|
||||
*pdns_addr = dns_addr;
|
||||
return 0;
|
||||
}
|
||||
@ -119,7 +124,7 @@ int get_dns_addr(struct in_addr *pdns_addr)
|
||||
|
||||
if (dns_addr.s_addr != 0) {
|
||||
struct stat old_stat;
|
||||
if ((curtime - dns_addr_time) < 1000) {
|
||||
if ((curtime - dns_addr_time) < TIMEOUT_DEFAULT) {
|
||||
*pdns_addr = dns_addr;
|
||||
return 0;
|
||||
}
|
||||
@ -194,6 +199,7 @@ static void slirp_init_once(void)
|
||||
#endif
|
||||
|
||||
loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
loopback_mask = htonl(IN_CLASSA_NET);
|
||||
}
|
||||
|
||||
Slirp *slirp_init(int restricted, struct in_addr vnetwork,
|
||||
@ -254,15 +260,34 @@ void slirp_cleanup(Slirp *slirp)
|
||||
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
|
||||
#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
|
||||
|
||||
void slirp_update_timeout(uint32_t *timeout)
|
||||
static void slirp_update_timeout(uint32_t *timeout)
|
||||
{
|
||||
if (!QTAILQ_EMPTY(&slirp_instances)) {
|
||||
*timeout = MIN(1000, *timeout);
|
||||
Slirp *slirp;
|
||||
uint32_t t;
|
||||
|
||||
if (*timeout <= TIMEOUT_FAST) {
|
||||
return;
|
||||
}
|
||||
|
||||
t = MIN(1000, *timeout);
|
||||
|
||||
/* If we have tcp timeout with slirp, then we will fill @timeout with
|
||||
* more precise value.
|
||||
*/
|
||||
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
|
||||
if (slirp->time_fasttimo) {
|
||||
*timeout = TIMEOUT_FAST;
|
||||
return;
|
||||
}
|
||||
if (slirp->do_slowtimo) {
|
||||
t = MIN(TIMEOUT_SLOW, t);
|
||||
}
|
||||
}
|
||||
*timeout = t;
|
||||
}
|
||||
|
||||
void slirp_select_fill(int *pnfds,
|
||||
fd_set *readfds, fd_set *writefds, fd_set *xfds)
|
||||
void slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *xfds, uint32_t *timeout)
|
||||
{
|
||||
Slirp *slirp;
|
||||
struct socket *so, *so_next;
|
||||
@ -278,135 +303,138 @@ void slirp_select_fill(int *pnfds,
|
||||
global_xfds = NULL;
|
||||
|
||||
nfds = *pnfds;
|
||||
/*
|
||||
* First, TCP sockets
|
||||
*/
|
||||
do_slowtimo = 0;
|
||||
/*
|
||||
* First, TCP sockets
|
||||
*/
|
||||
|
||||
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
|
||||
/*
|
||||
* *_slowtimo needs calling if there are IP fragments
|
||||
* in the fragment queue, or there are TCP connections active
|
||||
*/
|
||||
do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
|
||||
(&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
|
||||
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
|
||||
/*
|
||||
* *_slowtimo needs calling if there are IP fragments
|
||||
* in the fragment queue, or there are TCP connections active
|
||||
*/
|
||||
slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
|
||||
(&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
|
||||
|
||||
for (so = slirp->tcb.so_next; so != &slirp->tcb;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
for (so = slirp->tcb.so_next; so != &slirp->tcb;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
|
||||
/*
|
||||
* See if we need a tcp_fasttimo
|
||||
*/
|
||||
if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
|
||||
time_fasttimo = curtime; /* Flag when we want a fasttimo */
|
||||
/*
|
||||
* See if we need a tcp_fasttimo
|
||||
*/
|
||||
if (slirp->time_fasttimo == 0 &&
|
||||
so->so_tcpcb->t_flags & TF_DELACK) {
|
||||
slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
|
||||
}
|
||||
|
||||
/*
|
||||
* NOFDREF can include still connecting to local-host,
|
||||
* newly socreated() sockets etc. Don't want to select these.
|
||||
*/
|
||||
if (so->so_state & SS_NOFDREF || so->s == -1)
|
||||
continue;
|
||||
/*
|
||||
* NOFDREF can include still connecting to local-host,
|
||||
* newly socreated() sockets etc. Don't want to select these.
|
||||
*/
|
||||
if (so->so_state & SS_NOFDREF || so->s == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set for reading sockets which are accepting
|
||||
*/
|
||||
if (so->so_state & SS_FACCEPTCONN) {
|
||||
FD_SET(so->s, readfds);
|
||||
UPD_NFDS(so->s);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Set for reading sockets which are accepting
|
||||
*/
|
||||
if (so->so_state & SS_FACCEPTCONN) {
|
||||
FD_SET(so->s, readfds);
|
||||
UPD_NFDS(so->s);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set for writing sockets which are connecting
|
||||
*/
|
||||
if (so->so_state & SS_ISFCONNECTING) {
|
||||
FD_SET(so->s, writefds);
|
||||
UPD_NFDS(so->s);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Set for writing sockets which are connecting
|
||||
*/
|
||||
if (so->so_state & SS_ISFCONNECTING) {
|
||||
FD_SET(so->s, writefds);
|
||||
UPD_NFDS(so->s);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set for writing if we are connected, can send more, and
|
||||
* we have something to send
|
||||
*/
|
||||
if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
|
||||
FD_SET(so->s, writefds);
|
||||
UPD_NFDS(so->s);
|
||||
}
|
||||
/*
|
||||
* Set for writing if we are connected, can send more, and
|
||||
* we have something to send
|
||||
*/
|
||||
if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
|
||||
FD_SET(so->s, writefds);
|
||||
UPD_NFDS(so->s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set for reading (and urgent data) if we are connected, can
|
||||
* receive more, and we have room for it XXX /2 ?
|
||||
*/
|
||||
if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
|
||||
FD_SET(so->s, readfds);
|
||||
FD_SET(so->s, xfds);
|
||||
UPD_NFDS(so->s);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Set for reading (and urgent data) if we are connected, can
|
||||
* receive more, and we have room for it XXX /2 ?
|
||||
*/
|
||||
if (CONN_CANFRCV(so) &&
|
||||
(so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
|
||||
FD_SET(so->s, readfds);
|
||||
FD_SET(so->s, xfds);
|
||||
UPD_NFDS(so->s);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* UDP sockets
|
||||
*/
|
||||
for (so = slirp->udb.so_next; so != &slirp->udb;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
/*
|
||||
* UDP sockets
|
||||
*/
|
||||
for (so = slirp->udb.so_next; so != &slirp->udb;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
|
||||
/*
|
||||
* See if it's timed out
|
||||
*/
|
||||
if (so->so_expire) {
|
||||
if (so->so_expire <= curtime) {
|
||||
udp_detach(so);
|
||||
continue;
|
||||
} else
|
||||
do_slowtimo = 1; /* Let socket expire */
|
||||
}
|
||||
|
||||
/*
|
||||
* When UDP packets are received from over the
|
||||
* link, they're sendto()'d straight away, so
|
||||
* no need for setting for writing
|
||||
* Limit the number of packets queued by this session
|
||||
* to 4. Note that even though we try and limit this
|
||||
* to 4 packets, the session could have more queued
|
||||
* if the packets needed to be fragmented
|
||||
* (XXX <= 4 ?)
|
||||
*/
|
||||
if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
|
||||
FD_SET(so->s, readfds);
|
||||
UPD_NFDS(so->s);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ICMP sockets
|
||||
*/
|
||||
for (so = slirp->icmp.so_next; so != &slirp->icmp;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
|
||||
/*
|
||||
* See if it's timed out
|
||||
*/
|
||||
if (so->so_expire) {
|
||||
if (so->so_expire <= curtime) {
|
||||
icmp_detach(so);
|
||||
continue;
|
||||
} else {
|
||||
do_slowtimo = 1; /* Let socket expire */
|
||||
}
|
||||
}
|
||||
|
||||
if (so->so_state & SS_ISFCONNECTED) {
|
||||
FD_SET(so->s, readfds);
|
||||
UPD_NFDS(so->s);
|
||||
}
|
||||
/*
|
||||
* See if it's timed out
|
||||
*/
|
||||
if (so->so_expire) {
|
||||
if (so->so_expire <= curtime) {
|
||||
udp_detach(so);
|
||||
continue;
|
||||
} else {
|
||||
slirp->do_slowtimo = true; /* Let socket expire */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*pnfds = nfds;
|
||||
/*
|
||||
* When UDP packets are received from over the
|
||||
* link, they're sendto()'d straight away, so
|
||||
* no need for setting for writing
|
||||
* Limit the number of packets queued by this session
|
||||
* to 4. Note that even though we try and limit this
|
||||
* to 4 packets, the session could have more queued
|
||||
* if the packets needed to be fragmented
|
||||
* (XXX <= 4 ?)
|
||||
*/
|
||||
if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
|
||||
FD_SET(so->s, readfds);
|
||||
UPD_NFDS(so->s);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ICMP sockets
|
||||
*/
|
||||
for (so = slirp->icmp.so_next; so != &slirp->icmp;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
|
||||
/*
|
||||
* See if it's timed out
|
||||
*/
|
||||
if (so->so_expire) {
|
||||
if (so->so_expire <= curtime) {
|
||||
icmp_detach(so);
|
||||
continue;
|
||||
} else {
|
||||
slirp->do_slowtimo = true; /* Let socket expire */
|
||||
}
|
||||
}
|
||||
if (so->so_state & SS_ISFCONNECTED) {
|
||||
FD_SET(so->s, readfds);
|
||||
UPD_NFDS(so->s);
|
||||
}
|
||||
}
|
||||
}
|
||||
slirp_update_timeout(timeout);
|
||||
*pnfds = nfds;
|
||||
}
|
||||
|
||||
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
|
||||
@ -427,177 +455,186 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
|
||||
curtime = bx_pc_system.time_usec() / 1000;
|
||||
|
||||
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
|
||||
/*
|
||||
* See if anything has timed out
|
||||
*/
|
||||
if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
|
||||
tcp_fasttimo(slirp);
|
||||
time_fasttimo = 0;
|
||||
}
|
||||
if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
|
||||
ip_slowtimo(slirp);
|
||||
tcp_slowtimo(slirp);
|
||||
last_slowtimo = curtime;
|
||||
}
|
||||
/*
|
||||
* See if anything has timed out
|
||||
*/
|
||||
if (slirp->time_fasttimo &&
|
||||
((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
|
||||
tcp_fasttimo(slirp);
|
||||
slirp->time_fasttimo = 0;
|
||||
}
|
||||
if (slirp->do_slowtimo &&
|
||||
((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
|
||||
ip_slowtimo(slirp);
|
||||
tcp_slowtimo(slirp);
|
||||
slirp->last_slowtimo = curtime;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check sockets
|
||||
*/
|
||||
if (!select_error) {
|
||||
/*
|
||||
* Check TCP sockets
|
||||
*/
|
||||
for (so = slirp->tcb.so_next; so != &slirp->tcb;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
|
||||
/*
|
||||
* FD_ISSET is meaningless on these sockets
|
||||
* (and they can crash the program)
|
||||
*/
|
||||
if (so->so_state & SS_NOFDREF || so->s == -1)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Check for URG data
|
||||
* This will soread as well, so no need to
|
||||
* test for readfds below if this succeeds
|
||||
*/
|
||||
if (FD_ISSET(so->s, xfds))
|
||||
sorecvoob(so);
|
||||
/*
|
||||
* Check sockets for reading
|
||||
*/
|
||||
else if (FD_ISSET(so->s, readfds)) {
|
||||
/*
|
||||
* Check for incoming connections
|
||||
*/
|
||||
if (so->so_state & SS_FACCEPTCONN) {
|
||||
tcp_connect(so);
|
||||
continue;
|
||||
} /* else */
|
||||
ret = soread(so);
|
||||
|
||||
/* Output it if we read something */
|
||||
if (ret > 0)
|
||||
tcp_output(sototcpcb(so));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check sockets for writing
|
||||
*/
|
||||
if (FD_ISSET(so->s, writefds)) {
|
||||
/*
|
||||
* Check for non-blocking, still-connecting sockets
|
||||
*/
|
||||
if (so->so_state & SS_ISFCONNECTING) {
|
||||
/* Connected */
|
||||
so->so_state &= ~SS_ISFCONNECTING;
|
||||
|
||||
ret = send(so->s, (const char*) &ret, 0, 0);
|
||||
if (ret < 0) {
|
||||
/* XXXXX Must fix, zero bytes is a NOP */
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK ||
|
||||
errno == EINPROGRESS || errno == ENOTCONN)
|
||||
continue;
|
||||
|
||||
/* else failed */
|
||||
so->so_state &= SS_PERSISTENT_MASK;
|
||||
so->so_state |= SS_NOFDREF;
|
||||
}
|
||||
/* else so->so_state &= ~SS_ISFCONNECTING; */
|
||||
|
||||
/*
|
||||
* Continue tcp_input
|
||||
*/
|
||||
tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
|
||||
/* continue; */
|
||||
} else
|
||||
ret = sowrite(so);
|
||||
/*
|
||||
* XXXXX If we wrote something (a lot), there
|
||||
* could be a need for a window update.
|
||||
* In the worst case, the remote will send
|
||||
* a window probe to get things going again
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe a still-connecting, non-blocking socket
|
||||
* to check if it's still alive
|
||||
*/
|
||||
#ifdef PROBE_CONN
|
||||
if (so->so_state & SS_ISFCONNECTING) {
|
||||
ret = qemu_recv(so->s, &ret, 0, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
/* XXX */
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK ||
|
||||
errno == EINPROGRESS || errno == ENOTCONN)
|
||||
continue; /* Still connecting, continue */
|
||||
|
||||
/* else failed */
|
||||
so->so_state &= SS_PERSISTENT_MASK;
|
||||
so->so_state |= SS_NOFDREF;
|
||||
|
||||
/* tcp_input will take care of it */
|
||||
} else {
|
||||
ret = send(so->s, (const char*)&ret, 0,0);
|
||||
if (ret < 0) {
|
||||
/* XXX */
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK ||
|
||||
errno == EINPROGRESS || errno == ENOTCONN)
|
||||
continue;
|
||||
/* else failed */
|
||||
so->so_state &= SS_PERSISTENT_MASK;
|
||||
so->so_state |= SS_NOFDREF;
|
||||
} else
|
||||
so->so_state &= ~SS_ISFCONNECTING;
|
||||
|
||||
}
|
||||
tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
|
||||
} /* SS_ISFCONNECTING */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Now UDP sockets.
|
||||
* Incoming packets are sent straight away, they're not buffered.
|
||||
* Incoming UDP data isn't buffered either.
|
||||
*/
|
||||
for (so = slirp->udb.so_next; so != &slirp->udb;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
|
||||
if (so->s != -1 && FD_ISSET(so->s, readfds)) {
|
||||
sorecvfrom(so);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Check sockets
|
||||
*/
|
||||
if (!select_error) {
|
||||
/*
|
||||
* Check TCP sockets
|
||||
*/
|
||||
for (so = slirp->tcb.so_next; so != &slirp->tcb;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
|
||||
/*
|
||||
* Check incoming ICMP relies.
|
||||
* FD_ISSET is meaningless on these sockets
|
||||
* (and they can crash the program)
|
||||
*/
|
||||
for (so = slirp->icmp.so_next; so != &slirp->icmp;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
if (so->so_state & SS_NOFDREF || so->s == -1) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Check for URG data
|
||||
* This will soread as well, so no need to
|
||||
* test for readfds below if this succeeds
|
||||
*/
|
||||
if (FD_ISSET(so->s, xfds)) {
|
||||
sorecvoob(so);
|
||||
}
|
||||
/*
|
||||
* Check sockets for reading
|
||||
*/
|
||||
else if (FD_ISSET(so->s, readfds)) {
|
||||
/*
|
||||
* Check for incoming connections
|
||||
*/
|
||||
if (so->so_state & SS_FACCEPTCONN) {
|
||||
tcp_connect(so);
|
||||
continue;
|
||||
} /* else */
|
||||
ret = soread(so);
|
||||
|
||||
/* Output it if we read something */
|
||||
if (ret > 0) {
|
||||
tcp_output(sototcpcb(so));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check sockets for writing
|
||||
*/
|
||||
if (FD_ISSET(so->s, writefds)) {
|
||||
/*
|
||||
* Check for non-blocking, still-connecting sockets
|
||||
*/
|
||||
if (so->so_state & SS_ISFCONNECTING) {
|
||||
/* Connected */
|
||||
so->so_state &= ~SS_ISFCONNECTING;
|
||||
|
||||
ret = send(so->s, (const char*) &ret, 0, 0);
|
||||
if (ret < 0) {
|
||||
/* XXXXX Must fix, zero bytes is a NOP */
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK ||
|
||||
errno == EINPROGRESS || errno == ENOTCONN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* else failed */
|
||||
so->so_state &= SS_PERSISTENT_MASK;
|
||||
so->so_state |= SS_NOFDREF;
|
||||
}
|
||||
/* else so->so_state &= ~SS_ISFCONNECTING; */
|
||||
|
||||
/*
|
||||
* Continue tcp_input
|
||||
*/
|
||||
tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
|
||||
/* continue; */
|
||||
} else {
|
||||
ret = sowrite(so);
|
||||
}
|
||||
/*
|
||||
* XXXXX If we wrote something (a lot), there
|
||||
* could be a need for a window update.
|
||||
* In the worst case, the remote will send
|
||||
* a window probe to get things going again
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe a still-connecting, non-blocking socket
|
||||
* to check if it's still alive
|
||||
*/
|
||||
#ifdef PROBE_CONN
|
||||
if (so->so_state & SS_ISFCONNECTING) {
|
||||
ret = qemu_recv(so->s, &ret, 0, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
/* XXX */
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK ||
|
||||
errno == EINPROGRESS || errno == ENOTCONN) {
|
||||
continue; /* Still connecting, continue */
|
||||
}
|
||||
|
||||
/* else failed */
|
||||
so->so_state &= SS_PERSISTENT_MASK;
|
||||
so->so_state |= SS_NOFDREF;
|
||||
|
||||
/* tcp_input will take care of it */
|
||||
} else {
|
||||
ret = send(so->s, (const char*)&ret, 0, 0);
|
||||
if (ret < 0) {
|
||||
/* XXX */
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK ||
|
||||
errno == EINPROGRESS || errno == ENOTCONN) {
|
||||
continue;
|
||||
}
|
||||
/* else failed */
|
||||
so->so_state &= SS_PERSISTENT_MASK;
|
||||
so->so_state |= SS_NOFDREF;
|
||||
} else {
|
||||
so->so_state &= ~SS_ISFCONNECTING;
|
||||
}
|
||||
|
||||
}
|
||||
tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
|
||||
} /* SS_ISFCONNECTING */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Now UDP sockets.
|
||||
* Incoming packets are sent straight away, they're not buffered.
|
||||
* Incoming UDP data isn't buffered either.
|
||||
*/
|
||||
for (so = slirp->udb.so_next; so != &slirp->udb;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
|
||||
if (so->s != -1 && FD_ISSET(so->s, readfds)) {
|
||||
sorecvfrom(so);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check incoming ICMP relies.
|
||||
*/
|
||||
for (so = slirp->icmp.so_next; so != &slirp->icmp;
|
||||
so = so_next) {
|
||||
so_next = so->so_next;
|
||||
|
||||
if (so->s != -1 && FD_ISSET(so->s, readfds)) {
|
||||
icmp_receive(so);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if_start(slirp);
|
||||
}
|
||||
|
||||
/* clear global file descriptor sets.
|
||||
* these reside on the stack in vl.c
|
||||
* so they're unusable if we're not in
|
||||
* slirp_select_fill or slirp_select_poll.
|
||||
*/
|
||||
global_readfds = NULL;
|
||||
global_writefds = NULL;
|
||||
global_xfds = NULL;
|
||||
/* clear global file descriptor sets.
|
||||
* these reside on the stack in vl.c
|
||||
* so they're unusable if we're not in
|
||||
* slirp_select_fill or slirp_select_poll.
|
||||
*/
|
||||
global_readfds = NULL;
|
||||
global_writefds = NULL;
|
||||
global_xfds = NULL;
|
||||
}
|
||||
|
||||
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
|
||||
|
@ -209,6 +209,9 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
|
||||
|
||||
struct Slirp {
|
||||
QTAILQ_ENTRY(Slirp) entry;
|
||||
u_int time_fasttimo;
|
||||
u_int last_slowtimo;
|
||||
bool do_slowtimo;
|
||||
|
||||
/* virtual network configuration */
|
||||
struct in_addr vnetwork_addr;
|
||||
@ -221,7 +224,6 @@ struct Slirp {
|
||||
char client_hostname[33];
|
||||
|
||||
int restricted;
|
||||
struct timeval tt;
|
||||
struct ex_list *exec_list;
|
||||
|
||||
/* mbuf states */
|
||||
|
@ -338,9 +338,9 @@ int tcp_fconnect(struct socket *so)
|
||||
|
||||
qemu_set_nonblock(s);
|
||||
opt = 1;
|
||||
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
|
||||
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt, sizeof(opt));
|
||||
opt = 1;
|
||||
setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
|
||||
setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt, sizeof(opt));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
|
||||
@ -427,23 +427,29 @@ void tcp_connect(struct socket *inso)
|
||||
}
|
||||
qemu_set_nonblock(s);
|
||||
opt = 1;
|
||||
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
|
||||
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt, sizeof(int));
|
||||
opt = 1;
|
||||
setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
|
||||
setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt, sizeof(int));
|
||||
opt = 1;
|
||||
setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int));
|
||||
setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt, sizeof(int));
|
||||
|
||||
so->so_fport = addr.sin_port;
|
||||
so->so_faddr = addr.sin_addr;
|
||||
/* Translate connections from localhost to the real hostname */
|
||||
if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
|
||||
so->so_faddr = slirp->vhost_addr;
|
||||
if (so->so_faddr.s_addr == 0 ||
|
||||
(so->so_faddr.s_addr & loopback_mask) ==
|
||||
(loopback_addr.s_addr & loopback_mask)) {
|
||||
so->so_faddr = slirp->vhost_addr;
|
||||
}
|
||||
|
||||
/* Close the accept() socket, set right state */
|
||||
if (inso->so_state & SS_FACCEPTONCE) {
|
||||
closesocket(so->s); /* If we only accept once, close the accept() socket */
|
||||
so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */
|
||||
/* if it's not FACCEPTONCE, it's already NOFDREF */
|
||||
/* If we only accept once, close the accept() socket */
|
||||
closesocket(so->s);
|
||||
|
||||
/* Don't select it yet, even though we have an FD */
|
||||
/* if it's not FACCEPTONCE, it's already NOFDREF */
|
||||
so->so_state = SS_NOFDREF;
|
||||
}
|
||||
so->s = s;
|
||||
so->so_state |= SS_INCOMING;
|
||||
@ -642,7 +648,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
|
||||
n4 = (laddr & 0xff);
|
||||
|
||||
m->m_len = bptr - m->m_data; /* Adjust length */
|
||||
m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
|
||||
m->m_len += snprintf(bptr, m->m_size - m->m_len,
|
||||
"ORT %d,%d,%d,%d,%d,%d\r\n%s",
|
||||
n1, n2, n3, n4, n5, n6, x==7?buff:"");
|
||||
return 1;
|
||||
@ -675,7 +681,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
|
||||
n4 = (laddr & 0xff);
|
||||
|
||||
m->m_len = bptr - m->m_data; /* Adjust length */
|
||||
m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
|
||||
m->m_len += snprintf(bptr, m->m_size - m->m_len,
|
||||
"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
|
||||
n1, n2, n3, n4, n5, n6, x==7?buff:"");
|
||||
|
||||
@ -701,7 +707,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
|
||||
if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
|
||||
(so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
|
||||
htons(lport), SS_FACCEPTONCE)) != NULL)
|
||||
m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d",
|
||||
m->m_len = snprintf(m->m_data, m->m_size, "%d",
|
||||
ntohs(so->so_fport)) + 1;
|
||||
return 1;
|
||||
|
||||
@ -721,7 +727,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
|
||||
return 1;
|
||||
}
|
||||
m->m_len = bptr - m->m_data; /* Adjust length */
|
||||
m->m_len += snprintf(bptr, m->m_hdr.mh_size,
|
||||
m->m_len += snprintf(bptr, m->m_size,
|
||||
"DCC CHAT chat %lu %u%c\n",
|
||||
(unsigned long)ntohl(so->so_faddr.s_addr),
|
||||
ntohs(so->so_fport), 1);
|
||||
@ -732,7 +738,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
|
||||
return 1;
|
||||
}
|
||||
m->m_len = bptr - m->m_data; /* Adjust length */
|
||||
m->m_len += snprintf(bptr, m->m_hdr.mh_size,
|
||||
m->m_len += snprintf(bptr, m->m_size,
|
||||
"DCC SEND %s %lu %u %u%c\n", buff,
|
||||
(unsigned long)ntohl(so->so_faddr.s_addr),
|
||||
ntohs(so->so_fport), n1, 1);
|
||||
@ -743,7 +749,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
|
||||
return 1;
|
||||
}
|
||||
m->m_len = bptr - m->m_data; /* Adjust length */
|
||||
m->m_len += snprintf(bptr, m->m_hdr.mh_size,
|
||||
m->m_len += snprintf(bptr, m->m_size,
|
||||
"DCC MOVE %s %lu %u %u%c\n", buff,
|
||||
(unsigned long)ntohl(so->so_faddr.s_addr),
|
||||
ntohs(so->so_fport), n1, 1);
|
||||
|
@ -36,6 +36,10 @@ static inline void tftp_session_update(struct tftp_session *spt)
|
||||
|
||||
static void tftp_session_terminate(struct tftp_session *spt)
|
||||
{
|
||||
if (spt->fd >= 0) {
|
||||
close(spt->fd);
|
||||
spt->fd = -1;
|
||||
}
|
||||
free(spt->filename);
|
||||
spt->slirp = NULL;
|
||||
}
|
||||
@ -53,7 +57,7 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
|
||||
|
||||
/* sessions time out after 5 inactive seconds */
|
||||
if ((int)(curtime - spt->timestamp) > 5000) {
|
||||
free(spt->filename);
|
||||
tftp_session_terminate(spt);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
@ -63,6 +67,7 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
|
||||
found:
|
||||
memset(spt, 0, sizeof(*spt));
|
||||
memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip));
|
||||
spt->fd = -1;
|
||||
spt->client_port = tp->udp.uh_sport;
|
||||
spt->slirp = slirp;
|
||||
|
||||
@ -91,37 +96,36 @@ static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int tftp_read_data(struct tftp_session *spt, uint16_t block_nr,
|
||||
static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
|
||||
uint8_t *buf, int len)
|
||||
{
|
||||
int fd;
|
||||
int bytes_read = 0;
|
||||
int bytes_read = 0;
|
||||
|
||||
fd = open(spt->filename, O_RDONLY | O_BINARY);
|
||||
if (spt->fd < 0) {
|
||||
spt->fd = open(spt->filename, O_RDONLY | O_BINARY);
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (spt->fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
lseek(fd, block_nr * 512, SEEK_SET);
|
||||
if (len) {
|
||||
lseek(spt->fd, block_nr * 512, SEEK_SET);
|
||||
|
||||
bytes_read = read(fd, buf, len);
|
||||
}
|
||||
bytes_read = read(spt->fd, buf, len);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return bytes_read;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static int tftp_send_oack(struct tftp_session *spt,
|
||||
const char *key, uint32_t value,
|
||||
const char *keys[], uint32_t values[], int nb,
|
||||
struct tftp_t *recv_tp)
|
||||
{
|
||||
struct sockaddr_in saddr, daddr;
|
||||
struct mbuf *m;
|
||||
struct tftp_t *tp;
|
||||
int n = 0;
|
||||
int i, n = 0;
|
||||
|
||||
m = m_get(spt->slirp);
|
||||
|
||||
@ -135,10 +139,12 @@ static int tftp_send_oack(struct tftp_session *spt,
|
||||
m->m_data += sizeof(struct udpiphdr);
|
||||
|
||||
tp->tp_op = htons(TFTP_OACK);
|
||||
n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
|
||||
key) + 1;
|
||||
n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
|
||||
value) + 1;
|
||||
for (i = 0; i < nb; i++) {
|
||||
n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
|
||||
keys[i]) + 1;
|
||||
n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
|
||||
values[i]) + 1;
|
||||
}
|
||||
|
||||
saddr.sin_addr = recv_tp->ip.ip_dst;
|
||||
saddr.sin_port = recv_tp->udp.uh_dport;
|
||||
@ -192,23 +198,18 @@ out:
|
||||
tftp_session_terminate(spt);
|
||||
}
|
||||
|
||||
static int tftp_send_data(struct tftp_session *spt,
|
||||
uint16_t block_nr,
|
||||
struct tftp_t *recv_tp)
|
||||
static void tftp_send_next_block(struct tftp_session *spt,
|
||||
struct tftp_t *recv_tp)
|
||||
{
|
||||
struct sockaddr_in saddr, daddr;
|
||||
struct mbuf *m;
|
||||
struct tftp_t *tp;
|
||||
int nobytes;
|
||||
|
||||
if (block_nr < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
m = m_get(spt->slirp);
|
||||
|
||||
if (!m) {
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
memset(m->m_data, 0, m->m_size);
|
||||
@ -218,7 +219,7 @@ static int tftp_send_data(struct tftp_session *spt,
|
||||
m->m_data += sizeof(struct udpiphdr);
|
||||
|
||||
tp->tp_op = htons(TFTP_DATA);
|
||||
tp->x.tp_data.tp_block_nr = htons(block_nr);
|
||||
tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
|
||||
|
||||
saddr.sin_addr = recv_tp->ip.ip_dst;
|
||||
saddr.sin_port = recv_tp->udp.uh_dport;
|
||||
@ -226,7 +227,7 @@ static int tftp_send_data(struct tftp_session *spt,
|
||||
daddr.sin_addr = spt->client_ip;
|
||||
daddr.sin_port = spt->client_port;
|
||||
|
||||
nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512);
|
||||
nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, 512);
|
||||
|
||||
if (nobytes < 0) {
|
||||
m_free(m);
|
||||
@ -235,7 +236,7 @@ static int tftp_send_data(struct tftp_session *spt,
|
||||
|
||||
tftp_send_error(spt, 1, "File not found", tp);
|
||||
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
|
||||
@ -250,7 +251,7 @@ static int tftp_send_data(struct tftp_session *spt,
|
||||
tftp_session_terminate(spt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
spt->block_nr++;
|
||||
}
|
||||
|
||||
static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
|
||||
@ -259,6 +260,9 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
|
||||
int s, k;
|
||||
size_t prefix_len;
|
||||
char *req_fname;
|
||||
const char *option_name[2];
|
||||
uint32_t option_value[2];
|
||||
unsigned nb_options = 0;
|
||||
|
||||
/* check if a session already exists and if so terminate it */
|
||||
s = tftp_session_find(slirp, tp);
|
||||
@ -336,7 +340,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
|
||||
return;
|
||||
}
|
||||
|
||||
while (k < pktlen) {
|
||||
while (k < pktlen && nb_options < ARRAY_SIZE(option_name)) {
|
||||
const char *key, *value;
|
||||
|
||||
key = &tp->x.tp_buf[k];
|
||||
@ -363,12 +367,32 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
|
||||
}
|
||||
}
|
||||
|
||||
tftp_send_oack(spt, "tsize", tsize, tp);
|
||||
return;
|
||||
option_name[nb_options] = "tsize";
|
||||
option_value[nb_options] = tsize;
|
||||
nb_options++;
|
||||
} else if (strcasecmp(key, "blksize") == 0) {
|
||||
int blksize = atoi(value);
|
||||
|
||||
/* If blksize option is bigger than what we will
|
||||
* emit, accept the option with our packet size.
|
||||
* Otherwise, simply do as we didn't see the option.
|
||||
*/
|
||||
if (blksize >= 512) {
|
||||
option_name[nb_options] = "blksize";
|
||||
option_value[nb_options] = 512;
|
||||
nb_options++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tftp_send_data(spt, 1, tp);
|
||||
if (nb_options > 0) {
|
||||
assert(nb_options <= ARRAY_SIZE(option_name));
|
||||
tftp_send_oack(spt, option_name, option_value, nb_options, tp);
|
||||
return;
|
||||
}
|
||||
|
||||
spt->block_nr = 0;
|
||||
tftp_send_next_block(spt, tp);
|
||||
}
|
||||
|
||||
static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
|
||||
@ -381,11 +405,7 @@ static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
|
||||
return;
|
||||
}
|
||||
|
||||
if (tftp_send_data(&slirp->tftp_sessions[s],
|
||||
ntohs(tp->x.tp_data.tp_block_nr) + 1,
|
||||
tp) < 0) {
|
||||
return;
|
||||
}
|
||||
tftp_send_next_block(&slirp->tftp_sessions[s], tp);
|
||||
}
|
||||
|
||||
static void tftp_handle_error(Slirp *slirp, struct tftp_t *tp, int pktlen)
|
||||
|
@ -1,4 +1,6 @@
|
||||
/* tftp defines */
|
||||
#ifndef SLIRP_TFTP_H
|
||||
#define SLIRP_TFTP_H 1
|
||||
|
||||
#define TFTP_SESSIONS_MAX 3
|
||||
|
||||
@ -33,11 +35,15 @@ struct tftp_t {
|
||||
struct tftp_session {
|
||||
Slirp *slirp;
|
||||
char *filename;
|
||||
int fd;
|
||||
|
||||
struct in_addr client_ip;
|
||||
uint16_t client_port;
|
||||
uint32_t block_nr;
|
||||
|
||||
int timestamp;
|
||||
};
|
||||
|
||||
void tftp_input(struct mbuf *m);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user