14e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
24e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#include "XmlRpcDispatch.h"
34e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#include "XmlRpcSource.h"
44e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#include "XmlRpcUtil.h"
54e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
64e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#include <math.h>
74e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
84e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#if defined(_WINDOWS)
94e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius# include <winsock2.h>
104e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
114e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius# define USE_FTIME
124e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius# if defined(_MSC_VER)
134e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#  define timeb _timeb
144e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#  define ftime _ftime
154e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius# endif
164e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#else
174e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius# include <sys/time.h>
184e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#endif  // _WINDOWS
194e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
204e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
214e2ea8184cc1f9609f1f1251394316629a108a78Roshan Piususing namespace XmlRpc;
224e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
234e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
244e2ea8184cc1f9609f1f1251394316629a108a78Roshan PiusXmlRpcDispatch::XmlRpcDispatch()
254e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius{
264e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  _endTime = -1.0;
274e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  _doClear = false;
284e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  _inWork = false;
294e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius}
304e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
314e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
324e2ea8184cc1f9609f1f1251394316629a108a78Roshan PiusXmlRpcDispatch::~XmlRpcDispatch()
334e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius{
344e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius}
354e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
364e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius// Monitor this source for the specified events and call its event handler
374e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius// when the event occurs
384e2ea8184cc1f9609f1f1251394316629a108a78Roshan Piusvoid
394e2ea8184cc1f9609f1f1251394316629a108a78Roshan PiusXmlRpcDispatch::addSource(XmlRpcSource* source, unsigned mask)
404e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius{
414e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  _sources.push_back(MonitoredSource(source, mask));
424e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius}
434e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
444e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius// Stop monitoring this source. Does not close the source.
454e2ea8184cc1f9609f1f1251394316629a108a78Roshan Piusvoid
464e2ea8184cc1f9609f1f1251394316629a108a78Roshan PiusXmlRpcDispatch::removeSource(XmlRpcSource* source)
474e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius{
484e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
494e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    if (it->getSource() == source)
504e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    {
514e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      _sources.erase(it);
524e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      break;
534e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    }
544e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius}
554e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
564e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
574e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius// Modify the types of events to watch for on this source
584e2ea8184cc1f9609f1f1251394316629a108a78Roshan Piusvoid
594e2ea8184cc1f9609f1f1251394316629a108a78Roshan PiusXmlRpcDispatch::setSourceEvents(XmlRpcSource* source, unsigned eventMask)
604e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius{
614e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
624e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    if (it->getSource() == source)
634e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    {
644e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      it->getMask() = eventMask;
654e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      break;
664e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    }
674e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius}
684e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
694e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
704e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
714e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius// Watch current set of sources and process events
724e2ea8184cc1f9609f1f1251394316629a108a78Roshan Piusvoid
734e2ea8184cc1f9609f1f1251394316629a108a78Roshan PiusXmlRpcDispatch::work(double timeout)
744e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius{
754e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  // Compute end time
764e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  _endTime = (timeout < 0.0) ? -1.0 : (getTime() + timeout);
774e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  _doClear = false;
784e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  _inWork = true;
794e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
804e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  // Only work while there is something to monitor
814e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  while (_sources.size() > 0) {
824e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
834e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    // Construct the sets of descriptors we are interested in
844e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    fd_set inFd, outFd, excFd;
854e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius	  FD_ZERO(&inFd);
864e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius	  FD_ZERO(&outFd);
874e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius	  FD_ZERO(&excFd);
884e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
894e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    int maxFd = -1;     // Not used on windows
904e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    SourceList::iterator it;
914e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    for (it=_sources.begin(); it!=_sources.end(); ++it) {
924e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      int fd = it->getSource()->getfd();
934e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      if (it->getMask() & ReadableEvent) FD_SET(fd, &inFd);
944e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      if (it->getMask() & WritableEvent) FD_SET(fd, &outFd);
954e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      if (it->getMask() & Exception)     FD_SET(fd, &excFd);
964e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      if (it->getMask() && fd > maxFd)   maxFd = fd;
974e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    }
984e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
994e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    // Check for events
1004e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    int nEvents;
1014e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    if (timeout < 0.0)
1024e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL);
1034e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    else
1044e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    {
1054e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      struct timeval tv;
1064e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      tv.tv_sec = (int)floor(timeout);
1074e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      tv.tv_usec = ((int)floor(1000000.0 * (timeout-floor(timeout)))) % 1000000;
1084e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      nEvents = select(maxFd+1, &inFd, &outFd, &excFd, &tv);
1094e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    }
1104e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1114e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    if (nEvents < 0)
1124e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    {
1134e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents);
1144e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      _inWork = false;
1154e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      return;
1164e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    }
1174e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1184e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    // Process events
1194e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    for (it=_sources.begin(); it != _sources.end(); )
1204e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    {
1214e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      SourceList::iterator thisIt = it++;
1224e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      XmlRpcSource* src = thisIt->getSource();
1234e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      int fd = src->getfd();
1244e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      unsigned newMask = (unsigned) -1;
1254e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      if (fd <= maxFd) {
1264e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius        // If you select on multiple event types this could be ambiguous
1274e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius        if (FD_ISSET(fd, &inFd))
1284e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius          newMask &= src->handleEvent(ReadableEvent);
1294e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius        if (FD_ISSET(fd, &outFd))
1304e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius          newMask &= src->handleEvent(WritableEvent);
1314e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius        if (FD_ISSET(fd, &excFd))
1324e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius          newMask &= src->handleEvent(Exception);
1334e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1344e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius        if ( ! newMask) {
1354e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius          _sources.erase(thisIt);  // Stop monitoring this one
1364e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius          if ( ! src->getKeepOpen())
1374e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius            src->close();
1384e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius        } else if (newMask != (unsigned) -1) {
1394e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius          thisIt->getMask() = newMask;
1404e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius        }
1414e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      }
1424e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    }
1434e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1444e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    // Check whether to clear all sources
1454e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    if (_doClear)
1464e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    {
1474e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      SourceList closeList = _sources;
1484e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      _sources.clear();
1494e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) {
1504e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius	XmlRpcSource *src = it->getSource();
1514e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius        src->close();
1524e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      }
1534e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1544e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      _doClear = false;
1554e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    }
1564e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1574e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    // Check whether end time has passed
1584e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    if (0 <= _endTime && getTime() > _endTime)
1594e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      break;
1604e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  }
1614e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1624e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  _inWork = false;
1634e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius}
1644e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1654e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1664e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius// Exit from work routine. Presumably this will be called from
1674e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius// one of the source event handlers.
1684e2ea8184cc1f9609f1f1251394316629a108a78Roshan Piusvoid
1694e2ea8184cc1f9609f1f1251394316629a108a78Roshan PiusXmlRpcDispatch::exit()
1704e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius{
1714e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  _endTime = 0.0;   // Return from work asap
1724e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius}
1734e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1744e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius// Clear all sources from the monitored sources list
1754e2ea8184cc1f9609f1f1251394316629a108a78Roshan Piusvoid
1764e2ea8184cc1f9609f1f1251394316629a108a78Roshan PiusXmlRpcDispatch::clear()
1774e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius{
1784e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  if (_inWork)
1794e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    _doClear = true;  // Finish reporting current events before clearing
1804e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  else
1814e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  {
1824e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    SourceList closeList = _sources;
1834e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    _sources.clear();
1844e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius    for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it)
1854e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius      it->getSource()->close();
1864e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  }
1874e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius}
1884e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1894e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1904e2ea8184cc1f9609f1f1251394316629a108a78Roshan Piusdouble
1914e2ea8184cc1f9609f1f1251394316629a108a78Roshan PiusXmlRpcDispatch::getTime()
1924e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius{
1934e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#ifdef USE_FTIME
1944e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  struct timeb	tbuff;
1954e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
1964e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  ftime(&tbuff);
1974e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  return ((double) tbuff.time + ((double)tbuff.millitm / 1000.0) +
1984e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius	  ((double) tbuff.timezone * 60));
1994e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#else
2004e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  struct timeval	tv;
2014e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  struct timezone	tz;
2024e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
2034e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  gettimeofday(&tv, &tz);
2044e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius  return (tv.tv_sec + tv.tv_usec / 1000000.0);
2054e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius#endif /* USE_FTIME */
2064e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius}
2074e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
2084e2ea8184cc1f9609f1f1251394316629a108a78Roshan Pius
209