r23779: Change from v2 or later to v3 or later.
[ira/wip.git] / examples / libsmbclient / smbwrapper / select.c
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 3 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
39 int 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
71 int 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 }