Porting continues. TCP works fine now.

git-svn-id: file:///svn/unbound/trunk@1128 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-06-23 13:52:03 +00:00
parent fc3fc7a1f3
commit ee5ee20071
7 changed files with 184 additions and 25 deletions

View file

@ -1,3 +1,13 @@
23 June 2008: Wouter
- fixup minitpkg to cleanup on windows with its file locking troubles.
- minitpkg shows skipped tests in report.
- skip ipv6 tests on ipv4 only hosts (requires only ipv6 localhost not
ipv6 connectivity).
- winsock event handler keeps track of sticky TCP events, that have
not been fully handled yet. when interest in the event(s) resumes,
they are sent again. When WOULDBLOCK is returned events are cleared.
- skip tests that need signals when testing on mingw.
18 June 2008: Wouter
- open testbound replay files in binary mode, because fseek/ftell
do not work in ascii-mode on windows. The b does nothing on unix.

View file

@ -7,6 +7,22 @@ NEED_XXD='fwd_compress_c00c.tpkg'
NEED_NC='fwd_compress_c00c.tpkg'
NEED_CURL='06-ianaports.tpkg'
NEED_WHOAMI='07-confroot.tpkg'
NEED_IPV6='fwd_ancil.tpkg fwd_tcp_tc6.tpkg'
NEED_JOBCONTROL='tcp_sigpipe.tpkg'
# test if job control - and also signals - are available (not on mingw).
if wait %% 2>&1 | grep "job control not enabled" >/dev/null 2>&1; then
JOBCONTROL=no
else
JOBCONTROL=yes
fi
# test for ipv6, uses dig 9.4.2 peculiarity (test @ before -v).
if dig @::1 -v >/dev/null 2>&1; then
HAVE_IPV6=yes
else
HAVE_IPV6=no
fi
cd testdata;
sh ../testcode/mini_tpkg.sh clean
@ -48,6 +64,16 @@ for test in `ls *.tpkg`; do
SKIP=1;
fi
fi
if echo $NEED_IPV6 | grep $test >/dev/null; then
if test "$HAVE_IPV6" = no; then
SKIP=1;
fi
fi
if echo $NEED_JOBCONTROL | grep $test >/dev/null; then
if test "$JOBCONTROL" = no; then
SKIP=1;
fi
fi
if test $SKIP -eq 0; then
echo $test
sh ../testcode/mini_tpkg.sh -a ../.. exe $test

View file

@ -18,14 +18,18 @@ if test "$1" = "fake"; then
fi
if test "$1" = "report" || test "$2" = "report"; then
echo "Minitpkg Report"
for result in result.*; do
name=`echo $result | sed -e 's/result\.//'`
for result in *.tpkg; do
name=`basename $result .tpkg`
if test -f ".done-$name"; then
if test "$1" != "-q"; then
echo "** PASSED ** : $name"
fi
else
echo "!! FAILED !! : $name"
if test -f "result.$name"; then
echo "!! FAILED !! : $name"
else
echo ">> SKIPPED<< : $name"
fi
fi
done
exit 0
@ -113,3 +117,10 @@ fi
mv $result ..
cd ..
rm -rf $dir
# compat for windows where deletion may not succeed initially (files locked
# by processes that still have to exit).
if test $? -eq 1; then
echo "minitpkg waiting for processes to terminate"
sleep 2 # some time to exit, and try again
rm -rf $dir
fi

Binary file not shown.

View file

