1 2 #include "XmlRpcDispatch.h" 3 #include "XmlRpcSource.h" 4 #include "XmlRpcUtil.h" 5 6 #include <math.h> 7 8 #if defined(_WINDOWS) 9 # include <winsock2.h> 10 11 # define USE_FTIME 12 # if defined(_MSC_VER) 13 # define timeb _timeb 14 # define ftime _ftime 15 # endif 16 #else 17 # include <sys/time.h> 18 #endif // _WINDOWS 19 20 21 using namespace XmlRpc; 22 23 24 XmlRpcDispatch::XmlRpcDispatch() 25 { 26 _endTime = -1.0; 27 _doClear = false; 28 _inWork = false; 29 } 30 31 32 XmlRpcDispatch::~XmlRpcDispatch() 33 { 34 } 35 36 // Monitor this source for the specified events and call its event handler 37 // when the event occurs 38 void 39 XmlRpcDispatch::addSource(XmlRpcSource* source, unsigned mask) 40 { 41 _sources.push_back(MonitoredSource(source, mask)); 42 } 43 44 // Stop monitoring this source. Does not close the source. 45 void 46 XmlRpcDispatch::removeSource(XmlRpcSource* source) 47 { 48 for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it) 49 if (it->getSource() == source) 50 { 51 _sources.erase(it); 52 break; 53 } 54 } 55 56 57 // Modify the types of events to watch for on this source 58 void 59 XmlRpcDispatch::setSourceEvents(XmlRpcSource* source, unsigned eventMask) 60 { 61 for (SourceList::iterator it=_sources.begin(); it!=_sources.end(); ++it) 62 if (it->getSource() == source) 63 { 64 it->getMask() = eventMask; 65 break; 66 } 67 } 68 69 70 71 // Watch current set of sources and process events 72 void 73 XmlRpcDispatch::work(double timeout) 74 { 75 // Compute end time 76 _endTime = (timeout < 0.0) ? -1.0 : (getTime() + timeout); 77 _doClear = false; 78 _inWork = true; 79 80 // Only work while there is something to monitor 81 while (_sources.size() > 0) { 82 83 // Construct the sets of descriptors we are interested in 84 fd_set inFd, outFd, excFd; 85 FD_ZERO(&inFd); 86 FD_ZERO(&outFd); 87 FD_ZERO(&excFd); 88 89 int maxFd = -1; // Not used on windows 90 SourceList::iterator it; 91 for (it=_sources.begin(); it!=_sources.end(); ++it) { 92 int fd = it->getSource()->getfd(); 93 if (it->getMask() & ReadableEvent) FD_SET(fd, &inFd); 94 if (it->getMask() & WritableEvent) FD_SET(fd, &outFd); 95 if (it->getMask() & Exception) FD_SET(fd, &excFd); 96 if (it->getMask() && fd > maxFd) maxFd = fd; 97 } 98 99 // Check for events 100 int nEvents; 101 if (timeout < 0.0) 102 nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL); 103 else 104 { 105 struct timeval tv; 106 tv.tv_sec = (int)floor(timeout); 107 tv.tv_usec = ((int)floor(1000000.0 * (timeout-floor(timeout)))) % 1000000; 108 nEvents = select(maxFd+1, &inFd, &outFd, &excFd, &tv); 109 } 110 111 if (nEvents < 0) 112 { 113 XmlRpcUtil::error("Error in XmlRpcDispatch::work: error in select (%d).", nEvents); 114 _inWork = false; 115 return; 116 } 117 118 // Process events 119 for (it=_sources.begin(); it != _sources.end(); ) 120 { 121 SourceList::iterator thisIt = it++; 122 XmlRpcSource* src = thisIt->getSource(); 123 int fd = src->getfd(); 124 unsigned newMask = (unsigned) -1; 125 if (fd <= maxFd) { 126 // If you select on multiple event types this could be ambiguous 127 if (FD_ISSET(fd, &inFd)) 128 newMask &= src->handleEvent(ReadableEvent); 129 if (FD_ISSET(fd, &outFd)) 130 newMask &= src->handleEvent(WritableEvent); 131 if (FD_ISSET(fd, &excFd)) 132 newMask &= src->handleEvent(Exception); 133 134 if ( ! newMask) { 135 _sources.erase(thisIt); // Stop monitoring this one 136 if ( ! src->getKeepOpen()) 137 src->close(); 138 } else if (newMask != (unsigned) -1) { 139 thisIt->getMask() = newMask; 140 } 141 } 142 } 143 144 // Check whether to clear all sources 145 if (_doClear) 146 { 147 SourceList closeList = _sources; 148 _sources.clear(); 149 for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) { 150 XmlRpcSource *src = it->getSource(); 151 src->close(); 152 } 153 154 _doClear = false; 155 } 156 157 // Check whether end time has passed 158 if (0 <= _endTime && getTime() > _endTime) 159 break; 160 } 161 162 _inWork = false; 163 } 164 165 166 // Exit from work routine. Presumably this will be called from 167 // one of the source event handlers. 168 void 169 XmlRpcDispatch::exit() 170 { 171 _endTime = 0.0; // Return from work asap 172 } 173 174 // Clear all sources from the monitored sources list 175 void 176 XmlRpcDispatch::clear() 177 { 178 if (_inWork) 179 _doClear = true; // Finish reporting current events before clearing 180 else 181 { 182 SourceList closeList = _sources; 183 _sources.clear(); 184 for (SourceList::iterator it=closeList.begin(); it!=closeList.end(); ++it) 185 it->getSource()->close(); 186 } 187 } 188 189 190 double 191 XmlRpcDispatch::getTime() 192 { 193 #ifdef USE_FTIME 194 struct timeb tbuff; 195 196 ftime(&tbuff); 197 return ((double) tbuff.time + ((double)tbuff.millitm / 1000.0) + 198 ((double) tbuff.timezone * 60)); 199 #else 200 struct timeval tv; 201 struct timezone tz; 202 203 gettimeofday(&tv, &tz); 204 return (tv.tv_sec + tv.tv_usec / 1000000.0); 205 #endif /* USE_FTIME */ 206 } 207 208 209