9 static const char rcsid[] __attribute__((used)) =
"$Id: SocketMux.cpp 1653 2016-02-28 19:54:59Z sella $";
11 #include "SocketMux.h"
12 #include "../util/CommonMacro.h"
13 #include "../util/Time.h"
23 #include <arpa/inet.h>
24 #include <netinet/in.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/select.h>
34 using namespace sella::net;
36 SocketMux::SocketMux(ssize_t epollMaxEvents,
bool pthread_cancel)
throw (SocketException) :
39 cancel(pthread_cancel),
40 epollMaxEvents(epollMaxEvents),
47 events = (epoll_event*) calloc(epollMaxEvents,
sizeof(
struct epoll_event));
49 if ((e = epoll_create(EPOLL_SIZE)) == -1) {
50 THROW2(SocketException,
"epoll_create1()");
54 SocketMux::~SocketMux() {
57 }
catch (SocketException) { }
63 int SocketMux::epoll(
struct timeval *tv)
throw (SocketException) {
64 int c, msec = (int) sella::util::Time::tvtomsec(*tv);
69 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
70 c = ::epoll_wait(e, events, epollMaxEvents, msec);
71 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
77 THROW2(SocketException,
"epoll_wait()");
83 for (
int i = 0; i < c; i++) {
84 event = (bool) (events[i].events & EPOLLIN);
86 auto it = rMap.find(events[i].data.fd);
87 if (it != rMap.end()) {
88 it->second->read =
true;
90 rList.push_front(it->second);
94 event = (bool) (events[i].events & EPOLLOUT);
96 auto it = wMap.find(events[i].data.fd);
97 if (it != wMap.end()) {
98 it->second->write =
true;
100 wList.push_front(it->second);
104 event = (bool) ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP));
106 auto it = eMap.find(events[i].data.fd);
107 if (it != eMap.end()) {
108 it->second->except =
true;
110 eList.push_front(it->second);
118 int SocketMux::epoll(uint64_t usec)
throw (SocketException) {
119 struct timeval tv = sella::util::Time::usectotv(usec);
121 return this->epoll(&tv);
124 int SocketMux::select(
struct timeval *tv)
throw (SocketException) {
126 fd_set rfds, wfds, efds;
130 FD_COPY(&rfds, &rfdset);
132 FD_COPY(&wfds, &wfdset);
134 FD_COPY(&efds, &efdset);
136 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
137 c = ::select(fdmax + 1, &rfds, &wfds, &efds, tv);
138 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
141 if (errno == EINTR) {
144 THROW2(SocketException,
"select() [%d]", errno);
150 for (
auto it = rMap.cbegin(); it != rMap.cend(); ++it) {
151 if (FD_ISSET(it->first, &rfds)) {
152 it->second->read =
true;
153 rList.push_front(it->second);
155 if (++f >= c)
return c;
159 for (
auto it = wMap.cbegin(); it != wMap.cend(); ++it) {
160 if (FD_ISSET(it->first, &wfds)) {
161 it->second->write =
true;
162 wList.push_front(it->second);
164 if (++f >= c)
return c;
168 for (
auto it = eMap.cbegin(); it != eMap.cend(); ++it) {
169 if (FD_ISSET(it->first, &efds)) {
170 it->second->except =
true;
171 eList.push_front(it->second);
173 if (++f >= c)
return c;
180 int SocketMux::select(uint64_t usec)
throw (SocketException) {
181 struct timeval tv = sella::util::Time::usectotv(usec);
183 return this->select(&tv);
186 int SocketMux::rselect(
struct timeval *tv)
throw (SocketException) {
192 FD_COPY(&rfds, &rfdset);
194 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
195 c = ::select(fdmax + 1, &rfds, NULL, NULL, tv);
196 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
199 if (errno == EINTR) {
202 THROW2(SocketException,
"select() [%d]", errno);
208 for (
auto it = rMap.cbegin(); it != rMap.cend(); ++it) {
209 if (FD_ISSET(it->first, &rfds)) {
210 it->second->read =
true;
211 rList.push_front(it->second);
213 if (++f >= c)
return c;
220 int SocketMux::rselect(uint64_t usec)
throw (SocketException) {
221 struct timeval tv = sella::util::Time::usectotv(usec);
223 return this->rselect(&tv);
226 int SocketMux::wselect(
struct timeval *tv)
throw (SocketException) {
232 FD_COPY(&wfds, &wfdset);
234 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
235 c = ::select(fdmax + 1, NULL, &wfds, NULL, tv);
236 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
239 if (errno == EINTR) {
242 THROW2(SocketException,
"select() [%d]", errno);
248 for (
auto it = wMap.cbegin(); it != wMap.cend(); ++it) {
249 if (FD_ISSET(it->first, &wfds)) {
250 it->second->write =
true;
251 wList.push_front(it->second);
253 if (++f >= c)
return c;
260 int SocketMux::wselect(uint64_t usec)
throw (SocketException) {
261 struct timeval tv = sella::util::Time::usectotv(usec);
263 return this->wselect(&tv);
266 int SocketMux::eselect(
struct timeval *tv)
throw (SocketException) {
272 FD_COPY(&efds, &efdset);
274 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
275 c = ::select(fdmax + 1, NULL, NULL, &efds, tv);
276 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
279 if (errno == EINTR) {
282 THROW2(SocketException,
"select() [%d]", errno);
288 for (
auto it = eMap.cbegin(); it != eMap.cend(); ++it) {
289 if (FD_ISSET(it->first, &efds)) {
290 it->second->except =
true;
291 eList.push_front(it->second);
293 if (++f >= c)
return c;
300 int SocketMux::eselect(uint64_t usec)
throw (SocketException) {
301 struct timeval tv = sella::util::Time::usectotv(usec);
303 return this->eselect(&tv);
306 int SocketMux::rwselect(
struct timeval *tv)
throw (SocketException) {
313 FD_COPY(&rfds, &rfdset);
315 FD_COPY(&wfds, &wfdset);
317 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
318 c = ::select(fdmax + 1, &rfds, &wfds, NULL, tv);
319 if (cancel) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
322 if (errno == EINTR) {
325 THROW2(SocketException,
"select() [%d]", errno);
331 for (
auto it = rMap.cbegin(); it != rMap.cend(); ++it) {
332 if (FD_ISSET(it->first, &rfds)) {
333 it->second->read =
true;
334 rList.push_front(it->second);
336 if (++f >= c)
return c;
340 for (
auto it = wMap.cbegin(); it != wMap.cend(); ++it) {
341 if (FD_ISSET(it->first, &wfds)) {
342 it->second->write =
true;
343 wList.push_front(it->second);
345 if (++f >= c)
return c;
352 int SocketMux::rwselect(uint64_t usec)
throw (SocketException) {
353 struct timeval tv = sella::util::Time::usectotv(usec);
355 return this->rwselect(&tv);
358 void SocketMux::clear(
void) throw (SocketException) {
372 if ((e = epoll_create(EPOLL_SIZE)) == -1) {
373 THROW2(SocketException,
"epoll_create1()");
377 size_t SocketMux::size(
void)
const {
378 return (rMap.size() + wMap.size() + eMap.size());
381 const SocketMux::shared_flist& SocketMux::getReadList(
void) {
385 const SocketMux::shared_flist& SocketMux::getWriteList(
void) {
389 const SocketMux::shared_flist& SocketMux::getExceptList(
void) {
393 bool SocketMux::insertRead(Socket::shared socket)
throw (SocketException) {
394 fd_set *set = &rfdset;
395 int_shared_map *map = &rMap;
397 return insert(socket, set, map, EPOLLIN | EPOLLET);
400 bool SocketMux::removeRead(Socket::shared socket)
throw (SocketException) {
401 fd_set *set = &rfdset;
402 int_shared_map *map = &rMap;
404 return remove(socket, set, map, EPOLLIN | EPOLLET);
407 bool SocketMux::insertWrite(Socket::shared socket)
throw (SocketException) {
408 fd_set *set = &wfdset;
409 int_shared_map *map = &wMap;
411 return insert(socket, set, map, EPOLLOUT | EPOLLET);
414 bool SocketMux::removeWrite(Socket::shared socket)
throw (SocketException) {
415 fd_set *set = &wfdset;
416 int_shared_map *map = &wMap;
418 return remove(socket, set, map, EPOLLOUT | EPOLLET);
421 bool SocketMux::insertExcept(Socket::shared socket)
throw (SocketException) {
422 fd_set *set = &efdset;
423 int_shared_map *map = &eMap;
425 return insert(socket, set, map, EPOLLERR | EPOLLET);
428 bool SocketMux::removeExcept(Socket::shared socket)
throw (SocketException) {
429 fd_set *set = &efdset;
430 int_shared_map *map = &eMap;
432 return remove(socket, set, map, EPOLLERR | EPOLLET);
435 const SocketMux::shared SocketMux::shared_ptr(ssize_t epollMaxEvents,
bool pthread_cancel)
throw (SocketException) {
436 return std::make_shared<SocketMux>(epollMaxEvents, pthread_cancel);
439 bool SocketMux::insert(Socket::shared socket, fd_set *set, int_shared_map *map, uint32_t events)
throw (SocketException) {
444 THROW(SocketException,
"Passed NULL socket");
447 int s = socket->getFD();
449 if (s < 0 || s > FD_SETSIZE) {
450 THROW(SocketException,
"Socket fd(%d) less than 0 or greater than FD_SETSIZE(%u)", s, FD_SETSIZE);
453 if (!FD_ISSET(s, set)) {
454 struct epoll_event event = {};
456 event.events = events;
457 if (epoll_ctl(e, EPOLL_CTL_ADD, s, &event) != 0) {
458 THROW2(SocketException,
"epoll_ctl()");
462 fdmax = (s > fdmax) ? s : fdmax;
472 bool SocketMux::remove(Socket::shared socket, fd_set *set, int_shared_map *map, uint32_t events)
throw (SocketException) {
477 THROW(SocketException,
"Passed NULL socket");
480 int s = socket->getFD();
482 if (s < 0 || s > FD_SETSIZE) {
483 THROW(SocketException,
"Socket fd(%d) less than 0 or greater than FD_SETSIZE(%u)", s, FD_SETSIZE);
486 if (FD_ISSET(s, set)) {
487 struct epoll_event event = {};
489 event.events = events;
490 if (epoll_ctl(e, EPOLL_CTL_DEL, s, &event) != 0) {
491 THROW2(SocketException,
"epoll_ctl()");
497 for (; fdmax >= 0; fdmax--) {
498 if (FD_ISSET(fdmax, set)) {
513 void SocketMux::clearLists(
void) {