Proxy removes OtherInfo Proxy Address and Session ID. Other
[yazpp-moved-to-github.git] / src / yaz-socket-manager.cpp
1 /*
2  * Copyright (c) 1998-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  * 
6  * $Log: yaz-socket-manager.cpp,v $
7  * Revision 1.7  1999-04-28 13:02:08  adam
8  * Added include of string.h.
9  *
10  * Revision 1.6  1999/04/21 12:09:01  adam
11  * Many improvements. Modified to proxy server to work with "sessions"
12  * based on cookies.
13  *
14  * Revision 1.5  1999/04/09 11:46:57  adam
15  * Added object Yaz_Z_Assoc. Much more functional client.
16  *
17  * Revision 1.4  1999/03/23 14:17:57  adam
18  * More work on timeout handling. Work on yaz-client.
19  *
20  * Revision 1.3  1999/02/02 14:01:23  adam
21  * First WIN32 port of YAZ++.
22  *
23  * Revision 1.2  1999/01/28 13:08:48  adam
24  * Yaz_PDU_Assoc better encapsulated. Memory leak fix in
25  * yaz-socket-manager.cc.
26  *
27  * Revision 1.1.1.1  1999/01/28 09:41:07  adam
28  * First implementation of YAZ++.
29  *
30  */
31 #include <assert.h>
32 #ifdef WIN32
33 #include <winsock.h>
34 #else
35 #include <sys/time.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #endif
39 #include <errno.h>
40 #include <string.h>
41
42 #include <log.h>
43 #include <yaz-socket-manager.h>
44
45
46 Yaz_SocketManager::YazSocketEntry **Yaz_SocketManager::lookupObserver(
47     IYazSocketObserver *observer)
48 {
49     YazSocketEntry **se;
50     
51     for (se = &m_observers; *se; se = &(*se)->next)
52         if ((*se)->observer == observer)
53             break;
54     return se;
55 }
56
57 void Yaz_SocketManager::addObserver(int fd, IYazSocketObserver *observer)
58 {
59     YazSocketEntry *se;
60
61     se = *lookupObserver(observer);
62     if (!se)
63     {
64         se = new YazSocketEntry;
65         se->next= m_observers;
66         m_observers = se;
67         se->observer = observer;
68     }
69     se->fd = fd;
70     se->mask = 0;
71     se->last_activity = 0;
72     se->timeout = 0;
73 }
74
75 void Yaz_SocketManager::deleteObserver(IYazSocketObserver *observer)
76 {
77     YazSocketEntry **se = lookupObserver(observer);
78     if (*se)
79     {
80         removeEvent (observer);
81         YazSocketEntry *se_tmp = *se;
82         *se = (*se)->next;
83         delete se_tmp;
84     }
85 }
86
87 void Yaz_SocketManager::deleteObservers()
88 {
89     YazSocketEntry *se = m_observers;
90     
91     while (se)
92     {
93         YazSocketEntry *se_next = se->next;
94         delete se;
95         se = se_next;
96     }
97     m_observers = 0;
98 }
99
100 void Yaz_SocketManager::maskObserver(IYazSocketObserver *observer, int mask)
101 {
102     YazSocketEntry *se;
103
104     se = *lookupObserver(observer);
105     if (se)
106         se->mask = mask;
107 }
108
109 void Yaz_SocketManager::timeoutObserver(IYazSocketObserver *observer,
110                                         unsigned timeout)
111 {
112     YazSocketEntry *se;
113
114     se = *lookupObserver(observer);
115     if (se)
116         se->timeout = timeout;
117 }
118
119 int Yaz_SocketManager::processEvent()
120 {
121     YazSocketEntry *p;
122     YazSocketEvent *event = getEvent();
123     unsigned timeout = 0;
124     logf (LOG_LOG, "processEvent");
125     if (event)
126     {
127         event->observer->socketNotify(event->event);
128         delete event;
129         return 1;
130     }
131
132     fd_set in, out, except;
133     int res;
134     int max = 0;
135     int no = 0;
136
137     FD_ZERO(&in);
138     FD_ZERO(&out);
139     FD_ZERO(&except);
140
141     time_t now = time(0);
142     for (p = m_observers; p; p = p->next)
143     {
144         int fd = p->fd;
145         if (p->mask)
146             no++;
147         if (p->mask & YAZ_SOCKET_OBSERVE_READ)
148             FD_SET(fd, &in);
149         if (p->mask & YAZ_SOCKET_OBSERVE_WRITE)
150             FD_SET(fd, &out);
151         if (p->mask & YAZ_SOCKET_OBSERVE_EXCEPT)
152             FD_SET(fd, &except);
153         if (fd > max)
154             max = fd;
155         if (p->timeout)
156         {
157             unsigned timeout_this;
158             timeout_this = p->timeout;
159             if (p->last_activity)
160                 timeout_this -= now - p->last_activity;
161             if (timeout_this < 1)
162                 timeout_this = 1;
163             if (!timeout || timeout_this < timeout)
164                 timeout = timeout_this;
165         }
166     }
167     if (!no)
168     {
169         logf (LOG_LOG, "no pending events return 0");
170         if (!m_observers)
171             logf (LOG_LOG, "no observers");
172         return 0;
173     }
174
175     struct timeval to;
176     to.tv_sec = timeout;
177     to.tv_usec = 0;
178     
179     logf (LOG_LOG, "timeout=%d", timeout);
180     while ((res = select(max + 1, &in, &out, &except, timeout ? &to : 0)) < 0)
181         if (errno != EINTR)
182             return -1;
183     now = time(0);
184     for (p = m_observers; p; p = p->next)
185     {
186         int fd = p->fd;
187         int mask = 0;
188         if (FD_ISSET(fd, &in))
189             mask |= YAZ_SOCKET_OBSERVE_READ;
190
191         if (FD_ISSET(fd, &out))
192             mask |= YAZ_SOCKET_OBSERVE_WRITE;
193
194         if (FD_ISSET(fd, &except))
195             mask |= YAZ_SOCKET_OBSERVE_EXCEPT;
196         
197         if (mask)
198         {
199             YazSocketEvent *event = new YazSocketEvent;
200             p->last_activity = now;
201             event->observer = p->observer;
202             event->event = mask;
203             putEvent (event);
204         }
205         else if (p->timeout && now >= p->last_activity + (int) (p->timeout))
206         {
207             YazSocketEvent *event = new YazSocketEvent;
208             p->last_activity = now;
209             event->observer = p->observer;
210             event->event = YAZ_SOCKET_OBSERVE_TIMEOUT;
211             putEvent (event);
212         }
213     }
214     if ((event = getEvent()))
215     {
216         event->observer->socketNotify(event->event);
217         delete event;
218         return 1;
219     }
220     return 0;
221 }
222
223 void Yaz_SocketManager::putEvent(YazSocketEvent *event)
224 {
225     // put in back of queue
226     if (m_queue_back)
227     {
228         m_queue_back->prev = event;
229         assert (m_queue_front);
230     }
231     else
232     {
233         assert (!m_queue_front);
234         m_queue_front = event;
235     }
236     event->next = m_queue_back;
237     event->prev = 0;
238     m_queue_back = event;
239 }
240
241 Yaz_SocketManager::YazSocketEvent *Yaz_SocketManager::getEvent()
242 {
243     // get from front of queue
244     YazSocketEvent *event = m_queue_front;
245     if (!event)
246         return 0;
247     assert (m_queue_back);
248     m_queue_front = event->prev;
249     if (m_queue_front)
250     {
251         assert (m_queue_back);
252         m_queue_front->next = 0;
253     }
254     else
255         m_queue_back = 0;
256     return event;
257 }
258
259 void Yaz_SocketManager::removeEvent(IYazSocketObserver *observer)
260 {
261     YazSocketEvent *ev = m_queue_back;
262     while (ev)
263     {
264         YazSocketEvent *ev_next = ev->next;
265         if (observer == ev->observer)
266         {
267             if (ev->prev)
268                 ev->prev->next = ev->next;
269             else
270                 m_queue_back = ev->next;
271             if (ev->next)
272                 ev->next->prev = ev->prev;
273             else
274                 m_queue_front = ev->prev;
275             delete ev;
276         }
277         ev = ev_next;
278     }
279 }
280
281 Yaz_SocketManager::Yaz_SocketManager()
282 {
283     m_observers = 0;
284     m_queue_front = 0;
285     m_queue_back = 0;
286 }
287
288 Yaz_SocketManager::~Yaz_SocketManager()
289 {
290     deleteObservers();
291 }