Switch to poll instead of select, to avoid crashes from select's arbitrary fd limit.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5848 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
a13e5cfbcf
commit
5e38a007c7
4 changed files with 75 additions and 34 deletions
|
@ -3221,6 +3221,7 @@ static qboolean QDECL SHA1File_Close (struct vfsfile_s *file)
|
||||||
hashfile_t *f = (hashfile_t*)file;
|
hashfile_t *f = (hashfile_t*)file;
|
||||||
if (!VFS_CLOSE(f->f))
|
if (!VFS_CLOSE(f->f))
|
||||||
f->fail = true; //something went wrong.
|
f->fail = true; //something went wrong.
|
||||||
|
f->f = NULL;
|
||||||
|
|
||||||
f->hashfunc->terminate(digest, &f->ctx);
|
f->hashfunc->terminate(digest, &f->ctx);
|
||||||
if (f->fail)
|
if (f->fail)
|
||||||
|
@ -3434,10 +3435,9 @@ static void PM_StartADownload(void)
|
||||||
#ifdef AVAIL_XZDEC
|
#ifdef AVAIL_XZDEC
|
||||||
case EXTRACT_XZ:
|
case EXTRACT_XZ:
|
||||||
{
|
{
|
||||||
vfsfile_t *raw;
|
vfsfile_t *raw = FS_OpenVFS(temp, "wb", temproot);
|
||||||
raw = FS_OpenVFS(temp, "wb", temproot);
|
tmpfile = raw?FS_XZ_DecompressWriteFilter(raw):NULL;
|
||||||
tmpfile = FS_XZ_DecompressWriteFilter(raw);
|
if (!tmpfile && raw)
|
||||||
if (!tmpfile)
|
|
||||||
VFS_CLOSE(raw);
|
VFS_CLOSE(raw);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3445,10 +3445,9 @@ static void PM_StartADownload(void)
|
||||||
#ifdef AVAIL_GZDEC
|
#ifdef AVAIL_GZDEC
|
||||||
case EXTRACT_GZ:
|
case EXTRACT_GZ:
|
||||||
{
|
{
|
||||||
vfsfile_t *raw;
|
vfsfile_t *raw = FS_OpenVFS(temp, "wb", temproot);
|
||||||
raw = FS_OpenVFS(temp, "wb", temproot);
|
tmpfile = raw?FS_GZ_WriteFilter(raw, true, false):NULL;
|
||||||
tmpfile = FS_GZ_WriteFilter(raw, true, false);
|
if (!tmpfile && raw)
|
||||||
if (!tmpfile)
|
|
||||||
VFS_CLOSE(raw);
|
VFS_CLOSE(raw);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3474,6 +3473,7 @@ static void PM_StartADownload(void)
|
||||||
char syspath[MAX_OSPATH];
|
char syspath[MAX_OSPATH];
|
||||||
FS_NativePath(temp, temproot, syspath, sizeof(syspath));
|
FS_NativePath(temp, temproot, syspath, sizeof(syspath));
|
||||||
Con_Printf("Unable to write %s. Fix permissions before trying to download %s\n", syspath, p->name);
|
Con_Printf("Unable to write %s. Fix permissions before trying to download %s\n", syspath, p->name);
|
||||||
|
p->trymirrors = 0; //don't bother trying other mirrors if we can't write the file or understand its type.
|
||||||
}
|
}
|
||||||
if (p->download)
|
if (p->download)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8859,6 +8859,42 @@ void NET_Shutdown (void)
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_TCP
|
#ifdef HAVE_TCP
|
||||||
|
#ifdef HAVE_EPOLL
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
static qboolean VFSTCP_IsStillConnecting(SOCKET sock)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_EPOLL
|
||||||
|
//poll has no arbitrary fd limit. use it instead of select where possible.
|
||||||
|
struct pollfd ourfd[1];
|
||||||
|
ourfd[0].fd = sock;
|
||||||
|
ourfd[0].events = POLLOUT;
|
||||||
|
ourfd[0].revents = 0;
|
||||||
|
if (!poll(ourfd, countof(ourfd), 0))
|
||||||
|
return true; //no events yet.
|
||||||
|
#else
|
||||||
|
//okay on windows where sock+1 is ignored, has issues when lots of other fds are already open (for any reason).
|
||||||
|
fd_set fdw, fdx;
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
FD_ZERO(&fdw);
|
||||||
|
FD_SET(sock, &fdw);
|
||||||
|
FD_ZERO(&fdx);
|
||||||
|
FD_SET(sock, &fdx);
|
||||||
|
//check if we can actually write to it yet, without generating weird errors...
|
||||||
|
if (!select((int)sock+1, NULL, &fdw, &fdx, &timeout))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//if we get here then its writable(read: connected) or failed.
|
||||||
|
|
||||||
|
// int error = NET_ENOTCONN;
|
||||||
|
// socklen_t sz = sizeof(error);
|
||||||
|
// if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &sz))
|
||||||
|
// error = NET_ENOTCONN;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vfsfile_t funcs;
|
vfsfile_t funcs;
|
||||||
|
|
||||||
|
@ -8879,16 +8915,7 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
|
||||||
|
|
||||||
if (tf->conpending)
|
if (tf->conpending)
|
||||||
{
|
{
|
||||||
fd_set wr;
|
if (VFSTCP_IsStillConnecting(tf->sock))
|
||||||
fd_set ex;
|
|
||||||
struct timeval timeout;
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 0;
|
|
||||||
FD_ZERO(&wr);
|
|
||||||
FD_SET(tf->sock, &wr);
|
|
||||||
FD_ZERO(&ex);
|
|
||||||
FD_SET(tf->sock, &ex);
|
|
||||||
if (!select((int)tf->sock+1, NULL, &wr, &ex, &timeout))
|
|
||||||
return 0;
|
return 0;
|
||||||
tf->conpending = false;
|
tf->conpending = false;
|
||||||
}
|
}
|
||||||
|
@ -8976,16 +9003,7 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt
|
||||||
|
|
||||||
if (tf->conpending)
|
if (tf->conpending)
|
||||||
{
|
{
|
||||||
fd_set fdw, fdx;
|
if (VFSTCP_IsStillConnecting(tf->sock))
|
||||||
struct timeval timeout;
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 0;
|
|
||||||
FD_ZERO(&fdw);
|
|
||||||
FD_SET(tf->sock, &fdw);
|
|
||||||
FD_ZERO(&fdx);
|
|
||||||
FD_SET(tf->sock, &fdx);
|
|
||||||
//check if we can actually write to it yet, without generating weird errors...
|
|
||||||
if (!select((int)tf->sock+1, NULL, &fdw, &fdx, &timeout))
|
|
||||||
return 0;
|
return 0;
|
||||||
tf->conpending = false;
|
tf->conpending = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -532,6 +532,9 @@ static int VFSError_To_HTTP(int vfserr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_EPOLL
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
static qboolean HTTP_DL_Work(struct dl_download *dl)
|
static qboolean HTTP_DL_Work(struct dl_download *dl)
|
||||||
{
|
{
|
||||||
struct http_dl_ctx_s *con = dl->ctx;
|
struct http_dl_ctx_s *con = dl->ctx;
|
||||||
|
@ -547,6 +550,16 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
|
||||||
//if we're running in a thread, wait for some actual activity instead of busylooping like an moron.
|
//if we're running in a thread, wait for some actual activity instead of busylooping like an moron.
|
||||||
if (dl->threadctx)
|
if (dl->threadctx)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_EPOLL
|
||||||
|
struct pollfd fd;
|
||||||
|
fd.fd = con->sock;
|
||||||
|
fd.events = POLLIN;
|
||||||
|
fd.revents = 0;
|
||||||
|
if (con->state == HC_REQUESTING)
|
||||||
|
fd.events |= POLLOUT;
|
||||||
|
poll(&fd, 1, 0.1*1000); //wake up when we can read OR write
|
||||||
|
//note that https should wake up more often, but we don't want to wake up because we *can* write when we're reading without any need to write.
|
||||||
|
#else
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
fd_set rdset, wrset;
|
fd_set rdset, wrset;
|
||||||
FD_ZERO(&wrset);
|
FD_ZERO(&wrset);
|
||||||
|
@ -560,6 +573,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
|
||||||
else
|
else
|
||||||
select(con->sock+1, &rdset, NULL, NULL, &timeout); //wake when we can read.
|
select(con->sock+1, &rdset, NULL, NULL, &timeout); //wake when we can read.
|
||||||
//note that https should wake up more often, but we don't want to wake up because we *can* write when we're reading without any need to write.
|
//note that https should wake up more often, but we don't want to wake up because we *can* write when we're reading without any need to write.
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -215,26 +215,35 @@ void Cluster_Run(cluster_t *cluster, qboolean dowait)
|
||||||
|
|
||||||
if (dowait)
|
if (dowait)
|
||||||
{
|
{
|
||||||
|
//FIXME: use poll or epoll to work around FD_SETSIZE limits, though we're mostly only doing this for the sleeping.
|
||||||
|
|
||||||
FD_ZERO(&socketset);
|
FD_ZERO(&socketset);
|
||||||
m = 0;
|
m = 0;
|
||||||
if (cluster->qwdsocket[0] != INVALID_SOCKET)
|
if (cluster->qwdsocket[0] != INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
FD_SET(cluster->qwdsocket[0], &socketset);
|
if (cluster->qwdsocket[0] < FD_SETSIZE)
|
||||||
if (cluster->qwdsocket[0] >= m)
|
{
|
||||||
m = cluster->qwdsocket[0]+1;
|
FD_SET(cluster->qwdsocket[0], &socketset);
|
||||||
|
if (cluster->qwdsocket[0] >= m)
|
||||||
|
m = cluster->qwdsocket[0]+1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (cluster->qwdsocket[1] != INVALID_SOCKET)
|
if (cluster->qwdsocket[1] != INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
FD_SET(cluster->qwdsocket[1], &socketset);
|
if (cluster->qwdsocket[1] < FD_SETSIZE)
|
||||||
if (cluster->qwdsocket[1] >= m)
|
{
|
||||||
m = cluster->qwdsocket[1]+1;
|
FD_SET(cluster->qwdsocket[1], &socketset);
|
||||||
|
if (cluster->qwdsocket[1] >= m)
|
||||||
|
m = cluster->qwdsocket[1]+1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (sv = cluster->servers; sv; sv = sv->next)
|
for (sv = cluster->servers; sv; sv = sv->next)
|
||||||
{
|
{
|
||||||
if (sv->usequakeworldprotocols && sv->sourcesock != INVALID_SOCKET)
|
if (sv->usequakeworldprotocols && sv->sourcesock != INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
|
if (sv->sourcesock >= FD_SETSIZE)
|
||||||
|
continue; //panic...
|
||||||
FD_SET(sv->sourcesock, &socketset);
|
FD_SET(sv->sourcesock, &socketset);
|
||||||
if (sv->sourcesock >= m)
|
if (sv->sourcesock >= m)
|
||||||
m = sv->sourcesock+1;
|
m = sv->sourcesock+1;
|
||||||
|
|
Loading…
Reference in a new issue