XmlRpcDispatch.cpp
Go to the documentation of this file.
00001 
00002 #include "XmlRpcDispatch.h"
00003 #include "XmlRpcSource.h"
00004 #include "XmlRpcUtil.h"
00005 
00006 #include <math.h>
00007 #include <errno.h>
00008 #include <sys/timeb.h>
00009 #if defined (__ANDROID__)
00010 #include <sys/select.h>
00011 #endif
00012 
00013 #if defined(_WINDOWS)
00014 # include <winsock2.h>
00015 
00016 # define USE_FTIME
00017 # if defined(_MSC_VER)
00018 #  define timeb _timeb
00019 #  define ftime _ftime_s
00020 # endif
00021 #else
00022 # include <sys/time.h>
00023 #endif  // _WINDOWS
00024 
00025 
00026 using namespace XmlRpc;
00027 
00028 
00029 XmlRpcDispatch::XmlRpcDispatch()
00030 {
00031   _endTime = -1.0;
00032   _doClear = false;
00033   _inWork = false;
00034 }
00035 
00036 
00037 XmlRpcDispatch::~XmlRpcDispatch()
00038 {
00039 }
00040 
00041 // Monitor this source for the specified events and call its event handler
00042 // when the event occurs
00043 void
00044 XmlRpcDispatch::addSource(XmlRpcSource* source, unsigned mask)
00045 {
00046   _sources.push_back(MonitoredSource(source, mask));
00047 }
00048 
00049 // Stop monitoring this source. Does not close the source.
00050 void
00051 XmlRpcDispatch::removeSource(XmlRpcSource* source)
00052 {
00053   for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
00054     if (it->getSource() == source)
00055     {
00056       _sources.erase(it);
00057       break;
00058     }
00059 }
00060 
00061 
00062 // Modify the types of events to watch for on this source
00063 void 
00064 XmlRpcDispatch::setSourceEvents(XmlRpcSource* source, unsigned eventMask)
00065 {
00066   for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it)
00067     if (it->getSource() == source)
00068     {
00069       it->getMask() = eventMask;
00070       break;
00071     }
00072 }
00073 
00074 
00075 
00076 // Watch current set of sources and process events
00077 void
00078 XmlRpcDispatch::work(double timeout)
00079 {
00080   // Compute end time
00081   _endTime = (timeout < 0.0) ? -1.0 : (getTime() + timeout);
00082   _doClear = false;
00083   _inWork = true;
00084 
00085   // Only work while there is something to monitor
00086   while (_sources.size() > 0) {
00087 
00088     // Construct the sets of descriptors we are interested in
00089     fd_set inFd, outFd, excFd;
00090           FD_ZERO(&inFd);
00091           FD_ZERO(&outFd);
00092           FD_ZERO(&excFd);
00093 
00094     int maxFd = -1;     // Not used on windows
00095     SourceList::iterator it;
00096     for (it=_sources.begin(); it!=_sources.end(); ++it) {
00097       int fd = it->getSource()->getfd();
00098       if (it->getMask() & ReadableEvent) FD_SET(fd, &inFd);
00099       if (it->getMask() & WritableEvent) FD_SET(fd, &outFd);
00100       if (it->getMask() & Exception)     FD_SET(fd, &excFd);
00101       if (it->getMask() && fd > maxFd)   maxFd = fd;
00102     }
00103 
00104     // Check for events
00105     int nEvents;
00106     if (timeout < 0.0)
00107       nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL);
00108     else 
00109     {
00110       struct timeval tv;
00111       tv.tv_sec = (int)floor(timeout);
00112       tv.tv_usec = ((int)floor(1000000.0 * (timeout-floor(timeout)))) % 1000000;
00113       nEvents = select(maxFd+1, &inFd, &outFd, &excFd, &tv);
00114     }
00115 
00116     if (nEvents < 0)
00117     {
00118       if(errno != EINTR)
00119         XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents);
00120       _inWork = false;
00121       return;
00122     }
00123 
00124     // Process events
00125     for (it=_sources.begin(); it != _sources.end(); )
00126     {
00127       SourceList::iterator thisIt = it++;
00128       XmlRpcSource* src = thisIt->getSource();
00129       int fd = src->getfd();
00130       unsigned newMask = (unsigned) -1;
00131       if (fd <= maxFd) {
00132         // If you select on multiple event types this could be ambiguous
00133         if (FD_ISSET(fd, &inFd))
00134           newMask &= src->handleEvent(ReadableEvent);
00135         if (FD_ISSET(fd, &outFd))
00136           newMask &= src->handleEvent(WritableEvent);
00137         if (FD_ISSET(fd, &excFd))
00138           newMask &= src->handleEvent(Exception);
00139 
00140         // Find the source again.  It may have moved as a result of the way
00141         // that sources are removed and added in the call stack starting
00142         // from the handleEvent() calls above.
00143         for (thisIt=_sources.begin(); thisIt != _sources.end(); thisIt++)
00144         {
00145           if(thisIt->getSource() == src)
00146             break;
00147         }
00148         if(thisIt == _sources.end())
00149         {
00150           XmlRpcUtil::error("Error in XmlRpcDispatch::work: couldn't find source iterator");
00151           continue;
00152         }
00153 
00154         if ( ! newMask) {
00155           _sources.erase(thisIt);  // Stop monitoring this one
00156           if ( ! src->getKeepOpen())
00157             src->close();
00158         } else if (newMask != (unsigned) -1) {
00159           thisIt->getMask() = newMask;
00160         }
00161       }
00162     }
00163 
00164     // Check whether to clear all sources
00165     if (_doClear)
00166     {
00167       SourceList closeList = _sources;
00168       _sources.clear();
00169       for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) {
00170         XmlRpcSource *src = it->getSource();
00171         src->close();
00172       }
00173 
00174       _doClear = false;
00175     }
00176 
00177     // Check whether end time has passed
00178     if (0 <= _endTime && getTime() > _endTime)
00179       break;
00180   }
00181 
00182   _inWork = false;
00183 }
00184 
00185 
00186 // Exit from work routine. Presumably this will be called from
00187 // one of the source event handlers.
00188 void
00189 XmlRpcDispatch::exit()
00190 {
00191   _endTime = 0.0;   // Return from work asap
00192 }
00193 
00194 // Clear all sources from the monitored sources list
00195 void
00196 XmlRpcDispatch::clear()
00197 {
00198   if (_inWork)
00199     _doClear = true;  // Finish reporting current events before clearing
00200   else
00201   {
00202     SourceList closeList = _sources;
00203     _sources.clear();
00204     for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it)
00205       it->getSource()->close();
00206   }
00207 }
00208 
00209 
00210 double
00211 XmlRpcDispatch::getTime()
00212 {
00213 #ifdef USE_FTIME
00214   struct timeb  tbuff;
00215 
00216   ftime(&tbuff);
00217   return ((double) tbuff.time + ((double)tbuff.millitm / 1000.0) +
00218           ((double) tbuff.timezone * 60));
00219 #else
00220   struct timeval        tv;
00221   struct timezone       tz;
00222 
00223   gettimeofday(&tv, &tz);
00224   return (tv.tv_sec + tv.tv_usec / 1000000.0);
00225 #endif /* USE_FTIME */
00226 }
00227 
00228 


xmlrpcpp
Author(s): Chris Morley, Konstantin Pilipchuk, Morgan Quigley
autogenerated on Tue Mar 7 2017 03:44:43