Home | History | Annotate | Download | only in src
      1 
      2 #include "XmlRpcDispatch.h"
      3 #include "XmlRpcSource.h"
      4 #include "XmlRpcUtil.h"
      5 
      6 #include <math.h>
      7 
      8 #if defined(_WINDOWS)
      9 # include <winsock2.h>
     10 
     11 # define USE_FTIME
     12 # if defined(_MSC_VER)
     13 #  define timeb _timeb
     14 #  define ftime _ftime
     15 # endif
     16 #else
     17 # include <sys/time.h>
     18 #endif  // _WINDOWS
     19 
     20 
     21 using namespace XmlRpc;
     22 
     23 
     24 XmlRpcDispatch::XmlRpcDispatch()
     25 {
     26   _endTime = -1.0;
     27   _doClear = false;
     28   _inWork = false;
     29 }
     30 
     31 
     32 XmlRpcDispatch::~XmlRpcDispatch()
     33 {
     34 }
     35 
     36 // Monitor this source for the specified events and call its event handler
     37 // when the event occurs
     38 void
     39 XmlRpcDispatch::addSource(XmlRpcSource* source, unsigned mask)
     40 {
     41   _sources.push_back(MonitoredSource(source, mask));
     42 }
     43 
     44 // Stop monitoring this source. Does not close the source.
     45 void
     46 XmlRpcDispatch::removeSource(XmlRpcSource* source)
     47 {
     48   for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
     49     if (it->getSource() == source)
     50     {
     51       _sources.erase(it);
     52       break;
     53     }
     54 }
     55 
     56 
     57 // Modify the types of events to watch for on this source
     58 void
     59 XmlRpcDispatch::setSourceEvents(XmlRpcSource* source, unsigned eventMask)
     60 {
     61   for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
     62     if (it->getSource() == source)
     63     {
     64       it->getMask() = eventMask;
     65       break;
     66     }
     67 }
     68 
     69 
     70 
     71 // Watch current set of sources and process events
     72 void
     73 XmlRpcDispatch::work(double timeout)
     74 {
     75   // Compute end time
     76   _endTime = (timeout < 0.0) ? -1.0 : (getTime() + timeout);
     77   _doClear = false;
     78   _inWork = true;
     79 
     80   // Only work while there is something to monitor
     81   while (_sources.size() > 0) {
     82 
     83     // Construct the sets of descriptors we are interested in
     84     fd_set inFd, outFd, excFd;
     85 	  FD_ZERO(&inFd);
     86 	  FD_ZERO(&outFd);
     87 	  FD_ZERO(&excFd);
     88 
     89     int maxFd = -1;     // Not used on windows
     90     SourceList::iterator it;
     91     for (it=_sources.begin(); it!=_sources.end(); ++it) {
     92       int fd = it->getSource()->getfd();
     93       if (it->getMask() & ReadableEvent) FD_SET(fd, &inFd);
     94       if (it->getMask() & WritableEvent) FD_SET(fd, &outFd);
     95       if (it->getMask() & Exception)     FD_SET(fd, &excFd);
     96       if (it->getMask() && fd > maxFd)   maxFd = fd;
     97     }
     98 
     99     // Check for events
    100     int nEvents;
    101     if (timeout < 0.0)
    102       nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL);
    103     else
    104     {
    105       struct timeval tv;
    106       tv.tv_sec = (int)floor(timeout);
    107       tv.tv_usec = ((int)floor(1000000.0 * (timeout-floor(timeout)))) % 1000000;
    108       nEvents = select(maxFd+1, &inFd, &outFd, &excFd, &tv);
    109     }
    110 
    111     if (nEvents < 0)
    112     {
    113       XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents);
    114       _inWork = false;
    115       return;
    116     }
    117 
    118     // Process events
    119     for (it=_sources.begin(); it != _sources.end(); )
    120     {
    121       SourceList::iterator thisIt = it++;
    122       XmlRpcSource* src = thisIt->getSource();
    123       int fd = src->getfd();
    124       unsigned newMask = (unsigned) -1;
    125       if (fd <= maxFd) {
    126         // If you select on multiple event types this could be ambiguous
    127         if (FD_ISSET(fd, &inFd))
    128           newMask &= src->handleEvent(ReadableEvent);
    129         if (FD_ISSET(fd, &outFd))
    130           newMask &= src->handleEvent(WritableEvent);
    131         if (FD_ISSET(fd, &excFd))
    132           newMask &= src->handleEvent(Exception);
    133 
    134         if ( ! newMask) {
    135           _sources.erase(thisIt);  // Stop monitoring this one
    136           if ( ! src->getKeepOpen())
    137             src->close();
    138         } else if (newMask != (unsigned) -1) {
    139           thisIt->getMask() = newMask;
    140         }
    141       }
    142     }
    143 
    144     // Check whether to clear all sources
    145     if (_doClear)
    146     {
    147       SourceList closeList = _sources;
    148       _sources.clear();
    149       for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) {
    150 	XmlRpcSource *src = it->getSource();
    151         src->close();
    152       }
    153 
    154       _doClear = false;
    155     }
    156 
    157     // Check whether end time has passed
    158     if (0 <= _endTime && getTime() > _endTime)
    159       break;
    160   }
    161 
    162   _inWork = false;
    163 }
    164 
    165 
    166 // Exit from work routine. Presumably this will be called from
    167 // one of the source event handlers.
    168 void
    169 XmlRpcDispatch::exit()
    170 {
    171   _endTime = 0.0;   // Return from work asap
    172 }
    173 
    174 // Clear all sources from the monitored sources list
    175 void
    176 XmlRpcDispatch::clear()
    177 {
    178   if (_inWork)
    179     _doClear = true;  // Finish reporting current events before clearing
    180   else
    181   {
    182     SourceList closeList = _sources;
    183     _sources.clear();
    184     for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it)
    185       it->getSource()->close();
    186   }
    187 }
    188 
    189 
    190 double
    191 XmlRpcDispatch::getTime()
    192 {
    193 #ifdef USE_FTIME
    194   struct timeb	tbuff;
    195 
    196   ftime(&tbuff);
    197   return ((double) tbuff.time + ((double)tbuff.millitm / 1000.0) +
    198 	  ((double) tbuff.timezone * 60));
    199 #else
    200   struct timeval	tv;
    201   struct timezone	tz;
    202 
    203   gettimeofday(&tv, &tz);
    204   return (tv.tv_sec + tv.tv_usec / 1000000.0);
    205 #endif /* USE_FTIME */
    206 }
    207 
    208 
    209