Merge branch 'ctdb-merge' into v3-2-test
[nivanova/samba-autobuild/.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, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23  * WHY THIS FILE?
24  *
25  * This file implements the two functions in the select() family, as required
26  * by samba.  The samba native functions, though, implement a pipe to help
27  * alleviate a deadlock problem, but which creates problems of its own (the
28  * timeout stops working correctly).  Those functions also require that all
29  * signal handlers call a function which writes to the pipe -- a task which is
30  * difficult to do in the smbwrapper environment.
31  */
32
33
34 #include <sys/select.h>
35 #include <errno.h>
36 #include <stdio.h>
37
38 int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
39 {
40         int ret;
41         fd_set *readfds2, readfds_buf;
42
43         /* If readfds is NULL we need to provide our own set. */
44         if (readfds) {
45                 readfds2 = readfds;
46         } else {
47                 readfds2 = &readfds_buf;
48                 FD_ZERO(readfds2);
49         }
50
51         errno = 0;
52         ret = select(maxfd,readfds2,writefds,errorfds,tval);
53
54         if (ret <= 0) {
55                 FD_ZERO(readfds2);
56                 if (writefds)
57                         FD_ZERO(writefds);
58                 if (errorfds)
59                         FD_ZERO(errorfds);
60         }
61
62         return ret;
63 }
64
65 /*******************************************************************
66  Similar to sys_select() but catch EINTR and continue.
67  This is what sys_select() used to do in Samba.
68 ********************************************************************/
69
70 int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval)
71 {
72         int ret;
73         fd_set *readfds2, readfds_buf, *writefds2, writefds_buf, *errorfds2, errorfds_buf;
74         struct timeval tval2, *ptval, end_time, now_time;
75
76         readfds2 = (readfds ? &readfds_buf : NULL);
77         writefds2 = (writefds ? &writefds_buf : NULL);
78         errorfds2 = (errorfds ? &errorfds_buf : NULL);
79         if (tval) {
80                 gettimeofday(&end_time, NULL);
81                 end_time.tv_sec += tval->tv_sec;
82                 end_time.tv_usec += tval->tv_usec;
83                 end_time.tv_sec += end_time.tv_usec / 1000000;
84                 end_time.tv_usec %= 1000000;
85                 ptval = &tval2;
86         } else {
87                 ptval = NULL;
88         }
89
90         do {
91                 if (readfds)
92                         readfds_buf = *readfds;
93                 if (writefds)
94                         writefds_buf = *writefds;
95                 if (errorfds)
96                         errorfds_buf = *errorfds;
97                 if (tval) {
98                         gettimeofday(&now_time, NULL);
99                         tval2.tv_sec = end_time.tv_sec - now_time.tv_sec;
100                         tval2.tv_usec = end_time.tv_usec - now_time.tv_usec;
101                         if ((signed long) tval2.tv_usec < 0) {
102                                 tval2.tv_usec += 1000000;
103                                 tval2.tv_sec--;
104                         }
105                         if ((signed long) tval2.tv_sec < 0) {
106                                 ret = 0;
107                                 break;          /* time has already elapsed */
108                         }
109                 }
110
111                 ret = sys_select(maxfd, readfds2, writefds2, errorfds2, ptval);
112         } while (ret == -1 && errno == EINTR);
113
114         if (readfds)
115                 *readfds = readfds_buf;
116         if (writefds)
117                 *writefds = writefds_buf;
118         if (errorfds)
119                 *errorfds = errorfds_buf;
120
121         return ret;
122 }