]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/socketengine.cpp
Add support for blocking tag messages with the deaf mode.
[user/henk/code/inspircd.git] / src / socketengine.cpp
index c6c520efcd12501212dabdddca8cd930e528076b..9186f2c8c9ce88b78b0314a6357ccf763c39fcd0 100644 (file)
@@ -1,11 +1,16 @@
 /*
  * InspIRCd -- Internet Relay Chat Daemon
  *
- *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- *   Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
- *   Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc>
- *   Copyright (C) 2007 Burlex <???@???>
+ *   Copyright (C) 2017-2020 Sadie Powell <sadie@witchery.services>
+ *   Copyright (C) 2013-2014 Adam <Adam@anope.org>
+ *   Copyright (C) 2012, 2014-2015 Attila Molnar <attilamolnar@hush.com>
+ *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
+ *   Copyright (C) 2012 ChrisTX <xpipe@hotmail.de>
+ *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ *   Copyright (C) 2008, 2017 Robin Burchell <robin+git@viroteck.net>
+ *   Copyright (C) 2007 burlex <burlex@e03df62e-2008-0410-955e-edbf42e46eb7>
  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ *   Copyright (C) 2006-2008, 2010 Craig Edwards <brain@inspircd.org>
  *
  * This file is part of InspIRCd.  InspIRCd is free software: you can
  * redistribute it and/or modify it under the terms of the GNU General Public
  */
 
 
+#include "exitcodes.h"
 #include "inspircd.h"
 
+#include <iostream>
 
 /** Reference table, contains all current handlers
  **/
@@ -36,7 +43,7 @@ size_t SocketEngine::CurrentSetSize = 0;
  */
 std::set<int> SocketEngine::trials;
 
-int SocketEngine::MAX_DESCRIPTORS;
+size_t SocketEngine::MaxSetSize = 0;
 
 /** Socket engine statistics: count of various events, bandwidth usage
  */
@@ -48,11 +55,50 @@ EventHandler::EventHandler()
        event_mask = 0;
 }
 
+void EventHandler::SwapInternals(EventHandler& other)
+{
+       std::swap(fd, other.fd);
+       std::swap(event_mask, other.event_mask);
+}
+
 void EventHandler::SetFd(int FD)
 {
        this->fd = FD;
 }
 
+void EventHandler::OnEventHandlerWrite()
+{
+}
+
+void EventHandler::OnEventHandlerError(int errornum)
+{
+}
+
+void SocketEngine::InitError()
+{
+       std::cerr << con_red << "FATAL ERROR!" << con_reset << " Socket engine initialization failed. " << strerror(errno) << '.' << std::endl;
+       exit(EXIT_STATUS_SOCKETENGINE);
+}
+
+void SocketEngine::LookupMaxFds()
+{
+#if defined _WIN32
+       MaxSetSize = FD_SETSIZE;
+#else
+       struct rlimit limits;
+       if (!getrlimit(RLIMIT_NOFILE, &limits))
+               MaxSetSize = limits.rlim_cur;
+
+#if defined __APPLE__
+       limits.rlim_cur = limits.rlim_max == RLIM_INFINITY ? OPEN_MAX : limits.rlim_max;
+#else
+       limits.rlim_cur = limits.rlim_max;
+#endif
+       if (!setrlimit(RLIMIT_NOFILE, &limits))
+               MaxSetSize = limits.rlim_cur;
+#endif
+}
+
 void SocketEngine::ChangeEventMask(EventHandler* eh, int change)
 {
        int old_m = eh->event_mask;
@@ -91,9 +137,9 @@ void SocketEngine::DispatchTrialWrites()
                int mask = eh->event_mask;
                eh->event_mask &= ~(FD_ADD_TRIAL_READ | FD_ADD_TRIAL_WRITE);
                if ((mask & (FD_ADD_TRIAL_READ | FD_READ_WILL_BLOCK)) == FD_ADD_TRIAL_READ)
-                       eh->HandleEvent(EVENT_READ, 0);
+                       eh->OnEventHandlerRead();
                if ((mask & (FD_ADD_TRIAL_WRITE | FD_WRITE_WILL_BLOCK)) == FD_ADD_TRIAL_WRITE)
-                       eh->HandleEvent(EVENT_WRITE, 0);
+                       eh->OnEventHandlerWrite();
        }
 }
 
@@ -134,11 +180,7 @@ EventHandler* SocketEngine::GetRef(int fd)
 
 bool SocketEngine::BoundsCheckFd(EventHandler* eh)
 {
-       if (!eh)
-               return false;
-       if (eh->GetFd() < 0)
-               return false;
-       return true;
+       return eh && eh->HasFd();
 }
 
 
