diff --git a/CHANGES b/CHANGES index 127c273..32bb06a 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,9 @@ allocates space, it also needs to be in the initialized space. add -D_REENTRANT to CFLAGS so libowfat can be used in multi-threaded programs + further Windoze support (test/io5.c works, gatling still doesn't) + This is just to get gatling to work, I may remove it again after + that. 0.24: fix scan_to_sa (Tim Lorenz) diff --git a/GNUmakefile b/GNUmakefile index 2c9d1e7..712e5a9 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -14,7 +14,9 @@ buffer.a mmap.a taia.a tai.a dns.a case.a mult.a array.a io.a textcode.a all: t $(LIBS) libowfat.a libsocket -CC=gcc +CROSS= +#CROSS=i686-mingw- +CC=$(CROSS)gcc CFLAGS=-pipe -W -Wall -O2 -fomit-frame-pointer #CFLAGS=-pipe -Os -march=pentiumpro -mcpu=pentiumpro -fomit-frame-pointer -fschedule-insns2 -Wall @@ -126,8 +128,8 @@ $(TAIA_OBJS) $(TAI_OBJS) $(CASE_OBJS) $(ARRAY_OBJS) $(MULT_OBJS) \ $(IO_OBJS) libowfat.a: $(ALL_OBJS) - ar cr $@ $(ALL_OBJS) - -ranlib $@ + $(CROSS)ar cr $@ $(ALL_OBJS) + -$(CROSS)ranlib $@ CFLAGS+=-I. @@ -290,3 +292,5 @@ Makefile: GNUmakefile dep libdep -e 's/^CURNAME=.*/'CURNAME=$(CURNAME)/ \ -e 's/ Makefile//' < GNUmakefile >> $@ +windoze: + $(MAKE) DIET= CROSS=i686-mingw32- diff --git a/io/io_canread.c b/io/io_canread.c index bc22c11..a17a3fe 100644 --- a/io/io_canread.c +++ b/io/io_canread.c @@ -3,6 +3,10 @@ #include #include "io_internal.h" +#ifdef __MINGW32__ +#include +#endif + int64 io_canread() { io_entry* e; if (first_readable==-1) @@ -26,7 +30,18 @@ int64 io_canread() { first_readable=e->next_read; e->next_read=-1; debug_printf(("io_canread: dequeue %lld from normal read queue (next is %ld)\n",r,first_readable)); - if (e->wantread && e->canread) { + +#ifdef __MINGW32__ +// printf("event on %d: wr %d rq %d aq %d\n",(int)r,e->wantread,e->readqueued,e->acceptqueued); +#endif + + if (e->wantread && +#ifdef __MINGW32__ + (e->canread || e->acceptqueued==1 || e->readqueued==1) +#else + e->canread +#endif + ) { #ifdef HAVE_SIGIO e->next_read=alt_firstread; alt_firstread=r; diff --git a/io/io_canwrite.c b/io/io_canwrite.c index f28ef12..1acbc3c 100644 --- a/io/io_canwrite.c +++ b/io/io_canwrite.c @@ -26,7 +26,13 @@ int64 io_canwrite() { first_writeable=e->next_write; e->next_write=-1; debug_printf(("io_canwrite: dequeue %lld from normal write queue (next is %ld)\n",r,first_writeable)); - if (e->wantwrite && e->canwrite) { + if (e->wantwrite && +#ifdef __MINGW32__ + (e->canwrite || e->sendfilequeued==1) +#else + e->canwrite +#endif + ) { #ifdef HAVE_SIGIO e->next_write=alt_firstwrite; alt_firstwrite=r; diff --git a/io/io_fd.c b/io/io_fd.c index e361ddf..57cb3aa 100644 --- a/io/io_fd.c +++ b/io/io_fd.c @@ -50,8 +50,10 @@ int io_fd(int64 d) { long r; if ((r=fcntl(d,F_GETFL,0)) == -1) return 0; /* file descriptor not open */ + printf("io_fd(%d)\n",(int)d); #endif if (!(e=array_allocate(&io_fds,sizeof(io_entry),d))) return 0; + if (e->inuse) return 1; byte_zero(e,sizeof(io_entry)); e->inuse=1; #ifdef __MINGW32__ @@ -90,8 +92,13 @@ int io_fd(int64 d) { } #endif #ifdef __MINGW32__ - io_comport=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,1); - if (io_comport) io_waitmode=COMPLETIONPORT; + io_comport=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0); + if (io_comport) { + io_waitmode=COMPLETIONPORT; + } else { + errno=EINVAL; + return 0; + } #endif } #if defined(HAVE_SIGIO) @@ -103,6 +110,14 @@ int io_fd(int64 d) { #endif fcntl(d,F_SETFL,fcntl(d,F_GETFL)|O_NONBLOCK|O_ASYNC); } +#endif +#ifdef __MINGW32__ + if (io_comport) { + if (CreateIoCompletionPort((HANDLE)d,io_comport,(ULONG_PTR)d,0)==0) { + errno=EBADF; + return 0; + } + } #endif return 1; } diff --git a/io/io_mmapwritefile.c b/io/io_mmapwritefile.c index 1fdd7f9..87d8e74 100644 --- a/io/io_mmapwritefile.c +++ b/io/io_mmapwritefile.c @@ -6,8 +6,8 @@ #include #else #include -#include #endif +#include #define BUFSIZE 16384 diff --git a/io/io_sendfile.c b/io/io_sendfile.c index 5c3b20a..9e538b8 100644 --- a/io/io_sendfile.c +++ b/io/io_sendfile.c @@ -112,6 +112,38 @@ int64 io_sendfile(int64 s,int64 fd,uint64 off,uint64 n) { } #endif +#elif defined(__MINGW32__) + +#include +#include + +int64 io_sendfile(int64 out,int64 in,uint64 off,uint64 bytes) { + io_entry* e=array_get(&io_fds,sizeof(io_entry),out); + if (!e) { errno=EBADF; return -3; } + if (e->sendfilequeued==1) { + /* we called TransmitFile, and it returned. */ + e->sendfilequeued=2; + errno=e->errorcode; + if (e->bytes_written==-1) return -1; + if (e->bytes_written!=bytes) { /* we wrote less than caller wanted to write */ + e->sendfilequeued=1; /* so queue next request */ + off+=e->bytes_written; + bytes-=e->bytes_written; + e->os.Offset=off; + e->os.OffsetHigh=(off>>32); + TransmitFile(out,(HANDLE)in,bytes>0xffff?0xffff:bytes,0,&e->os,0,TF_USE_KERNEL_APC); + } + return e->bytes_written; + } else { + e->sendfilequeued=1; + e->os.Offset=off; + e->os.OffsetHigh=(off>>32); + /* we always write at most 64k, so timeout handling is possible */ + if (!TransmitFile(out,(HANDLE)in,bytes>0xffff?0xffff:bytes,0,&e->os,0,TF_USE_KERNEL_APC)) + return -3; + } +} + #else #include diff --git a/io/io_tryread.c b/io/io_tryread.c index a3d1b58..5c7ee2b 100644 --- a/io/io_tryread.c +++ b/io/io_tryread.c @@ -1,8 +1,74 @@ #include #include +#ifdef __MINGW32__ +#include +#include +#else #include +#endif #include #include "io_internal.h" +#include "byte.h" + +#ifdef __MINGW32__ +/* In Windows, I/O works differently. */ +/* Instead of calling read until it says EAGAIN, you call read in + * overlapping mode, and then wait for it to finish. + * We map this to our API by having the first call to io_tryread always + * return EAGAIN, wait for the I/O completion port to tell us the read + * is finished, and then return the data we actually read the next time + * we are called. */ + +int64 io_tryread(int64 d,char* buf,int64 len) { + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (!e) { errno=EBADF; return -3; } + if (len<0) { errno=EINVAL; return -3; } + if (e->readqueued==2) { + int x=e->bytes_read; + if (e->errorcode) { + errno=e->errorcode; + e->canread=0; + return -3; + } + if (x>len) x=len; + if (x) { + byte_copy(buf,x,e->inbuf); + byte_copy(e->inbuf,e->bytes_read-x,e->inbuf+x); + e->bytes_read-=x; + } + if (!e->bytes_read) { + e->canread=0; + if (len>x) { + /* queue next read */ + if (len>sizeof(e->inbuf)) len=sizeof(e->inbuf); + if (ReadFile((HANDLE)d,e->inbuf,len,0,&e->or)) { + e->canread=1; + e->readqueued=2; + e->next_write=first_writeable; + first_writeable=d; + } else if ((e->errorcode=GetLastError())==ERROR_IO_PENDING) { + e->readqueued=1; + e->errorcode=0; + } else { + e->canread=1; + e->readqueued=2; + e->next_write=first_writeable; + first_writeable=d; + } + } + } + return x; + } + if (!e->readqueued) { + if (len>sizeof(e->inbuf)) len=sizeof(e->inbuf); + if (ReadFile((HANDLE)d,e->inbuf,len,0,&e->or)) + e->readqueued=1; + } + errno=EAGAIN; + return -1; +} + +#else int64 io_tryread(int64 d,char* buf,int64 len) { long r; @@ -48,3 +114,5 @@ int64 io_tryread(int64 d,char* buf,int64 len) { } return r; } + +#endif diff --git a/io/io_trywrite.c b/io/io_trywrite.c index bde617e..ba69695 100644 --- a/io/io_trywrite.c +++ b/io/io_trywrite.c @@ -1,9 +1,63 @@ #include #include +#ifdef __MINGW32__ +#include +#else #include +#endif #include #include "io_internal.h" +#ifdef __MINGW32__ +/* All the Unix trickery is unsupported on Windows. Instead, one is + * supposed to do the whole write in overlapping mode and then get + * notified via an I/O completion port when it's done. */ + +/* So we assume io_trywrite is not used so much and do the overlapping + * stuff on I/O batches. */ + +int64 io_trywrite(int64 d,const char* buf,int64 len) { + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + int r; + if (!e) { errno=EBADF; return -3; } + if (!e->nonblock) { + DWORD written; + if (WriteFile((HANDLE)d,buf,len,&written,0)) + return written; + else + return winsock2errno(-3); + } else { + if (e->writequeued) { + errno=EAGAIN; + return -1; + } + if (e->canwrite) { + e->canwrite=0; + e->next_write=-1; + if (e->errorcode) { + errno=winsock2errno(e->errorcode); + return -3; + } + return e->bytes_written; + } else { + if (WriteFile((HANDLE)d,buf,len,&e->errorcode,&e->ow)) + return e->errorcode; /* should not happen */ + else if (GetLastError()==ERROR_IO_PENDING) { + e->writequeued=1; + errno=EAGAIN; + e->errorcode=0; + return -1; + } else { + winsock2errno(-1); + e->errorcode=errno; + return -3; + } + } + } +} + +#else + int64 io_trywrite(int64 d,const char* buf,int64 len) { long r; struct itimerval old,new; @@ -49,3 +103,5 @@ int64 io_trywrite(int64 d,const char* buf,int64 len) { } return r; } + +#endif diff --git a/io/io_waitread.c b/io/io_waitread.c index f89eb6f..8969d2f 100644 --- a/io/io_waitread.c +++ b/io/io_waitread.c @@ -1,8 +1,34 @@ #include +#ifdef __MINGW32__ +#include +#else #include +#endif #include #include "io_internal.h" +#ifdef __MINGW32__ + +int64 io_waitread(int64 d,char* buf,int64 len) { + long r; + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (!e) { errno=EBADF; return -3; } + if (e->nonblock) { + unsigned long i=0; + ioctlsocket(d, FIONBIO, &i); + } + r=read(d,buf,len); + if (e->nonblock) { + unsigned long i=1; + ioctlsocket(d, FIONBIO, &i); + } + if (r==-1) + r=-3; + return r; +} + +#else + int64 io_waitread(int64 d,char* buf,int64 len) { long r; struct pollfd p; @@ -25,3 +51,5 @@ again: } return r; } + +#endif diff --git a/io/io_waituntil2.c b/io/io_waituntil2.c index cf9cd42..deb92a7 100644 --- a/io/io_waituntil2.c +++ b/io/io_waituntil2.c @@ -8,7 +8,11 @@ #endif #include #include +#ifdef __MINGW32__ +#include +#else #include +#endif #include #ifdef HAVE_KQUEUE #include @@ -28,7 +32,9 @@ #endif int64 io_waituntil2(int64 milliseconds) { +#ifndef __MINGW32__ struct pollfd* p; +#endif long i,j,r; if (!io_wanted_fds) return 0; #ifdef HAVE_EPOLL @@ -195,6 +201,78 @@ int64 io_waituntil2(int64 milliseconds) { } dopoll: #endif +#ifdef __MINGW32__ + DWORD numberofbytes; + ULONG_PTR x; + LPOVERLAPPED o; + if (first_readable!=-1 || first_writeable!=-1) return; + if (GetQueuedCompletionStatus(io_comport,&numberofbytes,&x,&o,milliseconds==-1?milliseconds:INFINITE)) { + io_entry* e=array_get(&io_fds,sizeof(io_entry),x); + if (!e) return 0; + e->errorcode=0; + if (o==&e->or && e->readqueued==1) { + e->readqueued=2; + e->canread=1; + e->bytes_read=numberofbytes; + e->next_read=first_readable; + first_readable=x; +// printf("read %lu bytes on fd %lu: %p\n",numberofbytes,x,e); + } else if (o==&e->ow && e->writequeued==1) { + e->writequeued=2; + e->canwrite=1; + e->bytes_written=numberofbytes; + e->next_write=first_writeable; + first_writeable=x; + } else if (o==&e->or && e->acceptqueued==1) { + e->acceptqueued=2; + e->canread=1; + e->next_read=first_readable; + first_readable=x; + } else if (o==&e->ow && e->connectqueued==1) { + e->connectqueued=2; + e->canwrite=1; + e->next_write=first_writeable; + first_writeable=x; + } else if (o==&e->os && e->sendfilequeued==1) { + e->sendfilequeued=2; + e->canwrite=1; + e->bytes_written=numberofbytes; + e->next_write=first_writeable; + first_writeable=x; + } + return 1; + } else { + /* either the overlapped I/O request failed or we timed out */ + DWORD err; + io_entry* e; + if (!o) return 0; /* timeout */ + /* we got a completion packet for a failed I/O operation */ + err=GetLastError(); + if (err==WAIT_TIMEOUT) return 0; /* or maybe not */ + e=array_get(&io_fds,sizeof(io_entry),x); + if (!e) return 0; /* WTF?! */ + e->errorcode=err; + if (o==&e->or && (e->readqueued || e->acceptqueued)) { + if (e->readqueued) e->readqueued=2; else + if (e->acceptqueued) e->acceptqueued=2; + e->canread=1; + e->bytes_read=-1; + e->next_read=first_readable; + first_readable=x; + } else if ((o==&e->ow || o==&e->os) && + (e->writequeued || e->connectqueued || e->sendfilequeued)) { + if (o==&e->ow) { + if (e->writequeued) e->writequeued=2; else + if (e->connectqueued) e->connectqueued=2; + } else if (o==&e->os) e->sendfilequeued=2; + e->canwrite=1; + e->bytes_written=-1; + e->next_write=first_writeable; + first_writeable=x; + } + return 1; + } +#else for (i=r=0; i +#ifdef __MINGW32__ +#include +#else #include +#endif #include #include "io_internal.h" +#ifdef __MINGW32__ + +int64 io_waitwrite(int64 d,const char* buf,int64 len) { + long r; + io_entry* e=array_get(&io_fds,sizeof(io_entry),d); + if (!e) { errno=EBADF; return -3; } + if (e->nonblock) { + unsigned long i=0; + ioctlsocket(d, FIONBIO, &i); + } + r=write(d,buf,len); + if (e->nonblock) { + unsigned long i=1; + ioctlsocket(d, FIONBIO, &i); + } + if (r==-1) + r=-3; + return r; +} + +#else + int64 io_waitwrite(int64 d,const char* buf,int64 len) { long r; struct pollfd p; @@ -26,3 +52,5 @@ again: } return r; } + +#endif diff --git a/io/io_wantread.c b/io/io_wantread.c index 1d6b9cb..807282e 100644 --- a/io/io_wantread.c +++ b/io/io_wantread.c @@ -19,6 +19,9 @@ #include #include #endif +#ifdef __MINGW32__ +#include +#endif void io_wantread(int64 d) { int newfd; @@ -69,6 +72,34 @@ void io_wantread(int64 d) { first_readable=d; } } +#endif +#ifdef __MINGW32__ + if (e->listened) { + if (e->next_accept==0) e->next_accept=socket(AF_INET,SOCK_STREAM,0); + if (e->next_accept!=-1) { + AcceptEx(d,e->next_accept,e->inbuf,0,200,200,&e->errorcode,&e->or); + e->acceptqueued=1; + } + } else if (!e->wantread) { + if (ReadFile((HANDLE)d,e->inbuf,sizeof(e->inbuf),&e->errorcode,&e->or)) { +queueread: + /* had something to read immediately. Damn! */ + e->readqueued=0; + e->canread=1; + e->bytes_read=e->errorcode; + e->errorcode=0; + e->next_read=first_readable; + first_readable=d; + return; + } else if (GetLastError()==ERROR_IO_PENDING) + e->readqueued=1; + else + goto queueread; +#if 0 + e->next_read=first_readable; + first_readable=d; +#endif + } #endif e->wantread=1; } diff --git a/io/io_wantwrite.c b/io/io_wantwrite.c index 2113c95..c335ba2 100644 --- a/io/io_wantwrite.c +++ b/io/io_wantwrite.c @@ -69,6 +69,12 @@ void io_wantwrite(int64 d) { first_writeable=d; } } +#endif +#ifdef __MINGW32__ + if (!e->wantwrite) { + e->next_write=first_writeable; + first_writeable=d; + } #endif e->wantwrite=1; } diff --git a/io/iob_prefetch.c b/io/iob_prefetch.c index 8285363..1dbf1d5 100644 --- a/io/iob_prefetch.c +++ b/io/iob_prefetch.c @@ -1,4 +1,15 @@ #include "iob_internal.h" + +#ifdef __MINGW32__ + +/* not supported */ +void iob_internal(io_batch* b,uint64 bytes) { + (void)b; + (void)bytes; +} + +#else + #include #include #include @@ -40,3 +51,5 @@ void iob_prefetch(io_batch* b,uint64 bytes) { } (void)x; } + +#endif diff --git a/io/iob_send.c b/io/iob_send.c index 8a0b9e4..ff16a36 100644 --- a/io/iob_send.c +++ b/io/iob_send.c @@ -1,3 +1,82 @@ +#ifdef __MINGW32__ + +#include +#include +#include +#include "io_internal.h" +#include "iob_internal.h" + +int64 iob_send(int64 s,io_batch* b) { + /* Windows has a sendfile called TransmitFile, which can send one + * header and one trailer buffer. */ + iob_entry* x,* last; + io_entry* e; + int64 sent; + int i; + + if (b->bytesleft==0) return 0; + sent=-1; + e=array_get(&io_fds,sizeof(io_entry),s); + if (!e) { errno=EBADF; return -3; } + if (!(x=array_get(&b->b,sizeof(iob_entry),b->next))) + return -3; /* can't happen error */ + last=(iob_entry*)(((char*)array_start(&b->b))+array_bytes(&b->b)); + + if (e->canwrite || e->sendfilequeued==1) { + /* An overlapping write finished. Reap the result. */ + if (e->bytes_written==-1) return -3; + if (e->bytes_writtenn) { + sent=e->bytes_written; + if (x->n < e->bytes_written) { + e->bytes_written-=x->n; + x->n=0; + ++x; + } + x->n -= e->bytes_written; + x->offset += e->bytes_written; + b->bytesleft -= e->bytes_written; + } + e->canwrite=0; e->sendfilequeued=0; + } + + for (i=0; x+isendfilequeued=1; + memset(&tfb,0,sizeof(tfb)); + memset(&e[i].os,0,sizeof(e[i].os)); + e[i].os.Offset=x[i].offset; + e[i].os.OffsetHigh=(x[i].offset>>32); + if (!TransmitFile(s,(HANDLE)x[i].fd, + x[i].n+tfb.HeadLength>0xffff?0xffff:x[i].n, + 0,&e[i].os,&tfb,TF_USE_KERNEL_APC)) + return -3; + return sent; + } else { + e->writequeued=1; + if (!WriteFile(s,x[i].buf+x[i].offset,x[i].n,0,&e->ow)) + return -3; + return sent; + } + } else { + e->sendfilequeued=1; + memset(&e[i].os,0,sizeof(e[i].os)); + e[i].os.Offset=x[i].offset; + e[i].os.OffsetHigh=(x[i].offset>>32); + if (!TransmitFile(s,(HANDLE)x[i].fd, + x[i].n>0xffff?0xffff:x[i].n, + 0,&e[i].os,0,TF_USE_KERNEL_APC)) + return -3; + return sent; + } +} + +#else + #include "havebsdsf.h" #include #include @@ -132,3 +211,5 @@ eagain: abort: return total; } + +#endif diff --git a/io_internal.h b/io_internal.h index 34411f7..5343a21 100644 --- a/io_internal.h +++ b/io_internal.h @@ -1,5 +1,9 @@ #include "io.h" #include "array.h" +#ifdef __MINGW32__ +#include "socket.h" +extern HANDLE io_comport; +#else #include "haveepoll.h" #include "havekqueue.h" #include "havedevpoll.h" @@ -8,10 +12,6 @@ #define _GNU_SOURCE #include #endif - -#ifdef __MINGW32__ -#include "socket.h" -extern HANDLE io_comport; #endif typedef struct { @@ -22,6 +22,14 @@ typedef struct { unsigned int canwrite:1; unsigned int nonblock:1; unsigned int inuse:1; +#ifdef __MINGW32__ + unsigned int readqueued:2; + unsigned int writequeued:2; + unsigned int acceptqueued:2; + unsigned int connectqueued:2; + unsigned int sendfilequeued:2; + unsigned int listened:1; +#endif long next_read; long next_write; void* cookie; @@ -29,8 +37,12 @@ typedef struct { long maplen; uint64 mapofs; #ifdef __MINGW32__ - OVERLAPPED o; + OVERLAPPED or,ow,os; /* overlapped for read+accept, write+connect, sendfile */ HANDLE /* fd, */ mh; + char inbuf[8192]; + int bytes_read,bytes_written; + DWORD errorcode; + SOCKET next_accept; #endif } io_entry; diff --git a/socket/socket_accept4.c b/socket/socket_accept4.c index 7b9732d..61ced33 100644 --- a/socket/socket_accept4.c +++ b/socket/socket_accept4.c @@ -7,12 +7,75 @@ #include "socket.h" #include "havesl.h" +#ifdef __MINGW32__ +#include +#include +#include +#include +#include "io_internal.h" +#endif + int socket_accept4(int s,char *ip,uint16 *port) { struct sockaddr_in si; socklen_t len = sizeof si; int fd; - if ((fd=accept(s,(void*) &si,&len))==-1) - return winsock2errno(-1); + +#ifdef __MINGW32__ + io_entry* e=array_get(&io_fds,sizeof(io_entry),s); + if (e && e->inuse) { + int sa2len; + fd=-1; + if (e->acceptqueued==1) { + errno=EAGAIN; + return -1; + } + if (e->acceptqueued==2) { +incoming: + /* incoming! */ + { + struct sockaddr* x,* y; + GetAcceptExSockaddrs(e->inbuf,0,200,200,&x,&sa2len,&y,&len); + if (len>sizeof(si)) len=sizeof(si); + memcpy(&si,y,len); + } + fd=e->next_accept; + e->next_accept=0; + if (e->nonblock) { + if (io_fd(fd)) { + io_entry* f=array_get(&io_fds,sizeof(io_entry),fd); + if (f) { + f->nonblock=1; +// printf("setting fd %lu to non-blocking\n",(int)fd); + } + } + } + } + + /* no accept queued, queue one now. */ + if (e->next_accept==0) { + e->next_accept=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if (e==-1) + return winsock2errno(-1); + } + if (AcceptEx(s,e->next_accept,e->inbuf,0,200,200,&e->errorcode,&e->or)) + goto incoming; + if (WSAGetLastError() != ERROR_IO_PENDING) + return winsock2errno(-1); + e->acceptqueued=1; + if (fd==-1) { + errno=EAGAIN; + return fd; + } + + } else { +#endif + + if ((fd=accept(s,(void*) &si,&len))==-1) + return winsock2errno(-1); + +#ifdef __MINGW32__ + } +#endif if (ip) *(uint32*)ip = *(uint32*)&si.sin_addr; if (port) uint16_unpack_big((char *) &si.sin_port,port); return fd; diff --git a/socket/socket_accept6.c b/socket/socket_accept6.c index ba49f0a..cad1c37 100644 --- a/socket/socket_accept6.c +++ b/socket/socket_accept6.c @@ -12,6 +12,14 @@ #include "havesl.h" #include "havescope.h" +#ifdef __MINGW32__ +#include +#include +#include +#include +#include "io_internal.h" +#endif + int socket_accept6(int s,char* ip,uint16* port,uint32* scope_id) { #ifdef LIBC_HAS_IP6 @@ -22,9 +30,61 @@ int socket_accept6(int s,char* ip,uint16* port,uint32* scope_id) socklen_t dummy = sizeof sa; int fd; - fd = accept(s,(struct sockaddr *) &sa,&dummy); - if (fd == -1) - return winsock2errno(-1); +#ifdef __MINGW32__ + io_entry* e=array_get(&io_fds,sizeof(io_entry),s); + if (e && e->inuse) { + int sa2len; + fd=-1; + if (e->acceptqueued==1) { + errno=EAGAIN; + return -1; + } + if (e->acceptqueued==2) { +incoming: + /* incoming! */ + { + struct sockaddr* x,* y; + GetAcceptExSockaddrs(e->inbuf,0,200,200,&x,&sa2len,&y,&dummy); + if (dummy>sizeof(sa)) dummy=sizeof(sa); + memcpy(&sa,y,dummy); + } + fd=e->next_accept; + e->next_accept=0; + if (e->nonblock) { + if (io_fd(fd)) { + io_entry* f=array_get(&io_fds,sizeof(io_entry),fd); + if (f) { + f->nonblock=1; +// printf("setting fd %lu to non-blocking\n",(int)fd); + } + } + } + } + + /* no accept queued, queue one now. */ + if (e->next_accept==0) { + e->next_accept=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if (e==-1) + return winsock2errno(-1); + } + if (AcceptEx(s,e->next_accept,e->inbuf,0,200,200,&e->errorcode,&e->or)) + goto incoming; + if (WSAGetLastError() != ERROR_IO_PENDING) + return winsock2errno(-1); + e->acceptqueued=1; + if (fd==-1) { + errno=EAGAIN; + return fd; + } + + } else { +#endif + fd = accept(s,(struct sockaddr *) &sa,&dummy); + if (fd == -1) + return winsock2errno(-1); +#ifdef __MINGW32__ + } +#endif #ifdef LIBC_HAS_IP6 if (sa.sin6_family==AF_INET) { diff --git a/socket/socket_listen.c b/socket/socket_listen.c index 51e2e17..431d3aa 100644 --- a/socket/socket_listen.c +++ b/socket/socket_listen.c @@ -1,10 +1,33 @@ #include -#ifndef __MINGW32__ +#ifdef __MINGW32__ +#include "io_internal.h" +#include +#else #include #endif #include "socket.h" #include "windoze.h" int socket_listen(int s,unsigned int backlog) { - return winsock2errno(listen(s, backlog)); +#ifdef __MINGW32__ + io_entry* e; + int r = listen(s, backlog); + if (r==-1) return winsock2errno(-1); + e=array_get(&io_fds,sizeof(io_entry),s); + if (e && e->inuse) { + e->listened=1; + if (e->wantread) { + /* queue a non-blocking accept */ + DWORD received; + e->next_accept=socket(AF_INET,SOCK_STREAM,0); + if (e->next_accept!=-1) { + AcceptEx(s,e->next_accept,e->inbuf,0,200,200,&received,&e->or); + e->acceptqueued=1; + } + } + } + return r; +#else + return listen(s, backlog); +#endif } diff --git a/test/io5.c b/test/io5.c index b0bd83e..dfd2ad8 100644 --- a/test/io5.c +++ b/test/io5.c @@ -15,19 +15,19 @@ int main() { buffer_putnlflush(buffer_2); return 111; } - if (socket_listen(s,16)==-1) { - buffer_puts(buffer_2,"socket_listen: "); + if (!io_fd(s)) { + buffer_puts(buffer_2,"io_fd: "); buffer_puterror(buffer_2); buffer_putnlflush(buffer_2); return 111; } - io_nonblock(s); - if (!io_fd(s)) { - buffer_puts(buffer_2,"io_fd: "); + if (socket_listen(s,16)==-1) { + buffer_puts(buffer_2,"socket_listen: "); buffer_puterror(buffer_2); buffer_putnlflush(buffer_2); return 111; } + io_nonblock(s); io_wantread(s); buffer_puts(buffer_2,"listening on port 1234 (fd #"); buffer_putulong(buffer_2,s); @@ -35,7 +35,6 @@ int main() { for (;;) { int64 i; io_wait(); - buffer_putsflush(buffer_2,"io_wait() returned!\n"); while ((i=io_canread())!=-1) { if (i==s) { int n; @@ -64,6 +63,7 @@ int main() { } } else { char buf[1024]; + int l=io_tryread(i,buf,sizeof buf); if (l==-1) { buffer_puts(buffer_2,"io_tryread(");