anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

socketengine_select.cpp (3176B)

      1 /*
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "services.h"
     13 #include "anope.h"
     14 #include "sockets.h"
     15 #include "socketengine.h"
     16 #include "logger.h"
     17 #include "config.h"
     18 
     19 #ifdef _AIX
     20 # undef FD_ZERO
     21 # define FD_ZERO(p) memset((p), 0, sizeof(*(p)))
     22 #endif /* _AIX */
     23 
     24 static int MaxFD;
     25 static unsigned FDCount;
     26 static fd_set ReadFDs;
     27 static fd_set WriteFDs;
     28 
     29 void SocketEngine::Init()
     30 {
     31 	FD_ZERO(&ReadFDs);
     32 	FD_ZERO(&WriteFDs);
     33 }
     34 
     35 void SocketEngine::Shutdown()
     36 {
     37 	while (!Sockets.empty())
     38 		delete Sockets.begin()->second;
     39 }
     40 
     41 void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
     42 {
     43 	if (set == s->flags[flag])
     44 		return;
     45 
     46 	bool before_registered = s->flags[SF_READABLE] || s->flags[SF_WRITABLE];
     47 
     48 	s->flags[flag] = set;
     49 
     50 	bool now_registered = s->flags[SF_READABLE] || s->flags[SF_WRITABLE];
     51 
     52 	if (!before_registered && now_registered)
     53 	{
     54 		if (s->GetFD() > MaxFD)
     55 			MaxFD = s->GetFD();
     56 		if (s->flags[SF_READABLE])
     57 			FD_SET(s->GetFD(), &ReadFDs);
     58 		if (s->flags[SF_WRITABLE])
     59 			FD_SET(s->GetFD(), &WriteFDs);
     60 		++FDCount;
     61 	}
     62 	else if (before_registered && !now_registered)
     63 	{
     64 		if (s->GetFD() == MaxFD)
     65 			--MaxFD;
     66 		FD_CLR(s->GetFD(), &ReadFDs);
     67 		FD_CLR(s->GetFD(), &WriteFDs);
     68 		--FDCount;
     69 	}
     70 	else if (before_registered && now_registered)
     71 	{
     72 		if (s->flags[SF_READABLE])
     73 			FD_SET(s->GetFD(), &ReadFDs);
     74 		else
     75 			FD_CLR(s->GetFD(), &ReadFDs);
     76 
     77 		if (s->flags[SF_WRITABLE])
     78 			FD_SET(s->GetFD(), &WriteFDs);
     79 		else
     80 			FD_CLR(s->GetFD(), &WriteFDs);
     81 	}
     82 }
     83 
     84 void SocketEngine::Process()
     85 {
     86 	fd_set rfdset = ReadFDs, wfdset = WriteFDs, efdset = ReadFDs;
     87 	timeval tval;
     88 	tval.tv_sec = Config->ReadTimeout;
     89 	tval.tv_usec = 0;
     90 
     91 #ifdef _WIN32
     92 	/* We can use the socket engine to "sleep" services for a period of
     93 	 * time between connections to the uplink, which allows modules,
     94 	 * timers, etc to function properly. Windows, being as useful as it is,
     95 	 * does not allow to select() on 0 sockets and will immediately return error.
     96 	 * Thus:
     97 	 */
     98 	if (FDCount == 0)
     99 	{
    100 		sleep(tval.tv_sec);
    101 		return;
    102 	}
    103 #endif
    104 
    105 	int sresult = select(MaxFD + 1, &rfdset, &wfdset, &efdset, &tval);
    106 	Anope::CurTime = time(NULL);
    107 
    108 	if (sresult == -1)
    109 	{
    110 		Log() << "SockEngine::Process(): error: " << Anope::LastError();
    111 	}
    112 	else if (sresult)
    113 	{
    114 		int processed = 0;
    115 		for (std::map<int, Socket *>::const_iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end && processed != sresult;)
    116 		{
    117 			Socket *s = it->second;
    118 			++it;
    119 
    120 			bool has_read = FD_ISSET(s->GetFD(), &rfdset), has_write = FD_ISSET(s->GetFD(), &wfdset), has_error = FD_ISSET(s->GetFD(), &efdset);
    121 			if (has_read || has_write || has_error)
    122 				++processed;
    123 
    124 			if (has_error)
    125 			{
    126 				s->ProcessError();
    127 				delete s;
    128 				continue;
    129 			}
    130 
    131 			if (!s->Process())
    132 			{
    133 				if (s->flags[SF_DEAD])
    134 					delete s;
    135 				continue;
    136 			}
    137 
    138 			if (has_read && !s->ProcessRead())
    139 				s->flags[SF_DEAD] = true;
    140 
    141 			if (has_write && !s->ProcessWrite())
    142 				s->flags[SF_DEAD] = true;
    143 
    144 			if (s->flags[SF_DEAD])
    145 				delete s;
    146 		}
    147 	}
    148 }