summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2010-07-08 22:19:13 -0400
committerAdam <Adam@anope.org>2010-07-08 22:19:13 -0400
commit1cf4ebb231f2f7770b717a5e176d7bb5cbc66284 (patch)
tree16094a36484e2764c5f541c4324e1d2a6300f61b /src
parent8f8b1e46d670f45bafdc5c888bec3f005cc06c1f (diff)
Added an epoll socket engine
Diffstat (limited to 'src')
-rw-r--r--src/Makefile2
-rw-r--r--src/config.cpp2
-rw-r--r--src/core/m_socketengine_epoll.cpp155
-rw-r--r--src/core/m_socketengine_select.cpp134
-rw-r--r--src/core/os_modlist.cpp22
-rw-r--r--src/init.cpp3
-rw-r--r--src/main.cpp12
-rw-r--r--src/modules/ssl/m_ssl.cpp10
-rw-r--r--src/sockets.cpp549
9 files changed, 598 insertions, 291 deletions
diff --git a/src/Makefile b/src/Makefile
index d4ce6625e..e50218ab3 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -70,7 +70,7 @@ send.o: send.cpp $(INCLUDES)
servers.o: servers.cpp $(INCLUDES)
sessions.o: sessions.cpp $(INCLUDES)
slist.o: slist.cpp $(INCLUDES)
-sockets.o: sockets.cpp $(INCLUDES)
+sockets.o: sockets.cpp $(INCLUDES)
threadengine.o: threadengine.cpp $(INCLUDES)
threadengine_pthread.o: threadengine_pthread.cpp $(INCLUDES)
timers.o: timers.cpp $(INCLUDES)
diff --git a/src/config.cpp b/src/config.cpp
index 93a65f9ba..5785c4452 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -21,6 +21,7 @@ ServerConfig Config;
static ci::string Modules;
static ci::string EncModules;
static ci::string DBModules;
+static ci::string SocketEngineModule;
static ci::string HostCoreModules;
static ci::string MemoCoreModules;
static ci::string BotCoreModules;
@@ -629,6 +630,7 @@ int ServerConfig::Read(bool bail)
{"options", "encryption", "", new ValueContainerCIString(&EncModules), DT_CISTRING | DT_NORELOAD, ValidateNotEmpty},
{"options", "passlen", "32", new ValueContainerUInt(&Config.PassLen), DT_UINTEGER | DT_NORELOAD, NoValidation},
{"options", "database", "", new ValueContainerCIString(&DBModules), DT_CISTRING | DT_NORELOAD, ValidateNotEmpty},
+ {"options", "socketengine", "", new ValueContainerCIString(&Config.SocketEngine), DT_CISTRING | DT_NORELOAD, ValidateNotEmpty},
{"options", "userkey1", "0", new ValueContainerLUInt(&Config.UserKey1), DT_LUINTEGER, NoValidation},
{"options", "userkey2", "0", new ValueContainerLUInt(&Config.UserKey2), DT_LUINTEGER, NoValidation},
{"options", "userkey3", "0", new ValueContainerLUInt(&Config.UserKey3), DT_LUINTEGER, NoValidation},
diff --git a/src/core/m_socketengine_epoll.cpp b/src/core/m_socketengine_epoll.cpp
new file mode 100644
index 000000000..95bc60926
--- /dev/null
+++ b/src/core/m_socketengine_epoll.cpp
@@ -0,0 +1,155 @@
+#include "module.h"
+#include <sys/epoll.h>
+#include <ulimit.h>
+
+class SocketEngineEPoll : public SocketEngineBase
+{
+ private:
+ long max;
+ int EngineHandle;
+ epoll_event *events;
+ unsigned SocketCount;
+
+ public:
+ SocketEngineEPoll()
+ {
+ SocketCount = 0;
+ max = ulimit(4, 0);
+
+ if (max <= 0)
+ {
+ Alog() << "Can't determine maximum number of open sockets";
+ throw ModuleException("Can't determine maximum number of open sockets");
+ }
+
+ EngineHandle = epoll_create(max / 4);
+
+ if (EngineHandle == -1)
+ {
+ Alog() << "Could not initialize epoll socket engine: " << strerror(errno);
+ throw ModuleException("Could not initialize epoll socket engine: " + std::string(strerror(errno)));
+ }
+
+ events = new epoll_event[max];
+ memset(events, 0, sizeof(epoll_event) * max);
+ }
+
+ ~SocketEngineEPoll()
+ {
+ delete [] events;
+ }
+
+ void AddSocket(Socket *s)
+ {
+ epoll_event ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ ev.events = EPOLLIN | EPOLLOUT;
+ ev.data.fd = s->GetSock();
+
+ if (epoll_ctl(EngineHandle, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1)
+ {
+ Alog() << "Unable to add fd " << ev.data.fd << " to socketengine epoll: " << strerror(errno);
+ return;
+ }
+
+ Sockets.insert(std::make_pair(ev.data.fd, s));
+
+ ++SocketCount;
+ }
+
+ void DelSocket(Socket *s)
+ {
+ epoll_event ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ ev.data.fd = s->GetSock();
+
+ if (epoll_ctl(EngineHandle, EPOLL_CTL_DEL, ev.data.fd, &ev) == -1)
+ {
+ Alog() << "Unable to delete fd " << ev.data.fd << " from socketengine epoll: " << strerror(errno);
+ return;
+ }
+
+ Sockets.erase(ev.data.fd);
+
+ --SocketCount;
+ }
+
+ void Process()
+ {
+ int total = epoll_wait(EngineHandle, events, max - 1, (Config.ReadTimeout * 1000));
+
+ if (total == -1)
+ {
+ Alog() << "SockEngine::Process(): error " << strerror(errno);
+ return;
+ }
+
+ for (int i = 0; i < total; ++i)
+ {
+ epoll_event *ev = &events[i];
+ Socket *s = Sockets[ev->data.fd];
+
+ if (ev->events & (EPOLLHUP | EPOLLERR))
+ {
+ s->ProcessError();
+ s->SetFlag(SF_DEAD);
+ continue;
+ }
+
+ if (ev->events & EPOLLIN)
+ {
+ if (!s->ProcessRead())
+ {
+ s->SetFlag(SF_DEAD);
+ }
+ }
+
+ if (ev->events & EPOLLOUT)
+ {
+ if (!s->ProcessWrite())
+ {
+ s->SetFlag(SF_DEAD);
+ }
+ }
+ }
+
+ for (std::map<int, Socket *>::iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end;)
+ {
+ Socket *s = it->second;
+ ++it;
+
+ if (s->HasFlag(SF_DEAD))
+ {
+ delete s;
+ }
+ }
+ }
+};
+
+class ModuleSocketEngineEPoll : public Module
+{
+ SocketEngineEPoll *engine;
+
+ public:
+ ModuleSocketEngineEPoll(const std::string &modname, const std::string &creator) : Module(modname, creator)
+ {
+ this->SetPermanent(true);
+ this->SetType(SOCKETENGINE);
+
+ engine = new SocketEngineEPoll();
+ SocketEngine = engine;
+ }
+
+ ~ModuleSocketEngineEPoll()
+ {
+ delete engine;
+ SocketEngine = NULL;
+ }
+};
+
+MODULE_INIT(ModuleSocketEngineEPoll)
+
diff --git a/src/core/m_socketengine_select.cpp b/src/core/m_socketengine_select.cpp
new file mode 100644
index 000000000..c7346f87c
--- /dev/null
+++ b/src/core/m_socketengine_select.cpp
@@ -0,0 +1,134 @@
+#include "module.h"
+
+class SocketEngineSelect : public SocketEngineBase
+{
+ private:
+ /* Max Read FD */
+ int MaxFD;
+ /* Read FDs */
+ fd_set ReadFDs;
+ /* Write FDs */
+ fd_set WriteFDs;
+
+ public:
+ SocketEngineSelect()
+ {
+ MaxFD = 0;
+ FD_ZERO(&ReadFDs);
+ FD_ZERO(&WriteFDs);
+ }
+
+ ~SocketEngineSelect()
+ {
+ FD_ZERO(&ReadFDs);
+ FD_ZERO(&WriteFDs);
+ }
+
+ void AddSocket(Socket *s)
+ {
+ if (s->GetSock() > MaxFD)
+ MaxFD = s->GetSock();
+ FD_SET(s->GetSock(), &ReadFDs);
+ Sockets.insert(std::make_pair(s->GetSock(), s));
+ }
+
+ void DelSocket(Socket *s)
+ {
+ if (s->GetSock() == MaxFD)
+ --MaxFD;
+ FD_CLR(s->GetSock(), &ReadFDs);
+ FD_CLR(s->GetSock(), &WriteFDs);
+ Sockets.erase(s->GetSock());
+ }
+
+ void MarkWriteable(Socket *s)
+ {
+ FD_SET(s->GetSock(), &WriteFDs);
+ }
+
+ void ClearWriteable(Socket *s)
+ {
+ FD_CLR(s->GetSock(), &WriteFDs);
+ }
+
+ void Process()
+ {
+ fd_set rfdset = ReadFDs, wfdset = WriteFDs, efdset = ReadFDs;
+ timeval tval;
+ tval.tv_sec = Config.ReadTimeout;
+ tval.tv_usec = 0;
+
+ int sresult = select(MaxFD + 1, &rfdset, &wfdset, &efdset, &tval);
+
+ if (sresult == -1)
+ {
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+ Alog() << "SockEngine::Process(): error" << strerror(errno);
+ }
+ else if (sresult)
+ {
+ for (std::map<int, Socket *>::const_iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end; ++it)
+ {
+ Socket *s = it->second;
+
+ if (FD_ISSET(s->GetSock(), &efdset))
+ {
+ s->ProcessError();
+ s->SetFlag(SF_DEAD);
+ continue;
+ }
+ if (FD_ISSET(s->GetSock(), &rfdset))
+ {
+ if (!s->ProcessRead())
+ {
+ s->SetFlag(SF_DEAD);
+ }
+ }
+ if (FD_ISSET(s->GetSock(), &wfdset))
+ {
+ if (!s->ProcessWrite())
+ {
+ s->SetFlag(SF_DEAD);
+ }
+ }
+ }
+
+ for (std::map<int, Socket *>::iterator it = Sockets.begin(), it_end = Sockets.end(); it != it_end;)
+ {
+ Socket *s = it->second;
+ ++it;
+
+ if (s->HasFlag(SF_DEAD))
+ {
+ delete s;
+ }
+ }
+ }
+ }
+};
+
+class ModuleSocketEngineSelect : public Module
+{
+ SocketEngineSelect *engine;
+
+ public:
+ ModuleSocketEngineSelect(const std::string &modname, const std::string &creator) : Module(modname, creator)
+ {
+ this->SetPermanent(true);
+ this->SetType(SOCKETENGINE);
+
+ engine = new SocketEngineSelect();
+ SocketEngine = engine;
+ }
+
+ ~ModuleSocketEngineSelect()
+ {
+ delete engine;
+ SocketEngine = NULL;
+ }
+};
+
+MODULE_INIT(ModuleSocketEngineSelect)
+
diff --git a/src/core/os_modlist.cpp b/src/core/os_modlist.cpp
index c719b734d..8764188da 100644
--- a/src/core/os_modlist.cpp
+++ b/src/core/os_modlist.cpp
@@ -30,6 +30,7 @@ class CommandOSModList : public Command
int showSupported = 1;
int showQA = 1;
int showDB = 1;
+ int showSocketEngine = 1;
ci::string param = params.size() ? params[0] : "";
@@ -40,6 +41,7 @@ class CommandOSModList : public Command
char supported[] = "Supported";
char qa[] = "QATested";
char db[] = "Database";
+ char socketengine[] = "SocketEngine";
if (!param.empty())
{
@@ -52,6 +54,7 @@ class CommandOSModList : public Command
showSupported = 0;
showQA = 0;
showDB = 0;
+ showSocketEngine = 0;
}
else if (param == third)
{
@@ -62,6 +65,7 @@ class CommandOSModList : public Command
showProto = 0;
showEnc = 0;
showDB = 0;
+ showSocketEngine = 0;
}
else if (param == proto)
{
@@ -72,6 +76,7 @@ class CommandOSModList : public Command
showSupported = 0;
showQA = 0;
showDB = 0;
+ showSocketEngine = 0;
}
else if (param == supported)
{
@@ -82,6 +87,7 @@ class CommandOSModList : public Command
showEnc = 0;
showQA = 0;
showDB = 0;
+ showSocketEngine = 0;
}
else if (param == qa)
{
@@ -92,6 +98,7 @@ class CommandOSModList : public Command
showEnc = 0;
showQA = 1;
showDB = 0;
+ showSocketEngine = 0;
}
else if (param == enc)
{
@@ -102,6 +109,7 @@ class CommandOSModList : public Command
showEnc = 1;
showQA = 0;
showDB = 0;
+ showSocketEngine = 0;
}
else if (param == db)
{
@@ -112,6 +120,12 @@ class CommandOSModList : public Command
showEnc = 0;
showQA = 0;
showDB = 1;
+ showSocketEngine = 0;
+ }
+ else if (param == socketengine)
+ {
+ showCore = showThird = showProto = showSupported = showEnc = showQA = showDB = 0;
+ showSocketEngine = 1;
}
}
@@ -171,6 +185,14 @@ class CommandOSModList : public Command
notice_lang(Config.s_OperServ, u, OPER_MODULE_LIST, m->name.c_str(), m->version.c_str(), db);
++count;
}
+ break;
+ case SOCKETENGINE:
+ if (showSocketEngine)
+ {
+ notice_lang(Config.s_OperServ, u, OPER_MODULE_LIST, m->name.c_str(), m->version.c_str(), socketengine);
+ ++count;
+ }
+ break;
}
}
if (!count)
diff --git a/src/init.cpp b/src/init.cpp
index 07597c829..b0f019ad3 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -352,6 +352,9 @@ int init_primary(int ac, char **av)
/* Add Database Modules */
ModuleManager::LoadModuleList(Config.DBModuleList);
+ /* Load the socket engine */
+ ModuleManager::LoadModule(Config.SocketEngine, NULL);
+
return 0;
}
diff --git a/src/main.cpp b/src/main.cpp
index 7634a0e15..dccfcc15f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -109,16 +109,18 @@ class UpdateTimer : public Timer
Socket *UplinkSock = NULL;
-class UplinkSocket : public Socket
+class UplinkSocket : public ClientSocket
{
public:
- UplinkSocket(const std::string &nTargetHost, int nPort, const std::string &nBindHost = "", bool nIPv6 = false) : Socket(nTargetHost, nPort, nBindHost, nIPv6)
+ UplinkSocket(const std::string &nTargetHost, int nPort, const std::string &nBindHost = "", bool nIPv6 = false) : ClientSocket(nTargetHost, nPort, nBindHost, nIPv6)
{
UplinkSock = this;
}
~UplinkSocket()
{
+ /* Process the last bits of data before disconnecting */
+ SocketEngine->Process();
UplinkSock = NULL;
}
@@ -189,8 +191,6 @@ void do_restart_services()
UserListByUID.erase(it->second->GetUID().c_str());
}
ircdproto->SendSquit(Config.ServerName, quitmsg);
- /* Process to send the last bits of information before disconnecting */
- socketEngine.Process();
delete UplinkSock;
close_log();
/* First don't unload protocol module, then do so */
@@ -239,8 +239,6 @@ static void services_shutdown()
while (!UserListByNick.empty())
delete UserListByNick.begin()->second;
}
- /* Process to send the last bits of information before disconnecting */
- socketEngine.Process();
delete UplinkSock;
FOREACH_MOD(I_OnShutdown, OnShutdown());
/* First don't unload protocol module, then do so */
@@ -538,7 +536,7 @@ int main(int ac, char **av, char **envp)
ModeManager::ProcessModes();
/* Process the socket engine */
- socketEngine.Process();
+ SocketEngine->Process();
}
if (quitting)
diff --git a/src/modules/ssl/m_ssl.cpp b/src/modules/ssl/m_ssl.cpp
index 5bc9870da..0771e6d4c 100644
--- a/src/modules/ssl/m_ssl.cpp
+++ b/src/modules/ssl/m_ssl.cpp
@@ -14,22 +14,22 @@
static SSL_CTX *ctx;
-class SSLSocket : public Socket
+class SSLSocket : public ClientSocket
{
private:
SSL *sslsock;
- int RecvInternal(char *buf, size_t sz) const
+ const int RecvInternal(char *buf, size_t sz) const
{
return SSL_read(sslsock, buf, sz);
}
- int SendInternal(const std::string &buf) const
+ const int SendInternal(const std::string &buf) const
{
return SSL_write(sslsock, buf.c_str(), buf.size());
}
public:
- SSLSocket(const std::string &nTargetHost, int nPort, const std::string &nBindHost = "", bool nIPv6 = false) : Socket(nTargetHost, nPort, nBindHost, nIPv6)
+ SSLSocket(const std::string &nTargetHost, int nPort, const std::string &nBindHost = "", bool nIPv6 = false) : ClientSocket(nTargetHost, nPort, nBindHost, nIPv6)
{
sslsock = SSL_new(ctx);
@@ -37,7 +37,7 @@ class SSLSocket : public Socket
throw CoreException("Unable to initialize SSL socket");
SSL_set_connect_state(sslsock);
- SSL_set_fd(sslsock, Sock);
+ SSL_set_fd(sslsock, sock);
SSL_connect(sslsock);
UplinkSock = this;
diff --git a/src/sockets.cpp b/src/sockets.cpp
index db51d7b03..15592c7d6 100644
--- a/src/sockets.cpp
+++ b/src/sockets.cpp
@@ -1,11 +1,11 @@
#include "services.h"
-SocketEngine socketEngine;
+SocketEngineBase *SocketEngine;
int32 TotalRead = 0;
int32 TotalWritten = 0;
/** Trims all the \r and \ns from the begining and end of a string
- * @return A string without trailing \r and \ns
+ * @param buffer The buffer to trim
*/
static void TrimBuf(std::string &buffer)
{
@@ -15,148 +15,54 @@ static void TrimBuf(std::string &buffer)
buffer.erase(buffer.length() - 1);
}
-/** Default constructor
- * @param nTargetHost Hostname to connect to
- * @param nPort Port to connect to
- * @param nBindHos Host to bind to when connecting
- * @param nIPv6 true to use IPv6
+/** Constructor
+ * @param nsock The socket
+ * @param nIPv6 IPv6?
*/
-Socket::Socket(const std::string &nTargetHost, int nPort, const std::string &nBindHost, bool nIPv6) : TargetHost(nTargetHost), Port(nPort), BindHost(nBindHost), IPv6(nIPv6)
+Socket::Socket(int nsock, bool nIPv6)
{
- if (!IPv6 && (TargetHost.find(':') != std::string::npos || BindHost.find(':') != std::string::npos))
- IPv6 = true;
-
- Sock = socket(IPv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
-
- addrinfo hints;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = 0;
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_family = IPv6 ? AF_INET6 : AF_INET;
-
- if (!BindHost.empty())
- {
- addrinfo *bindar;
- sockaddr_in bindaddr;
- sockaddr_in6 bindaddr6;
-
- int Bound = -1;
- if (!getaddrinfo(BindHost.c_str(), NULL, &hints, &bindar))
- {
- if (IPv6)
- memcpy(&bindaddr6, bindar->ai_addr, bindar->ai_addrlen);
- else
- memcpy(&bindaddr, bindar->ai_addr, bindar->ai_addrlen);
-
- freeaddrinfo(bindar);
-
- Bound = bind(Sock, reinterpret_cast<sockaddr *>(&bindaddr), sizeof(bindaddr));
- }
- if (Bound < 0)
- {
- if (IPv6)
- {
- bindaddr6.sin6_family = AF_INET6;
-
- if (inet_pton(AF_INET6, BindHost.c_str(), &bindaddr6.sin6_addr) < 1)
- throw SocketException("Invalid bind host");
-
- if (bind(Sock, reinterpret_cast<sockaddr *>(&bindaddr6), sizeof(bindaddr6)) == -1)
- throw SocketException("Unable to bind to address");
- }
- else
- {
- bindaddr.sin_family = AF_INET;
-
- if (inet_pton(bindaddr.sin_family, BindHost.c_str(), &bindaddr.sin_addr) < 1)
- throw SocketException("Invalid bind host");
-
- if (bind(Sock, reinterpret_cast<sockaddr *>(&bindaddr), sizeof(bindaddr)) == -1)
- throw SocketException("Unable to bind to address");
- }
- }
- }
-
- addrinfo *conar;
- sockaddr_in conaddr;
- sockaddr_in6 conaddr6;
- if (!getaddrinfo(TargetHost.c_str(), NULL, &hints, &conar))
- {
- if (IPv6)
- memcpy(&conaddr6, conar->ai_addr, conar->ai_addrlen);
- else
- memcpy(&conaddr, conar->ai_addr, conar->ai_addrlen);
-
- freeaddrinfo(conar);
- }
- else
- {
- if (IPv6)
- {
- if (inet_pton(AF_INET6, TargetHost.c_str(), &conaddr6.sin6_addr) < 1)
- throw SocketException("Invalid server address");
- }
- else
- {
- if (inet_pton(AF_INET, TargetHost.c_str(), &conaddr.sin_addr) < 1)
- throw SocketException("Invalid server address");
- }
- }
-
- if (IPv6)
- {
- conaddr6.sin6_family = AF_INET6;
- conaddr6.sin6_port = htons(Port);
-
- if (connect(Sock, reinterpret_cast<sockaddr *>(&conaddr6), sizeof(conaddr6)) < 0)
- throw SocketException("Error connecting to server");
- }
+ Type = SOCKTYPE_CLIENT;
+ IPv6 = nIPv6;
+ if (nsock == 0)
+ sock = socket(IPv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
else
- {
- conaddr.sin_family = AF_INET;
- conaddr.sin_port = htons(Port);
-
- if (connect(Sock, reinterpret_cast<sockaddr *>(&conaddr), sizeof(conaddr)) < 0)
- throw SocketException("Error connecting to server");
- }
-
- socketEngine.AddSocket(this);
+ sock = nsock;
+ SocketEngine->AddSocket(this);
}
/** Default destructor
- */
+*/
Socket::~Socket()
{
- CloseSocket(Sock);
-
- socketEngine.DelSocket(this);
+ SocketEngine->DelSocket(this);
+ CloseSocket(sock);
}
-/** Read from the socket
- * @param buf Buffer to read to
+/** Really recieve something from the buffer
+ * @param buf The buf to read to
* @param sz How much to read
* @return Number of bytes recieved
*/
-int Socket::RecvInternal(char *buf, size_t sz) const
+const int Socket::RecvInternal(char *buf, size_t sz) const
{
return recv(GetSock(), buf, sz, 0);
}
-/** Write to the socket
+/** Really write something to the socket
* @param buf What to write
- * @return Number of bytes sent, -1 on error
+ * @return Number of bytes written
*/
-int Socket::SendInternal(const std::string &buf) const
+const int Socket::SendInternal(const std::string &buf) const
{
return send(GetSock(), buf.c_str(), buf.length(), 0);
}
/** Get the socket FD for this socket
- * @return The fd
+ * @return the fd
*/
int Socket::GetSock() const
{
- return Sock;
+ return sock;
}
/** Check if this socket is IPv6
@@ -167,21 +73,36 @@ bool Socket::IsIPv6() const
return IPv6;
}
-/** Called when there is something to be read from thie socket
- * @return true on success, false to kill this socket
+/** Get the length of the read buffer
+ * @return The length of the read buffer
+ */
+size_t Socket::ReadBufferLen() const
+{
+ return RecvLen;
+}
+
+/** Get the length of the write buffer
+ * @return The length of the write buffer
+ */
+size_t Socket::WriteBufferLen() const
+{
+ return WriteBuffer.length();
+}
+
+/** Called when there is something to be recieved for this socket
+ * @return true on success, false to drop this socket
*/
bool Socket::ProcessRead()
{
- char buffer[NET_BUFSIZE];
- memset(&buffer, 0, sizeof(buffer));
+ char tbuffer[NET_BUFSIZE];
+ memset(&tbuffer, '\0', sizeof(tbuffer));
- RecvLen = RecvInternal(buffer, sizeof(buffer) - 1);
+ RecvLen = RecvInternal(tbuffer, sizeof(tbuffer) - 1);
if (RecvLen <= 0)
return false;
- TotalRead += RecvLen;
std::string sbuffer = extrabuf;
- sbuffer.append(buffer);
+ sbuffer.append(tbuffer);
extrabuf.clear();
size_t lastnewline = sbuffer.find_last_of('\n');
if (lastnewline < sbuffer.size() - 1)
@@ -192,239 +113,311 @@ bool Socket::ProcessRead()
}
sepstream stream(sbuffer, '\n');
- std::string buf;
- while (stream.GetToken(buf))
+ std::string tbuf;
+ while (stream.GetToken(tbuf))
{
- TrimBuf(buf);
+ TrimBuf(tbuf);
- if (!buf.empty())
- if (!Read(buf))
+ if (!tbuf.empty())
+ if (!Read(tbuf))
return false;
}
return true;
}
-/** Called when this socket becomes writeable
+/** Called when there is something to be written to this socket
* @return true on success, false to drop this socket
*/
bool Socket::ProcessWrite()
{
- int Written = SendInternal(WriteBuffer);
- if (Written == -1)
+ if (WriteBuffer.empty())
+ {
+ return true;
+ }
+ if (SendInternal(WriteBuffer) == -1)
+ {
return false;
- TotalWritten += Written;
-
+ }
WriteBuffer.clear();
+ SocketEngine->ClearWriteable(this);
+
return true;
}
-/** Called when there is an error on this socket
+/** Called when there is an error for this socket
+ * @return true on success, false to drop this socket
*/
void Socket::ProcessError()
{
}
-/** Called with a message recieved from the socket
- * @param buf The message
- * @return true on success, false to kill this socket
+/** Called with a line recieved from the socket
+ * @param buf The line
+ * @return true to continue reading, false to drop the socket
*/
bool Socket::Read(const std::string &buf)
{
- return true;
+ return false;
}
/** Write to the socket
- * @param message The message to write
+ * @param message The message
*/
void Socket::Write(const char *message, ...)
{
- char buf[BUFSIZE];
va_list vi;
+ char tbuffer[BUFSIZE];
+ std::string sbuf;
+
+ if (!message)
+ return;
+
va_start(vi, message);
- vsnprintf(buf, sizeof(buf), message, vi);
+ vsnprintf(tbuffer, sizeof(tbuffer), message, vi);
va_end(vi);
- std::string sbuf = buf;
+ sbuf = tbuffer;
Write(sbuf);
}
/** Write to the socket
- * @param message The message to write
+ * @param message The message
*/
-void Socket::Write(std::string &message)
+void Socket::Write(const std::string &message)
{
WriteBuffer.append(message + "\r\n");
- socketEngine.MarkWriteable(this);
+ SocketEngine->MarkWriteable(this);
}
-/** Get the length of the read buffer
- * @return The length of the read buffer
+/** Constructor
+ * @param nLS The listen socket this connection came from
+ * @param nu The user using this socket
+ * @param nsock The socket
+ * @param nIPv6 IPv6
*/
-size_t Socket::ReadBufferLen() const
+ClientSocket::ClientSocket(const std::string &nTargetHost, int nPort, const std::string &nBindHost, bool nIPv6) : Socket(0, nIPv6), TargetHost(nTargetHost), Port(nPort), BindHost(nBindHost)
{
- return RecvLen;
-}
+ if (!IPv6 && (TargetHost.find(':') != std::string::npos || BindHost.find(':') != std::string::npos))
+ IPv6 = true;
+
+ addrinfo hints;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_family = IPv6 ? AF_INET6 : AF_INET;
-/** Get the length of the write buffer
- * @return The length of the write buffer
- */
-size_t Socket::WriteBufferLen() const
-{
- return WriteBuffer.size();
-}
+ if (!BindHost.empty())
+ {
+ addrinfo *bindar;
+ sockaddr_in bindaddr;
+ sockaddr_in6 bindaddr6;
-/** Constructor
- */
-SocketEngine::SocketEngine()
-{
- FD_ZERO(&ReadFDs);
- FD_ZERO(&WriteFDs);
- MaxFD = 0;
-
-#ifdef _WIN32
- WSADATA wsa;
- if (WSAStartup(MAKEWORD(2, 0), &wsa))
- Alog() << "Failed to initialize WinSock library";
-#endif
-}
+ if (getaddrinfo(BindHost.c_str(), NULL, &hints, &bindar) == 0)
+ {
+ if (IPv6)
+ memcpy(&bindaddr6, bindar->ai_addr, bindar->ai_addrlen);
+ else
+ memcpy(&bindaddr, bindar->ai_addr, bindar->ai_addrlen);
-/** Destructor
- */
-SocketEngine::~SocketEngine()
-{
-#ifdef _WIN32
- WSACleanup();
-#endif
-}
+ freeaddrinfo(bindar);
+ }
+ else
+ {
+ if (IPv6)
+ {
+ bindaddr6.sin6_family = AF_INET6;
-/** Add a socket to the socket engine
- * @param s The socket
- */
-void SocketEngine::AddSocket(Socket *s)
-{
- if (s->GetSock() > MaxFD)
- MaxFD = s->GetSock();
- FD_SET(s->GetSock(), &ReadFDs);
- Sockets.insert(s);
-}
+ if (inet_pton(AF_INET6, BindHost.c_str(), &bindaddr6.sin6_addr) < 1)
+ throw SocketException("Invalid bind host: " + std::string(strerror(errno)));
+ }
+ else
+ {
+ bindaddr.sin_family = AF_INET;
-/** Delete a socket from the socket engine
- * @param s The socket
- */
-void SocketEngine::DelSocket(Socket *s)
-{
- if (s->GetSock() == MaxFD)
- --MaxFD;
- FD_CLR(s->GetSock(), &ReadFDs);
- FD_CLR(s->GetSock(), &WriteFDs);
- Sockets.erase(s);
+ if (inet_pton(AF_INET, BindHost.c_str(), &bindaddr.sin_addr) < 1)
+ throw SocketException("Invalid bind host: " + std::string(strerror(errno)));
+ }
+ }
+
+ if (IPv6)
+ {
+ if (bind(sock, reinterpret_cast<sockaddr *>(&bindaddr6), sizeof(bindaddr6)) == -1)
+ throw SocketException("Unable to bind to address: " + std::string(strerror(errno)));
+ }
+ else
+ {
+ if (bind(sock, reinterpret_cast<sockaddr *>(&bindaddr), sizeof(bindaddr)) == -1)
+ throw SocketException("Unable to bind to address: " + std::string(strerror(errno)));
+ }
+ }
+
+ addrinfo *conar;
+ sockaddr_in6 addr6;
+ sockaddr_in addr;
+
+ if (getaddrinfo(TargetHost.c_str(), NULL, &hints, &conar) == 0)
+ {
+ if (IPv6)
+ memcpy(&addr6, conar->ai_addr, conar->ai_addrlen);
+ else
+ memcpy(&addr, conar->ai_addr, conar->ai_addrlen);
+
+ freeaddrinfo(conar);
+ }
+ else
+ {
+ if (IPv6)
+ {
+ if (inet_pton(AF_INET6, TargetHost.c_str(), &addr6.sin6_addr) < 1)
+ throw SocketException("Invalid server host: " + std::string(strerror(errno)));
+ }
+ else
+ {
+ if (inet_pton(AF_INET, TargetHost.c_str(), &addr.sin_addr) < 1)
+ throw SocketException("Invalid server host: " + std::string(strerror(errno)));
+ }
+ }
+
+ if (IPv6)
+ {
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = htons(nPort);
+
+ if (connect(sock, reinterpret_cast<sockaddr *>(&addr6), sizeof(addr6)) == -1)
+ {
+ throw SocketException("Error connecting to server: " + std::string(strerror(errno)));
+ }
+ }
+ else
+ {
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(nPort);
+
+ if (connect(sock, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) == -1)
+ {
+ throw SocketException("Error connecting to server: " + std::string(strerror(errno)));
+ }
+ }
}
-/** Mark a socket as wanting to be written to
- * @param s The socket
+/** Default destructor
*/
-void SocketEngine::MarkWriteable(Socket *s)
+ClientSocket::~ClientSocket()
{
- FD_SET(s->GetSock(), &WriteFDs);
}
-/** Unmark a socket as writeable
- * @param s The socket
+/** Called with a line recieved from the socket
+ * @param buf The line
+ * @return true to continue reading, false to drop the socket
*/
-void SocketEngine::ClearWriteable(Socket *s)
+bool ClientSocket::Read(const std::string &buf)
{
- FD_CLR(s->GetSock(), &WriteFDs);
+ return true;
}
-/** Called to iterate through each socket and check for activity
+/** Constructor
+ * @param bind The IP to bind to
+ * @param port The port to listen on
*/
-void SocketEngine::Process()
+ListenSocket::ListenSocket(const std::string &bindip, int port) : Socket(0, (bindip.find(':') != std::string::npos ? true : false))
{
- fd_set rfdset = ReadFDs, wfdset = WriteFDs, efdset = ReadFDs;
- timeval tval;
+ Type = SOCKTYPE_LISTEN;
+ BindIP = bindip;
+ Port = port;
- tval.tv_sec = Config.ReadTimeout;
- tval.tv_usec = 0;
+ sockaddr_in sock_addr;
+ sockaddr_in6 sock_addr6;
+
+ if (IPv6)
+ {
+ sock_addr6.sin6_family = AF_INET6;
+ sock_addr6.sin6_port = htons(port);
+
+ if (inet_pton(AF_INET6, bindip.c_str(), &sock_addr6.sin6_addr) < 1)
+ {
+ throw SocketException("Invalid bind host: " + std::string(strerror(errno)));
+ }
+ }
+ else
+ {
+ sock_addr.sin_family = AF_INET;
+ sock_addr.sin_port = htons(port);
- int sresult = select(MaxFD + 1, &rfdset, &wfdset, &efdset, &tval);
+ if (inet_pton(AF_INET, bindip.c_str(), &sock_addr.sin_addr) < 1)
+ {
+ throw SocketException("Invalid bind host: " + std::string(strerror(errno)));
+ }
+ }
- if (sresult == -1)
- Alog() << "SocketEngine::Process error, " << GetError();
- else if (sresult)
+ if (IPv6)
{
- for (std::set<Socket *>::iterator it = Sockets.begin(); it != Sockets.end(); ++it)
+ if (bind(sock, reinterpret_cast<sockaddr *>(&sock_addr6), sizeof(sock_addr6)) == -1)
{
- Socket *s = *it;
-
- if (FD_ISSET(s->GetSock(), &efdset))
- {
- s->ProcessError();
- OldSockets.insert(s);
- continue;
- }
- if (FD_ISSET(s->GetSock(), &rfdset))
- {
- if (!s->ProcessRead())
- OldSockets.insert(s);
- }
- if (FD_ISSET(s->GetSock(), &wfdset))
- {
- ClearWriteable(s);
- if (!s->ProcessWrite())
- OldSockets.insert(s);
- }
+ throw SocketException("Unable to bind to address: " + std::string(strerror(errno)));
+ }
+ }
+ el