From ee5ee2007183128c8477d5e9ffe8a9467c96fafc Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Mon, 23 Jun 2008 13:52:03 +0000 Subject: [PATCH] Porting continues. TCP works fine now. git-svn-id: file:///svn/unbound/trunk@1128 be551aaa-1e26-0410-a405-d3ace91eadb9 --- doc/Changelog | 10 +++++ testcode/do-tests.sh | 26 +++++++++++++ testcode/mini_tpkg.sh | 17 +++++++-- testdata/stream_tcp.tpkg | Bin 1835 -> 1857 bytes util/netevent.c | 39 +++++++++++++------ util/winsock_event.c | 80 ++++++++++++++++++++++++++++++++++----- util/winsock_event.h | 37 +++++++++++++++++- 7 files changed, 184 insertions(+), 25 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index 6b236714f..154fd37ab 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/testcode/do-tests.sh b/testcode/do-tests.sh index a50299e9e..4c13c9fb8 100755 --- a/testcode/do-tests.sh +++ b/testcode/do-tests.sh @@ -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 diff --git a/testcode/mini_tpkg.sh b/testcode/mini_tpkg.sh index 6e89a3986..1693c4884 100755 --- a/testcode/mini_tpkg.sh +++ b/testcode/mini_tpkg.sh @@ -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 diff --git a/testdata/stream_tcp.tpkg b/testdata/stream_tcp.tpkg index 17412150574d1d6c6ab14a649ac7de57fd2aa878..c0c147754067b4bac420d471ae325ca2d046bb1f 100644 GIT binary patch literal 1857 zc-jF$2fp|piwFQbm|sW$1ML}WbJ|AGU%6kgk(oG|R6-IDwKz}{j2kxz5RB_)+76MW z15|^g=tPLy>3{FuNdifRcsg;MHsyjrcel5@x9?S07*KOQ3N2r;ouIV$IfklMRHItO zUsW|~75=N?l9$APlGxs;P<7+obb91Iw|afyO_)26s^H#bd zMrC%*X5OR@u15-JJJdqK;AsV69eeD|XdR@5d+9A)Tfr5H6s&3Bd5A@l1ctyh=QNtx zp6q&|{BA*mYkB5b=4|S*P~aYW!4mZ$|KYh5`HasfcqrL1Z9BjvO*a%3|7k}@!=B(% zB41j(|N61r|7~X75slmYzf!Al|F4!+y{ZZS*Np1U|LbK;T>9`^OVITrKP~bvoD=j6Z3(`g;6A@lW+nf6s3f!xz!LCNNe%o1cMky*f$xYcAcD<&TN5b zzoM|R-T%30?uN!~{$JCzwg0PCk^gJ@&j0UY?8Ck+=RE>sd7tb9^A>?cA)Hc}n~Y26 zJ&KBFc34iS3r={z_%1ruFCdRWQA$eaUriJQQ{of9!NZ3Mq7D05D%|gGqp?CDfHUYb zTZG@h_TU;f5ix4iTe=_+;l`CSo56T#BM0KKcye((>YpCt*4(_Jz|hUJJJ2lI^nJ-) z;F{iisI9QXB~A=|-hI|P?{34D+P#5~esDri?>n@7#Qy_&M>KBn|FVk7KGXkU{x^2{ z|6ayT{}1SWdOx-Sd7s9z9vpWS3>@uw| zZ%|AK-WfDzw##G=;xgilBl$ew;*j1hr;arhp{g@@D;;vRxTFvrD^0yQEiHw4mo6Q* zl*Ti5NOTHhA69JTYay3G6N9CK?VgBL@Q}n&u~B@Gz8qhOAGTagL`42-!I=nKB3M{~ zOyPi)L~r@)QRyHf&V$lHvLAJI0wUp*?>>dxTMKBy;!-@VWElr(VOMC-m!@?!2}IcL z4>}Er+a`9DMVyopP#Hh(Qy(iq3eBXeP01q_+1E13ET$$KWn-D)26-(_C-R7>QHRij zi3bb+8{rY~6j|V6x{6~-BPf~c*`gwHT z9}Nd@8k(+>!bR(JI2t}5bj})ORkYWDP7?;#4HXXgFFb8PaeXRUeDVYx2_J2b6bgx5 zqE!|(?v~?8Kz)#ky2KaOIWMu%LLm~BjU_!GpPWh&za+kOiE6z%#3wY)=BrQ}oQnei$TrZ3S_dsCg!Y*n8o~K=H3y}$h;#w+eB5X$SR$6?B^G^QCXlv!W zTo)EPAW{~_DD-pi5)%n^`6FJLzgaoptfDRzl2sHWZYSM1B4r3BR=bhhneYK`ER4vp z=vHcJ!*=jfLdTg)%xEtIJja%wJ-KeelznY=zqW?3rUHx|-<3{}#h3~JZ z0!%0PSFIPF1}{MlR~3}}0pjv$!Z+R~L0*80C0-;wvTWeh!68pNFFLWnP+pID6dpSP zViM>~;7lUB{9TxMovp;hKr@=ca=BFK2XpSvD3%lRr0iH>e_@Z)7hwbO!`Icu>co$y#_|1`$L8t%n4ZI#es|DR& zXE5juNbC5=^RprLDE{@xvB_DdJv{Ao;q`gvj6V>JTZPkZp|#p+bhNL1ML}WbJ|AGU%6kgk(oG|R6-9PDGt;G3{FuNdifRxHGXm)0B;aPJ4H|d;7TCTd^>p=3*RLzG6E;W$!*fMQAi? z@v~mdJrmf|a73ftsH#zA!Yg&B|)VpE-dHA2(e;@W`846|xS>7l6z`Q81 zD1;;5XVe8JJYc*xpyXGOC!i=5CG@YR3Jz0}8Nb8h$0?x={m3O^ z*t0?l_7g7v#|6HOGhEzB!=NSsMb zU;YH|movwj!IXErKjbTNNl6S9C^B)#6U&A&QaXe(??@De`g%%m2@@wkN`jmTTu2mm z)IEa_5e=>tLamtxQagTy<#MUePv*j(Q^oQYC>1AMSyAN6)AWX-;y>-Ee9?b7xac2` z&j!QMjk(Z)(>}D(HHB65_G4|eFsb~V1hPv(O_vnQK|eVm%5R1d1J?^-@S~J=wZSq& zn0r%BjUk%9CdA{H$UA^UEZZE{BGc9M z8MUs!blH*y64$^qpgu^Ns_3d>s7h6pQi6G9a51tX7R5&q(Y`{T3ooFMaFhzqEw<(F zdJ$n{5npcnB8xRT$7ts%_wOkisOewecN@qVUqDVYRZ`ghx1ax(=T7eCjJf6fR}G`F z&i@R9pa0c{u{-}C0vHWG(x6F7_4t7f13*$7YDsPXY%{=q12&(6pxdE&f5bHv(N% zpOZJHP!MrGpRW4|i%}gfr4bB2%%wkgm7zaVv1cCh0EhW9n0vZ&763 zdPV1clbi*)MJYaBQ_jSul0_ndjA#KXE)JdO(+N*9kl-0!J*eFzC#ExxknC5qt$hCe z@3On#aa;U1YODCKSF4EE8fsnN#s5RVA@Bn=&I01wfXJoGgW>7-cwxw1EJ%4YdJRTh zRSD_!N5gmHmpvSVm+DdX6?neo*%Us6*FOGoqGZ@Rd;Jc68bYT7{XuUy91Kb4_=k)0 z5m=soJ$7tz-s_G|2YvYIqIb?41n(`S(|)P5>gn{)-}Z(pd?}NuCsOqK$M-9czD**% zD3bnAA{pC6GKwM@S&?qqe|!AnetAbec1!#lyyly)|JDsd-NpYyz>WGJn*D34{tc7r zNvr(i36zJO{_)@qJcF81tHRT#BwJuNudXRy+JkM@ZPXBw_PU3r}C(wR6Uo&~ZGE3t~XkjtQ*R#tfB2p-28Iz4WcA7vNE5lLgq(s)4?cxl0z#wQIX zRv=S2U=?w<{Ozc6kW=SDQDb>MB%&Z=A$jr+|eef#PO&u*wCys*jSoUD*LF9iUq5xhb z22q9 zG#|Dz4Okff5GSEfo&=6JE4<%{!eHBcDCP;K8PiSO3zgl0Jd5#zS!um#xaW z#1ZX^O+QxLXg*KXw-_#^SIOEl%xA-2#p*R**zy1|F6C`EGTv9{2} z$kldiQL_|^dn71xWtTNEUR1@lFqu*)ueGvf!sZlLr6rTN?Bws9wN~-UZGj0BMb5$j zg?$cQJGkY!yopQZ)szD+D%w&Zc|)y=n9_|YQjTHjsT5?S zNt<$p9eh3Tnf%XtpzptU*VESZAGIdF|Ei5${`U}YGyn4*`1@~$OPcb1j>o@F{rC!O z53aEj3FF4>EnN_Vu;a>^&-p%!5{PD+wWJvei*Q`7Cv%R)U(Zr1$^My)&YbugXk~hD Z(A)fdW(Pai!4B>V{sH&ktk(c2008FCnB@Qf diff --git a/util/netevent.c b/util/netevent.c index 9cf71b5f9..3e5e1c991 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -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 diff --git a/util/winsock_event.c b/util/winsock_event.c index c1ccb5aad..343367562 100644 --- a/util/winsock_event.c +++ b/util/winsock_event.c @@ -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; iis_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 */ diff --git a/util/winsock_event.h b/util/winsock_event.h index 6dec399da..2851b0eeb 100644 --- a/util/winsock_event.h +++ b/util/winsock_event.h @@ -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 */ -- 2.47.2