Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2012-10-12 21:49:59 +0200
committerArthur de Jong <arthur@arthurdejong.org>2012-10-12 21:49:59 +0200
commitf266f05f20afe73e89c3946a7bd60bd7c5948e1b (patch)
treed1e5395e449c26835ed721eb4647dbe06b16d948
parent7867b93f9a7c76b96f1571cddc1de0811134bb81 (diff)
use poll() instead of select() for checking file descriptor activity to also correctly work if more than FD_SETSIZE files are already open
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-pam-ldapd@1783 ef36b2f9-881f-0410-afb5-c4e39611909c
-rw-r--r--common/nslcd-prot.c13
-rw-r--r--common/tio.c134
-rw-r--r--common/tio.h5
-rw-r--r--nslcd/nslcd.c14
4 files changed, 57 insertions, 109 deletions
diff --git a/common/nslcd-prot.c b/common/nslcd-prot.c
index c0ecc99..3bb3e0c 100644
--- a/common/nslcd-prot.c
+++ b/common/nslcd-prot.c
@@ -38,6 +38,11 @@
#include "nslcd-prot.h"
#include "compat/socket.h"
+/* read timeout is 60 seconds because looking up stuff may take some time
+ write timeout is 10 secods because nslcd could be loaded with requests */
+#define READ_TIMEOUT 60*1000
+#define WRITE_TIMEOUT 10*1000
+
/* buffer sizes for I/O */
#define READBUFFER_MINSIZE 1024
#define READBUFFER_MAXSIZE 2*1024*1024
@@ -56,7 +61,6 @@ TFILE *nslcd_client_open()
{
int sock;
struct sockaddr_un addr;
- struct timeval readtimeout,writetimeout;
TFILE *fp;
/* create a socket */
if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 )
@@ -72,13 +76,8 @@ TFILE *nslcd_client_open()
(void)close(sock);
return NULL;
}
- /* set the timeouts */
- readtimeout.tv_sec=60; /* looking up stuff may take some time */
- readtimeout.tv_usec=0;
- writetimeout.tv_sec=10; /* nslcd could be loaded with requests */
- writetimeout.tv_usec=0;
/* create a stream object */
- if ((fp=tio_fdopen(sock,&readtimeout,&writetimeout,
+ if ((fp=tio_fdopen(sock,READ_TIMEOUT,WRITE_TIMEOUT,
READBUFFER_MINSIZE,READBUFFER_MAXSIZE,
WRITEBUFFER_MINSIZE,WRITEBUFFER_MAXSIZE))==NULL)
{
diff --git a/common/tio.c b/common/tio.c
index 75d1f64..0dffff4 100644
--- a/common/tio.c
+++ b/common/tio.c
@@ -35,6 +35,7 @@
#include <signal.h>
#include <stdio.h>
#include <limits.h>
+#include <poll.h>
#include "tio.h"
@@ -63,8 +64,8 @@ struct tio_fileinfo {
int fd;
struct tio_buffer readbuffer;
struct tio_buffer writebuffer;
- struct timeval readtimeout;
- struct timeval writetimeout;
+ int readtimeout;
+ int writetimeout;
int read_resettable; /* whether the tio_reset() function can be called */
#ifdef DEBUG_TIO_STATS
/* this is used to collect statistics on the use of the streams
@@ -74,21 +75,8 @@ struct tio_fileinfo {
#endif /* DEBUG_TIO_STATS */
};
-/* add the second timeval to the first modifing the first */
-static inline void tio_tv_add(struct timeval *tv1, const struct timeval *tv2)
-{
- /* BUG: we hope that this does not overflow */
- tv1->tv_usec+=tv2->tv_usec;
- if (tv1->tv_usec>=1000000)
- {
- tv1->tv_usec-=1000000;
- tv1->tv_sec+=1;
- }
- tv1->tv_sec+=tv2->tv_sec;
-}
-
/* build a timeval for comparison to when the operation should be finished */
-static inline void tio_tv_prepare(struct timeval *deadline, const struct timeval *timeout)
+static inline void tio_get_deadline(struct timeval *deadline,int timeout)
{
if (gettimeofday(deadline,NULL))
{
@@ -97,39 +85,27 @@ static inline void tio_tv_prepare(struct timeval *deadline, const struct timeval
deadline->tv_usec=0;
return;
}
- tio_tv_add(deadline,timeout);
+ deadline->tv_sec+=timeout/1000;
+ deadline->tv_sec+=(timeout%1000)*1000;
}
-/* update the timeval to the value that is remaining before deadline
+/* update the timeout to the value that is remaining before deadline
returns non-zero if there is no more time before the deadline */
-static inline int tio_tv_remaining(struct timeval *tv, const struct timeval *deadline)
+static inline int tio_time_remaining(const struct timeval *deadline)
{
+ struct timeval tv;
/* get the current time */
- if (gettimeofday(tv,NULL))
+ if (gettimeofday(&tv,NULL))
{
/* 1 second default if gettimeofday() is broken */
- tv->tv_sec=1;
- tv->tv_usec=0;
- return 0;
- }
- /* check if we're too late */
- if ( (tv->tv_sec>deadline->tv_sec) ||
- ( (tv->tv_sec==deadline->tv_sec) && (tv->tv_usec>deadline->tv_usec) ) )
- return -1;
- /* update tv */
- tv->tv_sec=deadline->tv_sec-tv->tv_sec;
- if (tv->tv_usec<=deadline->tv_usec)
- tv->tv_usec=deadline->tv_usec-tv->tv_usec;
- else
- {
- tv->tv_sec--;
- tv->tv_usec=1000000+deadline->tv_usec-tv->tv_usec;
+ return 1000;
}
- return 0;
+ /* calculate time remaining in miliseconds */
+ return (deadline->tv_sec-tv.tv_sec)*1000 + (deadline->tv_usec-tv.tv_usec)/1000;
}
/* open a new TFILE based on the file descriptor */
-TFILE *tio_fdopen(int fd,struct timeval *readtimeout,struct timeval *writetimeout,
+TFILE *tio_fdopen(int fd,int readtimeout,int writetimeout,
size_t initreadsize,size_t maxreadsize,
size_t initwritesize,size_t maxwritesize)
{
@@ -162,10 +138,8 @@ TFILE *tio_fdopen(int fd,struct timeval *readtimeout,struct timeval *writetimeou
fp->writebuffer.start=0;
fp->writebuffer.len=0;
/* initialize other attributes */
- fp->readtimeout.tv_sec=readtimeout->tv_sec;
- fp->readtimeout.tv_usec=readtimeout->tv_usec;
- fp->writetimeout.tv_sec=writetimeout->tv_sec;
- fp->writetimeout.tv_usec=writetimeout->tv_usec;
+ fp->readtimeout=readtimeout;
+ fp->writetimeout=writetimeout;
fp->read_resettable=0;
#ifdef DEBUG_TIO_STATS
fp->byteswritten=0;
@@ -176,23 +150,15 @@ TFILE *tio_fdopen(int fd,struct timeval *readtimeout,struct timeval *writetimeou
/* wait for any activity on the specified file descriptor using
the specified deadline */
-static int tio_select(TFILE *fp, int readfd, const struct timeval *deadline)
+static int tio_wait(TFILE *fp,int readfd,const struct timeval *deadline)
{
- struct timeval tv;
- fd_set fdset;
+ int timeout;
+ struct pollfd fds[1];
int rv;
while (1)
{
- /* prepare our filedescriptorset */
- if (fp->fd>=FD_SETSIZE)
- {
- errno=EBADFD;
- return -1;
- }
- FD_ZERO(&fdset);
- FD_SET(fp->fd,&fdset);
/* figure out the time we need to wait */
- if (tio_tv_remaining(&tv,deadline))
+ if ((timeout=tio_time_remaining(deadline))<0)
{
errno=ETIME;
return -1;
@@ -200,18 +166,21 @@ static int tio_select(TFILE *fp, int readfd, const struct timeval *deadline)
/* wait for activity */
if (readfd)
{
+ fds[0].fd=fp->fd;
+ fds[0].events=POLLIN;
/* santiy check for moving clock */
- if (tv.tv_sec>fp->readtimeout.tv_sec)
- tv.tv_sec=fp->readtimeout.tv_sec;
- rv=select(FD_SETSIZE,&fdset,NULL,NULL,&tv);
+ if (timeout>fp->readtimeout)
+ timeout=fp->readtimeout;
}
else
{
+ fds[0].fd=fp->fd;
+ fds[0].events=POLLOUT;
/* santiy check for moving clock */
- if (tv.tv_sec>fp->writetimeout.tv_sec)
- tv.tv_sec=fp->writetimeout.tv_sec;
- rv=select(FD_SETSIZE,NULL,&fdset,NULL,&tv);
+ if (timeout>fp->writetimeout)
+ timeout=fp->writetimeout;
}
+ rv=poll(fds,1,timeout);
if (rv>0)
return 0; /* we have activity */
else if (rv==0)
@@ -239,7 +208,7 @@ int tio_read(TFILE *fp, void *buf, size_t count)
/* have a more convenient storage type for the buffer */
uint8_t *ptr=(uint8_t *)buf;
/* build a time by which we should be finished */
- tio_tv_prepare(&deadline,&(fp->readtimeout));
+ tio_get_deadline(&deadline,fp->readtimeout);
/* loop until we have returned all the needed data */
while (1)
{
@@ -297,7 +266,7 @@ int tio_read(TFILE *fp, void *buf, size_t count)
}
}
/* wait until we have input */
- if (tio_select(fp,1,&deadline))
+ if (tio_wait(fp,1,&deadline))
return -1;
/* read the input in the buffer */
len=fp->readbuffer.size-fp->readbuffer.start;
@@ -331,8 +300,7 @@ int tio_skip(TFILE *fp, size_t count)
/* Read all available data from the stream and empty the read buffer. */
int tio_skipall(TFILE *fp)
{
- struct timeval tv;
- fd_set fdset;
+ struct pollfd fds[1];
int rv;
size_t len;
/* clear the read buffer */
@@ -347,19 +315,11 @@ int tio_skipall(TFILE *fp)
#endif /* SSIZE_MAX */
while (1)
{
- /* prepare our file descriptor set */
- if (fp->fd>=FD_SETSIZE)
- {
- errno=EBADFD;
- return -1;
- }
- FD_ZERO(&fdset);
- FD_SET(fp->fd,&fdset);
- /* prepare the time to wait */
- tv.tv_sec=0;
- tv.tv_usec=0;
/* see if any data is available */
- rv=select(FD_SETSIZE,&fdset,NULL,NULL,&tv);
+ fds[0].fd=fp->fd;
+ fds[0].events=POLLIN;
+ rv=poll(fds,1,0);
+ /* check the poll() result */
if (rv==0)
return 0; /* no file descriptor ready */
if ((rv<0)&&((errno==EINTR)||(errno==EAGAIN)))
@@ -434,12 +394,12 @@ int tio_flush(TFILE *fp)
{
struct timeval deadline;
/* build a time by which we should be finished */
- tio_tv_prepare(&deadline,&(fp->writetimeout));
+ tio_get_deadline(&deadline,fp->writetimeout);
/* loop until we have written our buffer */
while (fp->writebuffer.len > 0)
{
/* wait until we can write */
- if (tio_select(fp,0,&deadline))
+ if (tio_wait(fp,0,&deadline))
return -1;
/* write one block */
if (tio_writebuf(fp))
@@ -452,22 +412,12 @@ int tio_flush(TFILE *fp)
will accept data */
static int tio_flush_nonblock(TFILE *fp)
{
- struct timeval tv;
- fd_set fdset;
+ struct pollfd fds[1];
int rv;
- /* prepare our filedescriptorset */
- if (fp->fd>=FD_SETSIZE)
- {
- errno=EBADFD;
- return -1;
- }
- FD_ZERO(&fdset);
- FD_SET(fp->fd,&fdset);
- /* set the timeout to 0 to poll */
- tv.tv_sec=0;
- tv.tv_usec=0;
/* wait for activity */
- rv=select(FD_SETSIZE,NULL,&fdset,NULL,&tv);
+ fds[0].fd=fp->fd;
+ fds[0].events=POLLOUT;
+ rv=poll(fds,1,0);
/* check if any file descriptors were ready (timeout) or we were
interrupted */
if ((rv==0)||((rv<0)&&(errno==EINTR)))
diff --git a/common/tio.h b/common/tio.h
index 59f26df..cd3f370 100644
--- a/common/tio.h
+++ b/common/tio.h
@@ -46,9 +46,8 @@
typedef struct tio_fileinfo TFILE;
/* Open a new TFILE based on the file descriptor. The timeout is set for any
- operation. The timeout value is copied so may be dereferenced after the
- call. */
-TFILE *tio_fdopen(int fd,struct timeval *readtimeout,struct timeval *writetimeout,
+ operation (value in milliseconds). */
+TFILE *tio_fdopen(int fd,int readtimeout,int writetimeout,
size_t initreadsize,size_t maxreadsize,
size_t initwritesize,size_t maxwritesize)
LIKE_MALLOC MUST_USE;
diff --git a/nslcd/nslcd.c b/nslcd/nslcd.c
index fd836ae..54b97f3 100644
--- a/nslcd/nslcd.c
+++ b/nslcd/nslcd.c
@@ -66,6 +66,12 @@
#include "compat/getpeercred.h"
#include "compat/socket.h"
+/* read timeout is half a second because clients should send their request
+ quickly, write timeout is 60 seconds because clients could be taking some
+ time to process the results */
+#define READ_TIMEOUT 500
+#define WRITE_TIMEOUT 60*1000
+
/* buffer sizes for I/O */
#define READBUFFER_MINSIZE 32
#define READBUFFER_MAXSIZE 64
@@ -378,7 +384,6 @@ static void handleconnection(int sock,MYLDAP_SESSION *session)
{
TFILE *fp;
int32_t action;
- struct timeval readtimeout,writetimeout;
uid_t uid=(uid_t)-1;
gid_t gid=(gid_t)-1;
pid_t pid=(pid_t)-1;
@@ -388,13 +393,8 @@ static void handleconnection(int sock,MYLDAP_SESSION *session)
else
log_log(LOG_DEBUG,"connection from pid=%d uid=%d gid=%d",
(int)pid,(int)uid,(int)gid);
- /* set the timeouts */
- readtimeout.tv_sec=0; /* clients should send their request quickly */
- readtimeout.tv_usec=500000;
- writetimeout.tv_sec=60; /* clients could be taking some time to process the results */
- writetimeout.tv_usec=0;
/* create a stream object */
- if ((fp=tio_fdopen(sock,&readtimeout,&writetimeout,
+ if ((fp=tio_fdopen(sock,READ_TIMEOUT,WRITE_TIMEOUT,
READBUFFER_MINSIZE,READBUFFER_MAXSIZE,
WRITEBUFFER_MINSIZE,WRITEBUFFER_MAXSIZE))==NULL)
{