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
00048
00049 void
00050 XmlRpcDispatch::addSource(XmlRpcSource* source, unsigned mask)
00051 {
00052 _sources.push_back(MonitoredSource(source, mask));
00053 }
00054
00055
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
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
00083 void
00084 XmlRpcDispatch::work(double timeout)
00085 {
00086
00087 double timeNow = getTime();
00088 _endTime = (timeout < 0.0) ? -1.0 : (timeNow + timeout);
00089 _doClear = false;
00090 _inWork = true;
00091
00092
00093 while (_sources.size() > 0) {
00094
00095
00096 if ( ! waitForAndProcessEvents(timeout))
00097 {
00098 _inWork = false;
00099 return;
00100 }
00101
00102
00103
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
00117 if (_endTime == 0.0)
00118 break;
00119 else if (_endTime > 0.0)
00120 {
00121 double t = getTime();
00122 if (t > _endTime)
00123 break;
00124
00125
00126 timeout -= (t - timeNow);
00127 if (timeout < 0.0)
00128 timeout = 0.0;
00129 timeNow = t;
00130 }
00131 }
00132
00133 _inWork = false;
00134 }
00135
00136
00137
00138
00139
00140 void
00141 XmlRpcDispatch::exit()
00142 {
00143 _endTime = 0.0;
00144 }
00145
00146
00147
00148 void
00149 XmlRpcDispatch::clear()
00150 {
00151 if (_inWork)
00152 _doClear = true;
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
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
00180 }
00181
00182
00183
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
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
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
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
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
00261 if (nset)
00262 {
00263 if (newMask)
00264 thisIt->getMask() = newMask;
00265 else
00266 {
00267 _sources.erase(thisIt);
00268 if ( ! src->getKeepOpen())
00269 src->close();
00270 }
00271 }
00272 }
00273 }
00274 #endif
00275
00276 return true;
00277 }