]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/listensocket.cpp
Attempt to revert r11734
[user/henk/code/inspircd.git] / src / listensocket.cpp
index 961156ae6f74e4b846397d6ab3ef9d4ea33446d2..823cb9ecacdf45565798c3869ce0ede9a8f779ef 100644 (file)
@@ -2,8 +2,8 @@
  *       | Inspire Internet Relay Chat Daemon |
  *       +------------------------------------+
  *
- *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
- * See: http://www.inspircd.org/wiki/index.php/Credits
+ *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
+ * See: http://wiki.inspircd.org/Credits
  *
  * This program is free but copyrighted software; see
  *            the file COPYING for details.
 #include "socket.h"
 #include "socketengine.h"
 
+/* Private static member data must be declared in this manner */
+irc::sockets::sockaddrs ListenSocketBase::client;
+irc::sockets::sockaddrs ListenSocketBase::server;
 
-/* Private static member data must be initialized in this manner */
-unsigned int ListenSocketBase::socketcount = 0;
-sockaddr* ListenSocketBase::sock_us = NULL;
-sockaddr* ListenSocketBase::client = NULL;
-sockaddr* ListenSocketBase::raddr = NULL;
-
-ListenSocketBase::ListenSocketBase(InspIRCd* Instance, int port, const std::string &addr) : ServerInstance(Instance), desc("plaintext"), bind_addr(addr), bind_port(port)
+ListenSocketBase::ListenSocketBase(InspIRCd* Instance, int port, const std::string &addr) : ServerInstance(Instance), desc("plaintext")
 {
-       this->SetFd(irc::sockets::OpenTCPSocket(addr.c_str()));
-       if (this->GetFd() > -1)
+       irc::sockets::sockaddrs bind_to;
+
+       // canonicalize address if it is defined
+       if (!irc::sockets::aptosa(addr.c_str(), port, &bind_to))
        {
-               if (!Instance->BindSocket(this->fd,port,addr.c_str()))
-                       this->fd = -1;
-#ifdef IPV6
-               if ((!*addr.c_str()) || (strchr(addr.c_str(),':')))
-                       this->family = AF_INET6;
-               else
-#endif
-               this->family = AF_INET;
-               Instance->SE->AddFd(this);
+               // malformed address
+               bind_addr = addr;
+               bind_port = port;
+               bind_desc = addr + ":" + ConvToStr(port);
+               this->fd = -1;
        }
-       /* Saves needless allocations */
-       if (socketcount == 0)
+       else
        {
-               /* All instances of ListenSocket share these, so reference count it */
-               ServerInstance->Logs->Log("SOCKET", DEBUG,"Allocate sockaddr structures");
-               sock_us = new sockaddr[2];
-               client = new sockaddr[2];
-               raddr = new sockaddr[2];
+               irc::sockets::satoap(&bind_to, bind_addr, bind_port);
+               bind_desc = irc::sockets::satouser(&bind_to);
+
+               this->fd = irc::sockets::OpenTCPSocket(bind_addr.c_str());
+       }
+
+       if (this->fd > -1)
+       {
+               int rv = Instance->SE->Bind(this->fd, &bind_to.sa, sizeof(bind_to));
+               if (rv >= 0)
+                       rv = Instance->SE->Listen(this->fd, Instance->Config->MaxConn);
+
+               if (rv < 0)
+               {
+                       Instance->SE->Shutdown(this, 2);
+                       Instance->SE->Close(this);
+                       this->fd = -1;
+               }
+               else
+               {
+                       Instance->SE->NonBlocking(this->fd);
+                       Instance->SE->AddFd(this);
+               }
        }
-       socketcount++;
 }
 
 ListenSocketBase::~ListenSocketBase()
@@ -61,45 +72,29 @@ ListenSocketBase::~ListenSocketBase()
                        ServerInstance->Logs->Log("SOCKET", DEBUG,"Failed to cancel listener: %s", strerror(errno));
                this->fd = -1;
        }
