fc1df84fccedd989d69c85a4c9ce5ee8819a3cef
[yaz-moved-to-github.git] / src / zoom-socket.c
1 /*
2  * Copyright (C) 1995-2007, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: zoom-socket.c,v 1.3 2007-02-28 11:14:56 mike Exp $
6  */
7 /**
8  * \file zoom-socket.c
9  * \brief Implements ZOOM C socket interface.
10  */
11
12 #include <assert.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <yaz/zoom.h>
16
17 #include <yaz/log.h>
18 #include <yaz/xmalloc.h>
19
20 #if HAVE_SYS_TYPES_H
21 #include <sys/types.h>
22 #endif
23 #if HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #if HAVE_SYS_POLL_H
27 #include <sys/poll.h>
28 #endif
29 #if HAVE_SYS_SELECT_H
30 #include <sys/select.h>
31 #endif
32 #ifdef WIN32
33 #if FD_SETSIZE < 512
34 #define FD_SETSIZE 512
35 #endif
36 #include <winsock.h>
37 #endif
38
39
40 /*
41  * Note that ZOOM_event_sys_select() is limited as to how many file
42  * descriptors it can multiplex due to its use of select() which in
43  * turn uses the statically defined fd_set type to be a bitmap of the
44  * file descriptors to check.  On Ubuntu 6.06 (and almost certainly on
45  * Debian, and probably on all Linuxes, and maybe all Unixes) this is
46  * by default set to 1024 (though it may be possible to override this
47  * using a #define before including <sys/select.h> -- I've not tried
48  * this).  1024 file descriptors is a lot, but not enough in all
49  * cases, e.g. when running IRSpy on a large target database.  So you
50  * should ensure that YAZ uses ZOOM_event_sys_poll() when possible.
51  */
52 ZOOM_API(int)
53     ZOOM_event_sys_select(int no, ZOOM_connection *cs)
54 {
55     struct timeval tv;
56     fd_set input, output, except;
57     int i, r;
58     int max_fd = 0;
59     int timeout = 30;
60     int nfds = 0;
61
62     FD_ZERO(&input);
63     FD_ZERO(&output);
64     FD_ZERO(&except);
65
66     for (i = 0; i<no; i++)
67     {
68         ZOOM_connection c = cs[i];
69         int fd, mask;
70         
71         if (!c)
72             continue;
73         fd = ZOOM_connection_get_socket(c);
74         mask = ZOOM_connection_get_mask(c);
75         timeout = ZOOM_connection_get_timeout(c);
76
77         if (fd == -1)
78             continue;
79         if (max_fd < fd)
80             max_fd = fd;
81         
82         if (mask & ZOOM_SELECT_READ)
83             FD_SET(fd, &input);
84         if (mask & ZOOM_SELECT_WRITE)
85             FD_SET(fd, &output);
86         if (mask & ZOOM_SELECT_EXCEPT)
87             FD_SET(fd, &except);
88         if (mask)
89             nfds++;
90     }
91     if (nfds == 0)
92         return 0;
93
94     tv.tv_sec = timeout;
95     tv.tv_usec = 0;
96
97     while ((r = select(max_fd+1, &input, &output, &except,
98                        (timeout == -1 ? 0 : &tv))) < 0 && errno == EINTR)
99     {
100         ;
101     }
102     if (r < 0)
103     {
104         yaz_log(YLOG_WARN|YLOG_ERRNO, "ZOOM_event_sys_select");
105         return r;
106     }
107
108     for (i = 0; i<no; i++)
109     {
110         ZOOM_connection c = cs[i];
111         int fd, mask;
112
113         if (!c)
114             continue;
115         fd = ZOOM_connection_get_socket(c);
116         mask = 0;
117         if (r)
118         {
119             /* no timeout and real socket */
120             if (FD_ISSET(fd, &input))
121                 mask += ZOOM_SELECT_READ;
122             if (FD_ISSET(fd, &output))
123                 mask += ZOOM_SELECT_WRITE;
124             if (FD_ISSET(fd, &except))
125                 mask += ZOOM_SELECT_EXCEPT;
126             if (mask)
127                 ZOOM_connection_fire_event_socket(c, mask);
128         }
129         else
130             ZOOM_connection_fire_event_timeout(c);
131     }
132     return r;
133 }
134
135 #if HAVE_SYS_POLL_H
136 ZOOM_API(int)
137     ZOOM_event_sys_poll(int no, ZOOM_connection *cs)
138 {
139     struct pollfd *pollfds = xmalloc(no * sizeof *pollfds);
140     ZOOM_connection *poll_cs = xmalloc(no * sizeof *poll_cs);
141     int i, r;
142     int nfds = 0;
143     int timeout = 30;
144
145     for (i = 0; i<no; i++)
146     {
147         ZOOM_connection c = cs[i];
148         int fd, mask;
149         
150         if (!c)
151             continue;
152         fd = ZOOM_connection_get_socket(c);
153         mask = ZOOM_connection_get_mask(c);
154         timeout = ZOOM_connection_get_timeout(c);
155
156         if (fd == -1)
157             continue;
158         if (mask)
159         {
160             short poll_events = 0;
161
162             if (mask & ZOOM_SELECT_READ)
163                 poll_events += POLLIN;
164             if (mask & ZOOM_SELECT_WRITE)
165                 poll_events += POLLOUT;
166             if (mask & ZOOM_SELECT_EXCEPT)
167                 poll_events += POLLERR;
168             pollfds[nfds].fd = fd;
169             pollfds[nfds].events = poll_events;
170             pollfds[nfds].revents = 0;
171             poll_cs[nfds] = c;
172             nfds++;
173         }
174     }
175     if (nfds == 0) {
176         xfree(pollfds);
177         xfree(poll_cs);
178         return 0;
179     }
180     while ((r = poll(pollfds, nfds,
181          (timeout == -1 ? -1 : timeout * 1000))) < 0
182           && errno == EINTR)
183     {
184         ;
185     }
186     if (r < 0)
187     {
188         yaz_log(YLOG_WARN|YLOG_ERRNO, "ZOOM_event_sys_poll");
189         xfree(pollfds);
190         xfree(poll_cs);
191         return r;
192     }
193     for (i = 0; i<nfds; i++)
194     {
195         ZOOM_connection c = poll_cs[i];
196         if (r)
197         {
198             int mask = 0;
199             if (pollfds[i].revents & POLLIN)
200                 mask += ZOOM_SELECT_READ;
201             if (pollfds[i].revents & POLLOUT)
202                 mask += ZOOM_SELECT_WRITE;
203             if (pollfds[i].revents & POLLERR)
204                 mask += ZOOM_SELECT_EXCEPT;
205             ZOOM_connection_fire_event_socket(c, mask);
206         }
207         else
208             ZOOM_connection_fire_event_timeout(c);
209     }
210     xfree(pollfds);
211     xfree(poll_cs);
212     return r;
213 }
214 #endif
215
216 ZOOM_API(int)
217     ZOOM_event(int no, ZOOM_connection *cs)
218 {
219     int r;
220
221     r = ZOOM_event_nonblock(no, cs);
222     if (r)
223         return r;
224 #if HAVE_SYS_POLL_H
225     ZOOM_event_sys_poll(no, cs);
226 #else
227     ZOOM_event_sys_select(no, cs);
228 #endif
229     return ZOOM_event_nonblock(no, cs);
230 }
231
232 /*
233  * Local variables:
234  * c-basic-offset: 4
235  * indent-tabs-mode: nil
236  * End:
237  * vim: shiftwidth=4 tabstop=8 expandtab
238  */
239