@@ -195,38 +237,60 @@ void SocketEngine::SetReuse(int fd)
 int SocketEngine::RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen)
 {
        int nbRecvd = recvfrom(fd->GetFd(), (char*)buf, len, flags, from, fromlen);
-       if (nbRecvd > 0)
-               stats.Update(nbRecvd, 0);
+       stats.UpdateReadCounters(nbRecvd);
        return nbRecvd;
 }
 
 int SocketEngine::Send(EventHandler* fd, const void *buf, size_t len, int flags)
 {
        int nbSent = send(fd->GetFd(), (const char*)buf, len, flags);
-       if (nbSent > 0)
-               stats.Update(0, nbSent);
+       stats.UpdateWriteCounters(nbSent);
        return nbSent;
 }
 
 int SocketEngine::Recv(EventHandler* fd, void *buf, size_t len, int flags)
 {
        int nbRecvd = recv(fd->GetFd(), (char*)buf, len, flags);
-       if (nbRecvd > 0)
-               stats.Update(nbRecvd, 0);
+       stats.UpdateReadCounters(nbRecvd);
        return nbRecvd;
 }
 
-int SocketEngine::SendTo(EventHandler* fd, const void *buf, size_t len, int flags, const sockaddr *to, socklen_t tolen)
+int SocketEngine::SendTo(EventHandler* fd, const void* buf, size_t len, int flags, const irc::sockets::sockaddrs& address)
 {
-       int nbSent = sendto(fd->GetFd(), (const char*)buf, len, flags, to, tolen);
-       if (nbSent > 0)
-               stats.Update(0, nbSent);
+       int nbSent = sendto(fd->GetFd(), (const char*)buf, len, flags, &address.sa, address.sa_size());
+       stats.UpdateWriteCounters(nbSent);
        return nbSent;
 }
 
-int SocketEngine::Connect(EventHandler* fd, const sockaddr *serv_addr, socklen_t addrlen)
+int SocketEngine::WriteV(EventHandler* fd, const IOVector* iovec, int count)
 {
-       int ret = connect(fd->GetFd(), serv_addr, addrlen);
+       int sent = writev(fd->GetFd(), iovec, count);
+       stats.UpdateWriteCounters(sent);
+       return sent;
+}
+
+#ifdef _WIN32
+int SocketEngine::WriteV(EventHandler* fd, const iovec* iovec, int count)
+{
+       // On Windows the fields in iovec are not in the order required by the Winsock API; IOVector has
+       // the fields in the correct order.
+       // Create temporary IOVectors from the iovecs and pass them to the WriteV() method that accepts the
+       // platform's native struct.
+       IOVector wiovec[128];
+       count = std::min(count, static_cast<int>(sizeof(wiovec) / sizeof(IOVector)));
+
+       for (int i = 0; i < count; i++)
+       {
+               wiovec[i].iov_len = iovec[i].iov_len;
+               wiovec[i].iov_base = reinterpret_cast<char*>(iovec[i].iov_base);
+       }
+       return WriteV(fd, wiovec, count);
+}
+#endif
+
+int SocketEngine::Connect(EventHandler* fd, const irc::sockets::sockaddrs& address)
+{
+       int ret = connect(fd->GetFd(), &address.sa, address.sa_size());
 #ifdef _WIN32
        if ((ret == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
                errno = EINPROGRESS;
@@ -254,11 +318,26 @@ int SocketEngine::Shutdown(int fd, int how)
        return shutdown(fd, how);
 }
 
-void SocketEngine::Statistics::Update(size_t len_in, size_t len_out)
+void SocketEngine::Statistics::UpdateReadCounters(int len_in)
+{
+       CheckFlush();
+
+       ReadEvents++;
+       if (len_in > 0)
+               indata += len_in;
+       else if (len_in < 0)
+               ErrorEvents++;
+}
+
+void SocketEngine::Statistics::UpdateWriteCounters(int len_out)
 {
        CheckFlush();
-       indata += len_in;
-       outdata += len_out;
+
+       WriteEvents++;
+       if (len_out > 0)
+               outdata += len_out;
+       else if (len_out < 0)
+               ErrorEvents++;
 }
 
 void SocketEngine::Statistics::CheckFlush() const
@@ -291,7 +370,13 @@ std::string SocketEngine::LastError()
        DWORD dwErrorCode = WSAGetLastError();
        if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szErrorString, _countof(szErrorString), NULL) == 0)
                sprintf_s(szErrorString, _countof(szErrorString), "Error code: %u", dwErrorCode);
-       return szErrorString;
+
+       std::string::size_type p;
+       std::string ret = szErrorString;
+       while ((p = ret.find_last_of("\r\n")) != std::string::npos)
+               ret.erase(p, 1);
+
+       return ret;
 #endif
 }