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