1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#include <unistd.h>
#include <sys/time.h>
#ifdef __MINGW32__
#include <windows.h>
#else
#include <poll.h>
#endif
#include <errno.h>
#include "io_internal.h"
#ifdef __MINGW32__
#include <stdio.h>
/* 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=iarray_get(&io_fds,d);
int r;
if (!e) { errno=EBADF; return -3; }
if (!e->nonblock) {
DWORD written;
fprintf(stderr,"Socket is in blocking mode, just calling WriteFile...");
if (WriteFile((HANDLE)d,buf,len,&written,0)) {
fprintf(stderr," OK, got %u bytes.\n",written);
return written;
} else {
fprintf(stderr," failed.\n",written);
return winsock2errno(-3);
}
} else {
if (e->writequeued && !e->canwrite) {
fprintf(stderr,"io_trywrite: write already queued, returning EAGAIN\n");
errno=EAGAIN;
return -1;
}
if (e->canwrite) {
e->canwrite=0;
e->next_write=-1;
if (e->errorcode) {
fprintf(stderr,"io_trywrite: e->canwrite was set, returning error %d\n",e->errorcode);
errno=winsock2errno(e->errorcode);
return -3;
}
fprintf(stderr,"io_trywrite: e->canwrite was set, had written %u bytes\n",e->bytes_written);
return e->bytes_written;
} else {
fprintf(stderr,"io_trywrite: queueing write...");
if (WriteFile((HANDLE)d,buf,len,&e->errorcode,&e->ow)) {
fprintf(stderr," worked unexpectedly, error %d\n",e->errorcode);
return e->errorcode; /* should not happen */
} else if (GetLastError()==ERROR_IO_PENDING) {
fprintf(stderr," pending.\n");
e->writequeued=1;
errno=EAGAIN;
e->errorcode=0;
return -1;
} else {
fprintf(stderr," failed, error %d\n",e->errorcode);
winsock2errno(-1);
e->errorcode=errno;
return -3;
}
}
}
}
#else
int64 io_trywrite(int64 d,const char* buf,int64 len) {
long r;
struct itimerval old,new;
struct pollfd p;
io_entry* e=iarray_get(&io_fds,d);
io_sigpipe();
if (!e) { errno=EBADF; return -3; }
if (!e->nonblock) {
p.fd=d;
if (p.fd != d) { errno=EBADF; return -3; } /* catch overflow */
p.events=POLLOUT;
switch (poll(&p,1,0)) {
case -1: return -3;
case 0: errno=EAGAIN;
e->canwrite=0;
e->next_write=-1;
return -1;
}
new.it_interval.tv_usec=10000;
new.it_interval.tv_sec=0;
new.it_value.tv_usec=10000;
new.it_value.tv_sec=0;
setitimer(ITIMER_REAL,&new,&old);
}
r=write(d,buf,len);
if (!e->nonblock) {
setitimer(ITIMER_REAL,&old,0);
}
if (r==-1 && errno==EAGAIN)
io_eagain_write(d);
if (r==-1) {
if (errno==EINTR) errno=EAGAIN;
if (errno!=EAGAIN)
r=-3;
}
if (r!=len) {
e->canwrite=0;
io_eagain_write(d);
#if defined(HAVE_SIGIO)
if (d==alt_firstwrite) {
#if 0
debug_printf(("io_trywrite: dequeueing %ld from alt write queue (next is %ld)\n",d,e->next_write));
alt_firstwrite=e->next_write;
e->next_write=-1;
#else
if (d==alt_curwrite) alt_curwrite=-1;
} else {
debug_printf(("io_trywrite: enqueueing %ld into alt write queue (next is %ld)\n",d,alt_firstwrite));
e->next_write=alt_firstwrite;
alt_firstwrite=d;
#endif
}
#endif
}
return r;
}
#endif
|