OverSim
XmlRpcDispatch.cc
Go to the documentation of this file.
1 
7 #include "XmlRpcDispatch.h"
8 #include "XmlRpcSource.h"
9 #include "XmlRpcUtil.h"
10 
11 #include <errno.h>
12 #include <math.h>
13 #include <sys/timeb.h>
14 
15 #ifdef _WIN32
16 #define _WINDOWS
17 #endif
18 
19 #if defined(_WINDOWS)
20 # include <winsock2.h>
21 
22 # define USE_FTIME
23 # if defined(_MSC_VER)
24 # define timeb _timeb
25 # define ftime _ftime
26 # endif
27 #else
28 # include <sys/time.h>
29 #endif // _WINDOWS
30 
31 
32 using namespace XmlRpc;
33 
34 
36 {
37  _endTime = -1.0;
38  _doClear = false;
39  _inWork = false;
40 }
41 
42 
44 {
45 }
46 
47 // Monitor this source for the specified events and call its event handler
48 // when the event occurs
49 void
50 XmlRpcDispatch::addSource(XmlRpcSource* source, unsigned mask)
51 {
52  _sources.push_back(MonitoredSource(source, mask));
53 }
54 
55 // Stop monitoring this source. Does not close the source.
56 void
58 {
59  for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
60  if (it->getSource() == source)
61  {
62  _sources.erase(it);
63  break;
64  }
65 }
66 
67 
68 // Modify the types of events to watch for on this source
69 void
70 XmlRpcDispatch::setSourceEvents(XmlRpcSource* source, unsigned eventMask)
71 {
72  for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
73  if (it->getSource() == source)
74  {
75  it->getMask() = eventMask;
76  break;
77  }
78 }
79 
80 
81 
82 // Watch current set of sources and process events
83 void
84 XmlRpcDispatch::work(double timeout)
85 {
86  // Compute end time
87  double timeNow = getTime();
88  _endTime = (timeout < 0.0) ? -1.0 : (timeNow + timeout);
89  _doClear = false;
90  _inWork = true;
91 
92  // Only work while there is something to monitor
93  while (_sources.size() > 0) {
94 
95  // Wait for and dispatch events
96  if ( ! waitForAndProcessEvents(timeout))
97  {
98  _inWork = false;
99  return;
100  }
101 
102 
103  // Check whether to clear all sources
104  if (_doClear)
105  {
106  SourceList closeList = _sources;
107  _sources.clear();
108  for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) {
109  XmlRpcSource *src = it->getSource();
110  src->close();
111  }
112 
113  _doClear = false;
114  }
115 
116  // Check whether end time has passed or exit has been called
117  if (_endTime == 0.0) // Exit
118  break;
119  else if (_endTime > 0.0) // Check for timeout
120  {
121  double t = getTime();
122  if (t > _endTime)
123  break;
124 
125  // Decrement timeout by elapsed time
126  timeout -= (t - timeNow);
127  if (timeout < 0.0)
128  timeout = 0.0; // Shouldn't happen but its fp math...
129  timeNow = t;
130  }
131  }
132 
133  _inWork = false;
134 }
135 
136 
137 
138 // Exit from work routine. Presumably this will be called from
139 // one of the source event handlers.
140 void
142 {
143  _endTime = 0.0; // Return from work asap
144 }
145 
146 
147 // Clear all sources from the monitored sources list
148 void
150 {
151  if (_inWork)
152  _doClear = true; // Finish reporting current events before clearing
153  else
154  {
155  SourceList closeList = _sources;
156  _sources.clear();
157  for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it)
158  it->getSource()->close();
159  }
160 }
161 
162 
163 // Time utility
164 double
166 {
167 #ifdef USE_FTIME
168  struct timeb tbuff;
169 
170  ftime(&tbuff);
171  return ((double) tbuff.time + ((double)tbuff.millitm / 1000.0) +
172  ((double) tbuff.timezone * 60));
173 #else
174  struct timeval tv;
175  struct timezone tz;
176 
177  gettimeofday(&tv, &tz);
178  return (tv.tv_sec + tv.tv_usec / 1000000.0);
179 #endif /* USE_FTIME */
180 }
181 
182 
183 // Wait for I/O on any source, timeout, or interrupt signal.
184 bool
186 {
187 #if defined(_WINDOWS) && 0
188 
189  int nHandles = 0;
190  SourceList::iterator it;
191  for (it=_sources.begin(); it!=_sources.end(); ++it) {
192  int fd = it->getSource()->getfd();
193  int mask = 0;
194  if (it->getMask() & ReadableEvent) mask = (FD_READ | PACKET_FD_CLOSE | FD_ACCEPT);
195  if (it->getMask() & WritableEvent) mask |= (FD_WRITE | PACKET_FD_CLOSE);
196 
197 #else // Posix
198 
199  // Construct the sets of descriptors we are interested in
200  fd_set inFd, outFd, excFd;
201  FD_ZERO(&inFd);
202  FD_ZERO(&outFd);
203  FD_ZERO(&excFd);
204 
205  int maxFd = -1;
206  SourceList::iterator it;
207  for (it=_sources.begin(); it!=_sources.end(); ++it) {
208  int fd = it->getSource()->getfd();
209  if (it->getMask() & ReadableEvent) FD_SET(fd, &inFd);
210  if (it->getMask() & WritableEvent) FD_SET(fd, &outFd);
211  if (it->getMask() & Exception) FD_SET(fd, &excFd);
212  if (it->getMask() && fd > maxFd) maxFd = fd;
213  }
214 
215  // Check for events
216  int nEvents;
217  if (_endTime < 0.0)
218  nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL);
219  else
220  {
221  struct timeval tv;
222  tv.tv_sec = (int)floor(timeout);
223  tv.tv_usec = ((int)floor(1000000.0 * (timeout-floor(timeout)))) % 1000000;
224  nEvents = select(maxFd+1, &inFd, &outFd, &excFd, &tv);
225  }
226 
227  if (nEvents < 0 && errno != EINTR)
228  {
229  XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents);
230  return false;
231  }
232 
233  // Process events
234  for (it=_sources.begin(); it != _sources.end(); )
235  {
236  SourceList::iterator thisIt = it++;
237  XmlRpcSource* src = thisIt->getSource();
238  int fd = src->getfd();
239 
240  if (fd <= maxFd) {
241  // handleEvent is called once per event type signalled
242  unsigned newMask = 0;
243  int nset = 0;
244  if (FD_ISSET(fd, &inFd))
245  {
246  newMask |= src->handleEvent(ReadableEvent);
247  ++nset;
248  }
249  if (FD_ISSET(fd, &outFd))
250  {
251  newMask |= src->handleEvent(WritableEvent);
252  ++nset;
253  }
254  if (FD_ISSET(fd, &excFd))
255  {
256  newMask |= src->handleEvent(Exception);
257  ++nset;
258  }
259 
260  // Some event occurred
261  if (nset)
262  {
263  if (newMask)
264  thisIt->getMask() = newMask;
265  else // Stop monitoring this one
266  {
267  _sources.erase(thisIt);
268  if ( ! src->getKeepOpen())
269  src->close();
270  }
271  }
272  }
273  }
274 #endif
275 
276  return true;
277 }