mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-24 21:02:26 +00:00
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;
|
||||
if (!VFS_CLOSE(f->f))
|
||||
f->fail = true; //something went wrong.
|
||||
f->f = NULL;
|
||||
|
||||
f->hashfunc->terminate(digest, &f->ctx);
|
||||
if (f->fail)
|
||||
|
@ -3434,10 +3435,9 @@ static void PM_StartADownload(void)
|
|||
#ifdef AVAIL_XZDEC
|
||||
case EXTRACT_XZ:
|
||||
{
|
||||
vfsfile_t *raw;
|
||||
raw = FS_OpenVFS(temp, "wb", temproot);
|
||||
tmpfile = FS_XZ_DecompressWriteFilter(raw);
|
||||
if (!tmpfile)
|
||||
vfsfile_t *raw = FS_OpenVFS(temp, "wb", temproot);
|
||||
tmpfile = raw?FS_XZ_DecompressWriteFilter(raw):NULL;
|
||||
if (!tmpfile && raw)
|
||||
VFS_CLOSE(raw);
|
||||
}
|
||||
break;
|
||||
|
@ -3445,10 +3445,9 @@ static void PM_StartADownload(void)
|
|||
#ifdef AVAIL_GZDEC
|
||||
case EXTRACT_GZ:
|
||||
{
|
||||
vfsfile_t *raw;
|
||||
raw = FS_OpenVFS(temp, "wb", temproot);
|
||||
tmpfile = FS_GZ_WriteFilter(raw, true, false);
|
||||
if (!tmpfile)
|
||||
vfsfile_t *raw = FS_OpenVFS(temp, "wb", temproot);
|
||||
tmpfile = raw?FS_GZ_WriteFilter(raw, true, false):NULL;
|
||||
if (!tmpfile && raw)
|
||||
VFS_CLOSE(raw);
|
||||
}
|
||||
break;
|
||||
|
@ -3474,6 +3473,7 @@ static void PM_StartADownload(void)
|
|||
char syspath[MAX_OSPATH];
|
||||
FS_NativePath(temp, temproot, syspath, sizeof(syspath));
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -8859,6 +8859,42 @@ void NET_Shutdown (void)
|
|||
|
||||
|
||||
#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 {
|
||||
vfsfile_t funcs;
|
||||
|
||||
|
@ -8879,16 +8915,7 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
|
|||
|
||||
if (tf->conpending)
|
||||
{
|
||||
fd_set wr;
|
||||
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))
|
||||
if (VFSTCP_IsStillConnecting(tf->sock))
|
||||
return 0;
|
||||
tf->conpending = false;
|
||||
}
|
||||
|
@ -8976,16 +9003,7 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt
|
|||
|
||||
if (tf->conpending)
|
||||
{
|
||||
fd_set fdw, fdx;
|
||||
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))
|
||||
if (VFSTCP_IsStillConnecting(tf->sock))
|
||||
return 0;
|
||||
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)
|
||||
{
|
||||
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 (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;
|
||||
fd_set rdset, wrset;
|
||||
FD_ZERO(&wrset);
|
||||
|
@ -560,6 +573,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
|
|||
else
|
||||
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.
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -215,26 +215,35 @@ void Cluster_Run(cluster_t *cluster, qboolean 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);
|
||||
m = 0;
|
||||
if (cluster->qwdsocket[0] != INVALID_SOCKET)
|
||||
{
|
||||
if (cluster->qwdsocket[0] < FD_SETSIZE)
|
||||
{
|
||||
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] < FD_SETSIZE)
|
||||
{
|
||||
FD_SET(cluster->qwdsocket[1], &socketset);
|
||||
if (cluster->qwdsocket[1] >= m)
|
||||
m = cluster->qwdsocket[1]+1;
|
||||
}
|
||||
}
|
||||
|
||||
for (sv = cluster->servers; sv; sv = sv->next)
|
||||
{
|
||||
if (sv->usequakeworldprotocols && sv->sourcesock != INVALID_SOCKET)
|
||||
{
|
||||
if (sv->sourcesock >= FD_SETSIZE)
|
||||
continue; //panic...
|
||||
FD_SET(sv->sourcesock, &socketset);
|
||||
if (sv->sourcesock >= m)
|
||||
m = sv->sourcesock+1;
|
||||
|
|
Loading…
Reference in a new issue