Initial revision
[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.1  1999-01-28 09:41:07  adam
8  * Initial revision
9  *
10  */
11 #include <assert.h>
12 #ifdef WINDOWS
13 #include <winsock.h>
14 #else
15 #include <sys/time.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18 #endif
19 #include <errno.h>
20
21 #include <log.h>
22 #include <yaz-socket-manager.h>
23
24
25 Yaz_SocketManager::YazSocketEntry **Yaz_SocketManager::lookupObserver(
26     IYazSocketObserver *observer)
27 {
28     YazSocketEntry **se;
29     
30     for (se = &m_observers; *se; se = &(*se)->next)
31         if ((*se)->observer == observer)
32             break;
33     return se;
34 }
35
36 void Yaz_SocketManager::addObserver(int fd, IYazSocketObserver *observer)
37 {
38     YazSocketEntry *se;
39
40     se = *lookupObserver(observer);
41     if (!se)
42     {
43         se = new YazSocketEntry;
44         se->next= m_observers;
45         m_observers = se;
46         se->observer = observer;
47     }
48     se->fd = fd;
49     se->mask = 0;
50 }
51
52 void Yaz_SocketManager::deleteObserver(IYazSocketObserver *observer)
53 {
54     YazSocketEntry **se = lookupObserver(observer);
55     if (*se)
56     {
57         removeEvent (observer);
58         YazSocketEntry *se_tmp = *se;
59         *se = (*se)->next;
60         delete se_tmp;
61     }
62 }
63
64 void Yaz_SocketManager::deleteObservers()
65 {
66     YazSocketEntry *se = m_observers;
67     
68     while (se)
69     {
70         YazSocketEntry *se_next = se->next;
71         delete se;
72         se = se_next;
73     }
74     m_observers = 0;
75 }
76
77 void Yaz_SocketManager::maskObserver(IYazSocketObserver *observer, int mask)
78 {
79     YazSocketEntry *se;
80
81     se = *lookupObserver(observer);
82     if (se)
83         se->mask = mask;
84 }
85
86 void Yaz_SocketManager::timeoutObserver(IYazSocketObserver *observer,
87                                         unsigned timeout)
88 {
89     YazSocketEntry *se;
90
91     se = *lookupObserver(observer);
92     if (se)
93         se->timeout = timeout;
94 }
95
96 int Yaz_SocketManager::processEvent()
97 {
98     YazSocketEvent *event = getEvent();
99     if (event)
100     {
101         event->observer->socketNotify(event->event);
102         return 1;
103     }
104
105     fd_set in, out, except;
106     int res;
107     int max = 0;
108     int no = 0;
109     struct timeval to;
110     struct timeval *timeout = &to;
111
112     FD_ZERO(&in);
113     FD_ZERO(&out);
114     FD_ZERO(&except);
115
116     timeout = &to; /* hang on select */
117     to.tv_sec = 5*60;
118     to.tv_usec = 0;
119
120     for (YazSocketEntry *p = m_observers; p; p = p->next)
121     {
122         int fd = p->fd;
123         logf (LOG_LOG, "fd = %d mask=%d", fd, p->mask);
124         if (p->mask)
125             no++;
126         if (p->mask & YAZ_SOCKET_OBSERVE_READ)
127             FD_SET(fd, &in);
128         if (p->mask & YAZ_SOCKET_OBSERVE_WRITE)
129             FD_SET(fd, &out);
130         if (p->mask & YAZ_SOCKET_OBSERVE_EXCEPT)
131             FD_SET(fd, &except);
132         if (fd > max)
133             max = fd;
134     }
135     if (!no)
136         return 0;
137     while ((res = select(max + 1, &in, &out, &except, timeout)) < 0)
138         if (errno != EINTR)
139             return -1;
140
141     for (YazSocketEntry * p = m_observers; p; p = p->next)
142     {
143         int fd = p->fd;
144         int mask = 0;
145         if (FD_ISSET(fd, &in))
146             mask |= YAZ_SOCKET_OBSERVE_READ;
147
148         if (FD_ISSET(fd, &out))
149             mask |= YAZ_SOCKET_OBSERVE_WRITE;
150
151         if (FD_ISSET(fd, &except))
152             mask |= YAZ_SOCKET_OBSERVE_EXCEPT;
153         
154         if (mask)
155         {
156             YazSocketEvent *event = new YazSocketEvent;
157             event->observer = p->observer;
158             event->event = mask;
159             putEvent (event);
160         }
161     }
162     if ((event = getEvent()))
163     {
164         event->observer->socketNotify(event->event);
165         return 1;
166     }
167     return 0;
168 }
169
170 void Yaz_SocketManager::putEvent(YazSocketEvent *event)
171 {
172     logf (LOG_LOG, "putEvent p=%p event=%d", event, event->event);
173     // put in back of queue
174     if (m_queue_back)
175     {
176         m_queue_back->prev = event;
177         assert (m_queue_front);
178     }
179     else
180     {
181         assert (!m_queue_front);
182         m_queue_front = event;
183     }
184     event->next = m_queue_back;
185     event->prev = 0;
186     m_queue_back = event;
187 }
188
189 Yaz_SocketManager::YazSocketEvent *Yaz_SocketManager::getEvent()
190 {
191     // get from front of queue
192     YazSocketEvent *event = m_queue_front;
193     if (!event)
194         return 0;
195     assert (m_queue_back);
196     m_queue_front = event->prev;
197     if (m_queue_front)
198     {
199         assert (m_queue_back);
200         m_queue_front->next = 0;
201     }
202     else
203         m_queue_back = 0;
204     return event;
205 }
206
207 void Yaz_SocketManager::removeEvent(IYazSocketObserver *observer)
208 {
209     YazSocketEvent *ev = m_queue_back;
210     while (ev)
211     {
212         YazSocketEvent *ev_next = ev->next;
213         if (observer == ev->observer)
214         {
215             if (ev->prev)
216                 ev->prev->next = ev->next;
217             else
218                 m_queue_back = ev->next;
219             if (ev->next)
220                 ev->next->prev = ev->prev;
221             else
222                 m_queue_front = ev->prev;
223             delete ev;
224         }
225         ev = ev_next;
226     }
227 }
228
229 Yaz_SocketManager::Yaz_SocketManager()
230 {
231     m_observers = 0;
232     m_queue_front = 0;
233     m_queue_back = 0;
234 }
235
236 Yaz_SocketManager::~Yaz_SocketManager()
237 {
238     deleteObservers();
239 }