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


xmlrpcpp
Author(s): Chris Morley, Konstantin Pilipchuk, Morgan Quigley
autogenerated on Mon Oct 6 2014 11:46:40