Removed prefix Yaz_ from several class - and interface names now
[yazpp-moved-to-github.git] / src / yaz-socket-manager.cpp
1 /*
2  * Copyright (c) 1998-2005, Index Data.
3  * See the file LICENSE for details.
4  * 
5  * $Id: yaz-socket-manager.cpp,v 1.33 2005-06-08 13:28:06 adam Exp $
6  */
7 #ifdef WIN32
8 #include <winsock.h>
9 #endif
10
11 #if HAVE_SYS_TIME_H
12 #include <sys/time.h>
13 #endif
14 #if HAVE_SYS_TYPES_H
15 #include <sys/types.h>
16 #endif
17 #if HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20
21 #include <errno.h>
22 #include <string.h>
23 #include <assert.h>
24
25 #include <yaz/log.h>
26 #include <yaz++/socket-manager.h>
27
28 using namespace yazpp_1;
29
30 SocketManager::SocketEntry **SocketManager::lookupObserver(
31     ISocketObserver *observer)
32 {
33     SocketEntry **se;
34     
35     for (se = &m_observers; *se; se = &(*se)->next)
36         if ((*se)->observer == observer)
37             break;
38     return se;
39 }
40
41 void SocketManager::addObserver(int fd, ISocketObserver *observer)
42 {
43     SocketEntry *se;
44
45     se = *lookupObserver(observer);
46     if (!se)
47     {
48         se = new SocketEntry;
49         se->next= m_observers;
50         m_observers = se;
51         se->observer = observer;
52     }
53     se->fd = fd;
54     se->mask = 0;
55     se->last_activity = 0;
56     se->timeout = -1;
57 }
58
59 void SocketManager::deleteObserver(ISocketObserver *observer)
60 {
61     SocketEntry **se = lookupObserver(observer);
62     if (*se)
63     {
64         removeEvent (observer);
65         SocketEntry *se_tmp = *se;
66         *se = (*se)->next;
67         delete se_tmp;
68     }
69 }
70
71 void SocketManager::deleteObservers()
72 {
73     SocketEntry *se = m_observers;
74     
75     while (se)
76     {
77         SocketEntry *se_next = se->next;
78         delete se;
79         se = se_next;
80     }
81     m_observers = 0;
82 }
83
84 void SocketManager::maskObserver(ISocketObserver *observer, int mask)
85 {
86     SocketEntry *se;
87
88     yaz_log(m_log, "obs=%p read=%d write=%d except=%d", observer,
89                     mask & SOCKET_OBSERVE_READ,
90                     mask & SOCKET_OBSERVE_WRITE,
91                     mask & SOCKET_OBSERVE_EXCEPT);
92
93     se = *lookupObserver(observer);
94     if (se)
95         se->mask = mask;
96 }
97
98 void SocketManager::timeoutObserver(ISocketObserver *observer,
99                                         int timeout)
100 {
101     SocketEntry *se;
102
103     se = *lookupObserver(observer);
104     if (se)
105         se->timeout = timeout;
106 }
107
108 int SocketManager::processEvent()
109 {
110     SocketEntry *p;
111     SocketEvent *event = getEvent();
112     int timeout = -1;
113     yaz_log (m_log, "SocketManager::processEvent manager=%p", this);
114     if (event)
115     {
116         event->observer->socketNotify(event->event);
117         delete event;
118         return 1;
119     }
120
121     fd_set in, out, except;
122     int res;
123     int max = 0;
124     int no = 0;
125
126     FD_ZERO(&in);
127     FD_ZERO(&out);
128     FD_ZERO(&except);
129
130     time_t now = time(0);
131     for (p = m_observers; p; p = p->next)
132     {
133         int fd = p->fd;
134         if (p->mask)
135             no++;
136         if (p->mask & SOCKET_OBSERVE_READ)
137         {
138             yaz_log (m_log, "SocketManager::select fd=%d read", fd);
139             FD_SET(fd, &in);
140         }
141         if (p->mask & SOCKET_OBSERVE_WRITE)
142         {
143             yaz_log (m_log, "SocketManager::select fd=%d write", fd);
144             FD_SET(fd, &out);
145         }
146         if (p->mask & SOCKET_OBSERVE_EXCEPT)
147         {
148             yaz_log (m_log, "SocketManager::select fd=%d except", fd);
149             FD_SET(fd, &except);
150         }
151         if (fd > max)
152             max = fd;
153         if (p->timeout > 0 ||
154             (p->timeout == 0 && (p->mask & SOCKET_OBSERVE_WRITE) == 0))
155         {
156             int timeout_this;
157             timeout_this = p->timeout;
158             if (p->last_activity)
159                 timeout_this -= now - p->last_activity;
160             else
161                 p->last_activity = now;
162             if (timeout_this < 0 || timeout_this > 2147483646)
163                 timeout_this = 0;
164             if (timeout == -1 || timeout_this < timeout)
165                 timeout = timeout_this;
166             p->timeout_this = timeout_this;
167             yaz_log (m_log, "SocketManager::select timeout_this=%d", 
168                      p->timeout_this);
169         }
170     }
171     if (!no)
172     {
173         yaz_log (m_log, "no pending events return 0");
174         if (!m_observers)
175             yaz_log (m_log, "no observers");
176         return 0;
177     }
178
179     struct timeval to;
180     to.tv_sec = timeout;
181     to.tv_usec = 0;
182     
183     yaz_log (m_log, "SocketManager::select begin no=%d timeout=%d",
184              no, timeout);
185     int pass = 0;
186     while ((res = select(max + 1, &in, &out, &except,
187                          timeout== -1 ? 0 : &to)) < 0)
188         if (errno != EINTR)
189         {
190             yaz_log(YLOG_ERRNO|YLOG_WARN, "select");
191             yaz_log(YLOG_WARN, "errno=%d max=%d timeout=%d",
192                              errno, max, timeout);
193             if (++pass > 10)
194                 return -1;
195         }
196     yaz_log(m_log, "select returned res=%d", res);
197     now = time(0);
198     for (p = m_observers; p; p = p->next)
199     {
200         int fd = p->fd;
201         int mask = 0;
202         if (FD_ISSET(fd, &in))
203             mask |= SOCKET_OBSERVE_READ;
204
205         if (FD_ISSET(fd, &out))
206             mask |= SOCKET_OBSERVE_WRITE;
207
208         if (FD_ISSET(fd, &except))
209             mask |= SOCKET_OBSERVE_EXCEPT;
210         
211         if (mask)
212         {
213             SocketEvent *event = new SocketEvent;
214             p->last_activity = now;
215             event->observer = p->observer;
216             event->event = mask;
217             putEvent (event);
218
219             yaz_log (m_log, "putEvent I/O mask=%d", mask);
220         }
221         else if (res == 0 && p->timeout_this == timeout)
222         {
223             SocketEvent *event = new SocketEvent;
224             assert (p->last_activity);
225             yaz_log (m_log, "putEvent timeout fd=%d, now = %ld last_activity=%ld timeout=%d",
226                      p->fd, now, p->last_activity, p->timeout);
227             p->last_activity = now;
228             event->observer = p->observer;
229             event->event = SOCKET_OBSERVE_TIMEOUT;
230             putEvent (event);
231         }
232     }
233     if ((event = getEvent()))
234     {
235         event->observer->socketNotify(event->event);
236         delete event;
237         return 1;
238     }
239     yaz_log(YLOG_WARN, "unhandled event in processEvent res=%d", res);
240     return 1;
241 }
242
243
244 //    n p    n p  ......   n p    n p
245 //   front                        back
246
247 void SocketManager::putEvent(SocketEvent *event)
248 {
249     // put in back of queue
250     if (m_queue_back)
251     {
252         m_queue_back->prev = event;
253         assert (m_queue_front);
254     }
255     else
256     {
257         assert (!m_queue_front);
258         m_queue_front = event;
259     }
260     event->next = m_queue_back;
261     event->prev = 0;
262     m_queue_back = event;
263 }
264
265 SocketManager::SocketEvent *SocketManager::getEvent()
266 {
267     // get from front of queue
268     SocketEvent *event = m_queue_front;
269     if (!event)
270         return 0;
271     assert (m_queue_back);
272     m_queue_front = event->prev;
273     if (m_queue_front)
274     {
275         assert (m_queue_back);
276         m_queue_front->next = 0;
277     }
278     else
279         m_queue_back = 0;
280     return event;
281 }
282
283 void SocketManager::removeEvent(ISocketObserver *observer)
284 {
285     SocketEvent *ev = m_queue_back;
286     while (ev)
287     {
288         SocketEvent *ev_next = ev->next;
289         if (observer == ev->observer)
290         {
291             if (ev->prev)
292                 ev->prev->next = ev->next;
293             else
294                 m_queue_back = ev->next;
295             if (ev->next)
296                 ev->next->prev = ev->prev;
297             else
298                 m_queue_front = ev->prev;
299             delete ev;
300         }
301         ev = ev_next;
302     }
303 }
304
305 SocketManager::SocketManager()
306 {
307     m_observers = 0;
308     m_queue_front = 0;
309     m_queue_back = 0;
310     m_log = YLOG_DEBUG;
311 }
312
313 SocketManager::~SocketManager()
314 {
315     deleteObservers();
316 }