XmlRpcDispatch.cc

Go to the documentation of this file.
00001 
00007 #include "XmlRpcDispatch.h"
00008 #include "XmlRpcSource.h"
00009 #include "XmlRpcUtil.h"
00010 
00011 #include <errno.h>
00012 #include <math.h>
00013 #include <sys/timeb.h>
00014 
00015 #ifdef _WIN32
00016 #define _WINDOWS
00017 #endif
00018 
00019 #if defined(_WINDOWS)
00020 # include <winsock2.h>
00021 
00022 # define USE_FTIME
00023 # if defined(_MSC_VER)
00024 #  define timeb _timeb
00025 #  define ftime _ftime
00026 # endif
00027 #else
00028 # include <sys/time.h>
00029 #endif  // _WINDOWS
00030 
00031 
00032 using namespace XmlRpc;
00033 
00034 
00035 XmlRpcDispatch::XmlRpcDispatch()
00036 {
00037   _endTime = -1.0;
00038   _doClear = false;
00039   _inWork = false;
00040 }
00041 
00042 
00043 XmlRpcDispatch::~XmlRpcDispatch()
00044 {
00045 }
00046 
00047 // Monitor this source for the specified events and call its event handler
00048 // when the event occurs
00049 void
00050 XmlRpcDispatch::addSource(XmlRpcSource* source, unsigned mask)
00051 {
00052   _sources.push_back(MonitoredSource(source, mask));
00053 }
00054 
00055 // Stop monitoring this source. Does not close the source.
00056 void
00057 XmlRpcDispatch::removeSource(XmlRpcSource* source)
00058 {
00059   for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
00060     if (it->getSource() == source)
00061     {
00062       _sources.erase(it);
00063       break;
00064     }
00065 }
00066 
00067 
00068 // Modify the types of events to watch for on this source
00069 void
00070 XmlRpcDispatch::setSourceEvents(XmlRpcSource* source, unsigned eventMask)
00071 {
00072   for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
00073     if (it->getSource() == source)
00074     {
00075       it->getMask() = eventMask;
00076       break;
00077     }
00078 }
00079 
00080 
00081 
00082 // Watch current set of sources and process events
00083 void
00084 XmlRpcDispatch::work(double timeout)
00085 {
00086   // Compute end time
00087   double timeNow = getTime();
00088   _endTime = (timeout < 0.0) ? -1.0 : (timeNow + timeout);
00089   _doClear = false;
00090   _inWork = true;
00091 
00092   // Only work while there is something to monitor
00093   while (_sources.size() > 0) {
00094 
00095     // Wait for and dispatch events
00096     if ( ! waitForAndProcessEvents(timeout))
00097     {
00098       _inWork = false;
00099       return;
00100     }
00101 
00102 
00103     // Check whether to clear all sources
00104     if (_doClear)
00105     {
00106       SourceList closeList = _sources;
00107       _sources.clear();
00108       for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) {
00109         XmlRpcSource *src = it->getSource();
00110         src->close();
00111       }
00112 
00113       _doClear = false;
00114     }
00115 
00116     // Check whether end time has passed or exit has been called
00117     if (_endTime == 0.0)        // Exit
00118       break;
00119     else if (_endTime > 0.0)    // Check for timeout
00120     {
00121       double t = getTime();
00122       if (t > _endTime)
00123         break;
00124 
00125       // Decrement timeout by elapsed time
00126       timeout -= (t - timeNow);
00127       if (timeout < 0.0)
00128         timeout = 0.0;    // Shouldn't happen but its fp math...
00129       timeNow = t;
00130     }
00131   }
00132 
00133   _inWork = false;
00134 }
00135 
00136 
00137 
00138 // Exit from work routine. Presumably this will be called from
00139 // one of the source event handlers.
00140 void
00141 XmlRpcDispatch::exit()
00142 {
00143   _endTime = 0.0;   // Return from work asap
00144 }
00145 
00146 
00147 // Clear all sources from the monitored sources list
00148 void
00149 XmlRpcDispatch::clear()
00150 {
00151   if (_inWork)
00152     _doClear = true;  // Finish reporting current events before clearing
00153   else
00154   {
00155     SourceList closeList = _sources;
00156     _sources.clear();
00157     for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it)
00158       it->getSource()->close();
00159   }
00160 }
00161 
00162 
00163 // Time utility
00164 double
00165 XmlRpcDispatch::getTime()
00166 {
00167 #ifdef USE_FTIME
00168   struct timeb  tbuff;
00169 
00170   ftime(&tbuff);
00171   return ((double) tbuff.time + ((double)tbuff.millitm / 1000.0) +
00172           ((double) tbuff.timezone * 60));
00173 #else
00174   struct timeval        tv;
00175   struct timezone       tz;
00176 
00177   gettimeofday(&tv, &tz);
00178   return (tv.tv_sec + tv.tv_usec / 1000000.0);
00179 #endif /* USE_FTIME */
00180 }
00181 
00182 
00183 // Wait for I/O on any source, timeout, or interrupt signal.
00184 bool
00185 XmlRpcDispatch::waitForAndProcessEvents(double timeout)
00186 {
00187 #if defined(_WINDOWS) && 0
00188 
00189   int nHandles = 0;
00190   SourceList::iterator it;
00191   for (it=_sources.begin(); it!=_sources.end(); ++it) {
00192     int fd = it->getSource()->getfd();
00193     int mask = 0;
00194     if (it->getMask() & ReadableEvent) mask = (FD_READ | PACKET_FD_CLOSE | FD_ACCEPT);
00195     if (it->getMask() & WritableEvent) mask |= (FD_WRITE | PACKET_FD_CLOSE);
00196 
00197 #else   // Posix
00198 
00199   // Construct the sets of descriptors we are interested in
00200   fd_set inFd, outFd, excFd;
00201   FD_ZERO(&inFd);
00202   FD_ZERO(&outFd);
00203   FD_ZERO(&excFd);
00204 
00205   int maxFd = -1;
00206   SourceList::iterator it;
00207   for (it=_sources.begin(); it!=_sources.end(); ++it) {
00208     int fd = it->getSource()->getfd();
00209     if (it->getMask() & ReadableEvent) FD_SET(fd, &inFd);
00210     if (it->getMask() & WritableEvent) FD_SET(fd, &outFd);
00211     if (it->getMask() & Exception)     FD_SET(fd, &excFd);
00212     if (it->getMask() && fd > maxFd)   maxFd = fd;
00213   }
00214 
00215   // Check for events
00216   int nEvents;
00217   if (_endTime < 0.0)
00218     nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL);
00219   else
00220   {
00221     struct timeval tv;
00222     tv.tv_sec = (int)floor(timeout);
00223     tv.tv_usec = ((int)floor(1000000.0 * (timeout-floor(timeout)))) % 1000000;
00224     nEvents = select(maxFd+1, &inFd, &outFd, &excFd, &tv);
00225   }
00226 
00227   if (nEvents < 0 && errno != EINTR)
00228   {
00229     XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents);
00230     return false;
00231   }
00232 
00233   // Process events
00234   for (it=_sources.begin(); it != _sources.end(); )
00235   {
00236     SourceList::iterator thisIt = it++;
00237     XmlRpcSource* src = thisIt->getSource();
00238     int fd = src->getfd();
00239 
00240     if (fd <= maxFd) {
00241       // handleEvent is called once per event type signalled
00242       unsigned newMask = 0;
00243       int nset = 0;
00244       if (FD_ISSET(fd, &inFd))
00245       {
00246         newMask |= src->handleEvent(ReadableEvent);
00247         ++nset;
00248       }
00249       if (FD_ISSET(fd, &outFd))
00250       {
00251         newMask |= src->handleEvent(WritableEvent);
00252         ++nset;
00253       }
00254       if (FD_ISSET(fd, &excFd))
00255       {
00256         newMask |= src->handleEvent(Exception);
00257         ++nset;
00258       }
00259 
00260       // Some event occurred
00261       if (nset)
00262       {
00263         if (newMask)
00264           thisIt->getMask() = newMask;
00265         else       // Stop monitoring this one
00266         {
00267           _sources.erase(thisIt);
00268           if ( ! src->getKeepOpen())
00269             src->close();
00270         }
00271       }
00272     }
00273   }
00274 #endif
00275 
00276   return true;
00277 }
Generated on Wed May 26 16:21:15 2010 for OverSim by  doxygen 1.6.3