$search
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