1/* 2 Unix SMB/Netbios implementation. 3 Version 3.0 4 Samba select/poll implementation 5 Copyright (C) Andrew Tridgell 1992-1998 6 Copyright (C) Derrell Lipman 2003-2005 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22 23/* 24 * WHY THIS FILE? 25 * 26 * This file implements the two functions in the select() family, as required 27 * by samba. The samba native functions, though, implement a pipe to help 28 * alleviate a deadlock problem, but which creates problems of its own (the 29 * timeout stops working correctly). Those functions also require that all 30 * signal handlers call a function which writes to the pipe -- a task which is 31 * difficult to do in the smbwrapper environment. 32 */ 33 34 35#include <sys/select.h> 36#include <errno.h> 37#include <stdio.h> 38 39int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval) 40{ 41 int ret; 42 fd_set *readfds2, readfds_buf; 43 44 /* If readfds is NULL we need to provide our own set. */ 45 if (readfds) { 46 readfds2 = readfds; 47 } else { 48 readfds2 = &readfds_buf; 49 FD_ZERO(readfds2); 50 } 51 52 errno = 0; 53 ret = select(maxfd,readfds2,writefds,errorfds,tval); 54 55 if (ret <= 0) { 56 FD_ZERO(readfds2); 57 if (writefds) 58 FD_ZERO(writefds); 59 if (errorfds) 60 FD_ZERO(errorfds); 61 } 62 63 return ret; 64} 65 66/******************************************************************* 67 Similar to sys_select() but catch EINTR and continue. 68 This is what sys_select() used to do in Samba. 69********************************************************************/ 70 71int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval) 72{ 73 int ret; 74 fd_set *readfds2, readfds_buf, *writefds2, writefds_buf, *errorfds2, errorfds_buf; 75 struct timeval tval2, *ptval, end_time, now_time; 76 extern void GetTimeOfDay(struct timeval *tval); 77 78 readfds2 = (readfds ? &readfds_buf : NULL); 79 writefds2 = (writefds ? &writefds_buf : NULL); 80 errorfds2 = (errorfds ? &errorfds_buf : NULL); 81 if (tval) { 82 GetTimeOfDay(&end_time); 83 end_time.tv_sec += tval->tv_sec; 84 end_time.tv_usec += tval->tv_usec; 85 end_time.tv_sec += end_time.tv_usec / 1000000; 86 end_time.tv_usec %= 1000000; 87 ptval = &tval2; 88 } else { 89 ptval = NULL; 90 } 91 92 do { 93 if (readfds) 94 readfds_buf = *readfds; 95 if (writefds) 96 writefds_buf = *writefds; 97 if (errorfds) 98 errorfds_buf = *errorfds; 99 if (tval) { 100 GetTimeOfDay(&now_time); 101 tval2.tv_sec = end_time.tv_sec - now_time.tv_sec; 102 tval2.tv_usec = end_time.tv_usec - now_time.tv_usec; 103 if ((signed long) tval2.tv_usec < 0) { 104 tval2.tv_usec += 1000000; 105 tval2.tv_sec--; 106 } 107 if ((signed long) tval2.tv_sec < 0) { 108 ret = 0; 109 break; /* time has already elapsed */ 110 } 111 } 112 113 ret = sys_select(maxfd, readfds2, writefds2, errorfds2, ptval); 114 } while (ret == -1 && errno == EINTR); 115 116 if (readfds) 117 *readfds = readfds_buf; 118 if (writefds) 119 *writefds = writefds_buf; 120 if (errorfds) 121 *errorfds = errorfds_buf; 122 123 return ret; 124} 125