@ -574,9 +574,12 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
log_err("accept failed: %s", strerror(errno));
#else /* USE_WINSOCK */
if(WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEWOULDBLOCK ||
WSAGetLastError() == WSAECONNRESET)
return;
if(WSAGetLastError() == WSAEWOULDBLOCK) {
winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
return ;
}
log_err("accept failed: %s", wsa_strerror(WSAGetLastError()));
#endif
log_addr(0, "remote address is", &c_hdl->repinfo.addr,
@ -671,10 +674,14 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
#endif
log_err("read (in tcp s): %s", strerror(errno));
#else /* USE_WINSOCK */
if(WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAECONNRESET ||
WSAGetLastError() == WSAEWOULDBLOCK)
if(WSAGetLastError() == WSAECONNRESET)
return 0;
if(WSAGetLastError() == WSAEINPROGRESS)
return 1;
if(WSAGetLastError() == WSAEWOULDBLOCK) {
winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
return 1;
}
log_err("read (in tcp s): %s",
wsa_strerror(WSAGetLastError()));
#endif
@ -712,10 +719,14 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
return 1;
log_err("read (in tcp r): %s", strerror(errno));
#else /* USE_WINSOCK */
if(WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAECONNRESET ||
WSAGetLastError() == WSAEWOULDBLOCK)
if(WSAGetLastError() == WSAECONNRESET)
return 0;
if(WSAGetLastError() == WSAEINPROGRESS)
return 1;
if(WSAGetLastError() == WSAEWOULDBLOCK) {
winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
return 1;
}
log_err("read (in tcp r): %s",
wsa_strerror(WSAGetLastError()));
#endif
@ -793,9 +804,12 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
return 1;
log_err("tcp writev: %s", strerror(errno));
#else
if(WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEWOULDBLOCK)
if(WSAGetLastError() == WSAEINPROGRESS)
return 1;
if(WSAGetLastError() == WSAEWOULDBLOCK) {
winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
return 1;
}
log_err("tcp send s: %s",
wsa_strerror(WSAGetLastError()));
#endif
@ -822,9 +836,12 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
return 1;
log_err("tcp send r: %s", strerror(errno));
#else
if(WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEWOULDBLOCK)
if(WSAGetLastError() == WSAEINPROGRESS)
return 1;
if(WSAGetLastError() == WSAEWOULDBLOCK) {
winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
return 1;
}
log_err("tcp send r: %s",
wsa_strerror(WSAGetLastError()));
#endif

View file

@ -126,6 +126,8 @@ void *event_init(uint32_t* time_secs, struct timeval* time_tv)
event_base_free(base);
return NULL;
}
base->tcp_stickies = 0;
base->tcp_reinvigorated = 0;
return base;
}
@ -184,12 +186,20 @@ static int handle_select(struct event_base* base, struct timeval* wait)
struct event* eventlist[WSK_MAX_ITEMS];
WSANETWORKEVENTS netev;
int i, numwait = 0, startidx = 0, was_timeout = 0;
int newstickies = 0;
struct timeval nultm;
#ifndef S_SPLINT_S
if(wait->tv_sec==(time_t)-1)
wait = NULL;
if(wait)
timeout = wait->tv_sec*1000 + wait->tv_usec/1000;
if(base->tcp_stickies) {
wait = &nultm;
nultm.tv_sec = 0;
nultm.tv_usec = 0;
timeout = 0; /* no waiting, we have sticky events */
}
#endif
/* prepare event array */
@ -201,7 +211,6 @@ static int handle_select(struct event_base* base, struct timeval* wait)
}
log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS);
/* do the wait */
if(numwait == 0) {
/* WSAWaitFor.. doesn't like 0 event objects */
@ -232,8 +241,8 @@ static int handle_select(struct event_base* base, struct timeval* wait)
return -1;
/* callbacks */
if(was_timeout)
return 0;
if(base->tcp_stickies)
startidx = 0; /* process all events, some are sticky */
for(i=startidx; i<numwait; i++) {
short bits = 0;
@ -248,37 +257,55 @@ static int handle_select(struct event_base* base, struct timeval* wait)
}
if((netev.lNetworkEvents & FD_READ)) {
if(netev.iErrorCode[FD_READ_BIT] != 0)
log_err("FD_READ_BIT error: %s",
verbose(VERB_ALGO, "FD_READ_BIT error: %s",
wsa_strerror(netev.iErrorCode[FD_READ_BIT]));
bits |= EV_READ;
}
if((netev.lNetworkEvents & FD_WRITE)) {
if(netev.iErrorCode[FD_WRITE_BIT] != 0)
log_err("FD_WRITE_BIT error: %s",
verbose(VERB_ALGO, "FD_WRITE_BIT error: %s",
wsa_strerror(netev.iErrorCode[FD_WRITE_BIT]));
bits |= EV_WRITE;
}
if((netev.lNetworkEvents & FD_CONNECT)) {
if(netev.iErrorCode[FD_CONNECT_BIT] != 0)
log_err("FD_CONNECT_BIT error: %s",
verbose(VERB_ALGO, "FD_CONNECT_BIT error: %s",
wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT]));
bits |= EV_READ;
bits |= EV_WRITE;
}
if((netev.lNetworkEvents & FD_ACCEPT)) {
if(netev.iErrorCode[FD_ACCEPT_BIT] != 0)
log_err("FD_ACCEPT_BIT error: %s",
verbose(VERB_ALGO, "FD_ACCEPT_BIT error: %s",
wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT]));
bits |= EV_READ;
}
if((netev.lNetworkEvents & FD_CLOSE)) {
if(netev.iErrorCode[FD_CLOSE_BIT] != 0)
log_err("FD_CLOSE_BIT error: %s",
verbose(VERB_ALGO, "FD_CLOSE_BIT error: %s",
wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT]));
bits |= EV_READ;
bits |= EV_WRITE;
}
if(bits) {
if(eventlist[i]->is_tcp && eventlist[i]->stick_events) {
verbose(VERB_ALGO, "winsock %d pass sticky %s%s",
eventlist[i]->ev_fd,
(eventlist[i]->old_events&EV_READ)?"EV_READ":"",
(eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
bits |= eventlist[i]->old_events;
}
if(eventlist[i]->is_tcp && bits) {
eventlist[i]->old_events = bits;
eventlist[i]->stick_events = 1;
if((eventlist[i]->ev_events & bits)) {
newstickies = 1;
}
verbose(VERB_ALGO, "winsock %d store sticky %s%s",
eventlist[i]->ev_fd,
(eventlist[i]->old_events&EV_READ)?"EV_READ":"",
(eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
}
if((bits & eventlist[i]->ev_events)) {
verbose(VERB_ALGO, "winsock event callback %p fd=%d "
"%s%s%s%s%s ; %s%s%s",
eventlist[i], eventlist[i]->ev_fd,
@ -296,9 +323,20 @@ static int handle_select(struct event_base* base, struct timeval* wait)
fptr_ok(fptr_whitelist_event(
eventlist[i]->ev_callback));
(*eventlist[i]->ev_callback)(eventlist[i]->ev_fd,
bits, eventlist[i]->ev_arg);
bits & eventlist[i]->ev_events,
eventlist[i]->ev_arg);
}
if(eventlist[i]->is_tcp && bits)
verbose(VERB_ALGO, "winsock %d got sticky %s%s",
eventlist[i]->ev_fd,
(eventlist[i]->old_events&EV_READ)?"EV_READ":"",
(eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
}
if(base->tcp_reinvigorated) {
base->tcp_reinvigorated = 0;
newstickies = 1;
}
base->tcp_stickies = newstickies;
return 0;
}
@ -358,6 +396,8 @@ void event_set(struct event *ev, int fd, short bits,
int event_base_set(struct event_base *base, struct event *ev)
{
ev->ev_base = base;
ev->old_events = 0;
ev->stick_events = 0;
ev->added = 0;
return 0;
}
@ -377,6 +417,7 @@ int event_add(struct event *ev, struct timeval *tv)
return -1;
ev->idx = ev->ev_base->max++;
ev->ev_base->items[ev->idx] = ev;
ev->is_tcp = 0;
if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
BOOL b=0;
@ -393,6 +434,7 @@ int event_add(struct event *ev, struct timeval *tv)
wsa_strerror(WSAGetLastError()));
if(t == SOCK_STREAM) {
/* TCP socket */
ev->is_tcp = 1;
events |= FD_CLOSE;
if( (ev->ev_events&EV_WRITE) )
events |= FD_CONNECT;
@ -414,6 +456,11 @@ int event_add(struct event *ev, struct timeval *tv)
log_err("WSAEventSelect failed: %s",
wsa_strerror(WSAGetLastError()));
}
if(ev->is_tcp && ev->stick_events &&
(ev->ev_events & ev->old_events)) {
/* go to processing the sticky event right away */
ev->ev_base->tcp_reinvigorated = 1;
}
}
if(tv && (ev->ev_events&EV_TIMEOUT)) {
@ -502,4 +549,17 @@ int signal_del(struct event *ev)
return 0;
}
void winsock_tcp_wouldblock(struct event* ev, int eventbits)
{
verbose(VERB_ALGO, "winsock: tcp wouldblock %s",
eventbits==EV_READ?"EV_READ":"EV_WRITE");
ev->old_events &= (~eventbits);
if(ev->old_events == 0)
ev->stick_events = 0;
/* in case this is the last sticky event, we could
* possibly run an empty handler loop to reset the base
* tcp_stickies variable
*/
}
#endif /* USE_WINSOCK */

View file

@ -56,8 +56,12 @@
* the socket has blocked, and the event handler can mark it as such.
* Thus, this file transforms the edge notify from windows to a level notify
* that is compatible with UNIX.
* However, the WSAEventSelect page says that it does do level notify, as long
* The WSAEventSelect page says that it does do level notify, as long
* as you call a recv/write/accept at least once when it is signalled.
* This last bit is not true, even though documented in server2008 api docs
* from microsoft, it does not happen at all. Instead you have to test for
* WSAEWOULDBLOCK on a tcp stream, and only then retest the socket.
* And before that remember the previous result as still valid.
*
* To stay 'fair', instead of emptying a socket completely, the event handler
* can test the other (marked as blocking) sockets for new events.
@ -69,6 +73,8 @@
*
* on winsock, you must use recv() and send() for TCP reads and writes,
* not read() and write(), those work only on files.
*
* Also fseek and fseeko do not work if a FILE is not fopen-ed in binary mode.
*/
#ifndef UTIL_WINSOCK_EVENT_H
@ -122,6 +128,20 @@ struct event_base
uint32_t* time_secs;
/** where to store time in microseconds */
struct timeval* time_tv;
/**
* TCP streams have sticky events to them, these are not
* reported by the windows event system anymore, we have to
* keep reporting those events as present until wouldblock() is
* signalled by the handler back to use.
*/
int tcp_stickies;
/**
* should next cycle process reinvigorated stickies,
* these are stickies that have been stored, but due to a new
* event_add a sudden interest in the event has incepted.
*/
int tcp_reinvigorated;
};
/**
@ -152,6 +172,13 @@ struct event {
int idx;
/** the event handle to wait for new events to become ready */
WSAEVENT hEvent;
/** true if this filedes is a TCP socket and needs special attention */
int is_tcp;
/** remembered EV_ values */
short old_events;
/** should remembered EV_ values be used for TCP streams.
* Reset after WOULDBLOCK is signaled using the function. */
int stick_events;
};
/** create event base */
@ -192,5 +219,13 @@ int signal_del(struct event *);
/** compare events in tree, based on timevalue, ptr for uniqueness */
int mini_ev_cmp(const void* a, const void* b);
/**
* Routine for windows only, where the handling layer can signal that
* a TCP stream encountered WSAEWOULDBLOCK for a stream and thus needs
* retesting the event.
* Pass if EV_READ or EV_WRITE gave wouldblock.
*/
void winsock_tcp_wouldblock(struct event* ev, int eventbit);
#endif /* USE_WINSOCK */
#endif /* UTIL_WINSOCK_EVENT_H */