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 21using namespace XmlRpc; 22 23 24XmlRpcDispatch::XmlRpcDispatch() 25{ 26 _endTime = -1.0; 27 _doClear = false; 28 _inWork = false; 29} 30 31 32XmlRpcDispatch::~XmlRpcDispatch() 33{ 34} 35 36// Monitor this source for the specified events and call its event handler 37// when the event occurs 38void 39XmlRpcDispatch::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. 45void 46XmlRpcDispatch::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 58void 59XmlRpcDispatch::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 72void 73XmlRpcDispatch::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. 168void 169XmlRpcDispatch::exit() 170{ 171 _endTime = 0.0; // Return from work asap 172} 173 174// Clear all sources from the monitored sources list 175void 176XmlRpcDispatch::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 190double 191XmlRpcDispatch::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