From f266f05f20afe73e89c3946a7bd60bd7c5948e1b Mon Sep 17 00:00:00 2001 From: Arthur de Jong Date: Fri, 12 Oct 2012 19:49:59 +0000 Subject: 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 --- common/nslcd-prot.c | 13 +++-- common/tio.c | 134 ++++++++++++++++------------------------------------ common/tio.h | 5 +- nslcd/nslcd.c | 14 +++--- 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 #include #include +#include #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) { -- cgit v1.2.3