-       socketcount--;
-       if (socketcount == 0)
-       {
-               delete[] sock_us;
-               delete[] client;
-               delete[] raddr;
-       }
 }
 
 /* Just seperated into another func for tidiness really.. */
 void ListenSocketBase::AcceptInternal()
 {
        ServerInstance->Logs->Log("SOCKET",DEBUG,"HandleEvent for Listensoket");
-       socklen_t uslen, length;                // length of our port number
        int incomingSockfd;
 
-#ifdef IPV6
-       if (this->family == AF_INET6)
-       {
-               uslen = sizeof(sockaddr_in6);
-               length = sizeof(sockaddr_in6);
-       }
-       else
-#endif
-       {
-               uslen = sizeof(sockaddr_in);
-               length = sizeof(sockaddr_in);
-       }
-
-       incomingSockfd = ServerInstance->SE->Accept(this, (sockaddr*)client, &length);
+       socklen_t length = sizeof(client);
+       incomingSockfd = ServerInstance->SE->Accept(this, &client.sa, &length);
 
-       if (incomingSockfd < 0 ||
-                 ServerInstance->SE->GetSockName(this, sock_us, &uslen) == -1)
+       if (incomingSockfd < 0)
        {
                ServerInstance->SE->Shutdown(incomingSockfd, 2);
                ServerInstance->SE->Close(incomingSockfd);
                ServerInstance->stats->statsRefused++;
                return;
        }
+
+       socklen_t sz = sizeof(server);
+       if (getsockname(incomingSockfd, &server.sa, &sz))
+               ServerInstance->Logs->Log("SOCKET", DEBUG, "Can't get peername: %s", strerror(errno));
+
        /*
         * XXX -
         * this is done as a safety check to keep the file descriptors within range of fd_ref_table.
@@ -119,35 +114,41 @@ void ListenSocketBase::AcceptInternal()
                return;
        }
 
-       static char buf[MAXBUF];
-       static char target[MAXBUF];     
-
-       *target = *buf = '\0';
-
-#ifdef IPV6
-       if (this->family == AF_INET6)
+       if (client.sa.sa_family == AF_INET6)
        {
-               inet_ntop(AF_INET6, &((const sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));
-               socklen_t raddrsz = sizeof(sockaddr_in6);
-               if (getsockname(incomingSockfd, (sockaddr*) raddr, &raddrsz) == 0)
-                       inet_ntop(AF_INET6, &((const sockaddr_in6*)raddr)->sin6_addr, target, sizeof(target));
-               else
-                       ServerInstance->Logs->Log("SOCKET", DEBUG, "Can't get peername: %s", strerror(errno));
-       }
-       else
-#endif
-       {
-               inet_ntop(AF_INET, &((const sockaddr_in*)client)->sin_addr, buf, sizeof(buf));
-               socklen_t raddrsz = sizeof(sockaddr_in);
-               if (getsockname(incomingSockfd, (sockaddr*) raddr, &raddrsz) == 0)
-                       inet_ntop(AF_INET, &((const sockaddr_in*)raddr)->sin_addr, target, sizeof(target));
-               else
-                       ServerInstance->Logs->Log("SOCKET", DEBUG, "Can't get peername: %s", strerror(errno));
+               /*
+                * This case is the be all and end all patch to catch and nuke 4in6
+                * instead of special-casing shit all over the place and wreaking merry
+                * havoc with crap, instead, we just recreate sockaddr and strip ::ffff: prefix
+                * if it's a 4in6 IP.
+                *
+                * This is, of course, much improved over the older way of handling this
+                * (pretend it doesn't exist + hack around it -- yes, both were done!)
+                *
+                * Big, big thanks to danieldg for his work on this.
+                * -- w00t
+                */
+               static const unsigned char prefix4in6[12] = { 0,0,0,0, 0,0,0,0, 0,0,0xFF,0xFF };
+               if (!memcmp(prefix4in6, &client.in6.sin6_addr, 12))
+               {
+                       // recreate as a sockaddr_in using the IPv4 IP
+                       uint16_t sport = client.in6.sin6_port;
+                       uint32_t addr = *reinterpret_cast<uint32_t*>(client.in6.sin6_addr.s6_addr + 12);
+                       client.in4.sin_family = AF_INET;
+                       client.in4.sin_port = sport;
+                       client.in4.sin_addr.s_addr = addr;
+
+                       sport = server.in6.sin6_port;
+                       addr = *reinterpret_cast<uint32_t*>(server.in6.sin6_addr.s6_addr + 12);
+                       server.in4.sin_family = AF_INET;
+                       server.in4.sin_port = sport;
+                       server.in4.sin_addr.s_addr = addr;
+               }
        }
 
        ServerInstance->SE->NonBlocking(incomingSockfd);
        ServerInstance->stats->statsAccept++;
-       this->OnAcceptReady(target, incomingSockfd, buf);
+       this->OnAcceptReady(incomingSockfd);
 }
 
 void ListenSocketBase::HandleEvent(EventType e, int err)
@@ -166,7 +167,7 @@ void ListenSocketBase::HandleEvent(EventType e, int err)
        }
 }
 
-void ClientListenSocket::OnAcceptReady(const std::string &ipconnectedto, int nfd, const std::string &incomingip)
+void ClientListenSocket::OnAcceptReady(int nfd)
 {
-       ServerInstance->Users->AddUser(ServerInstance, nfd, bind_port, false, this->family, client, ipconnectedto);
+       ServerInstance->Users->AddUser(ServerInstance, nfd, this, &client, &server);
 }