1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2008 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
18 #include "socketengine.h"
21 /* Private static member data must be initialized in this manner */
22 unsigned int ListenSocketBase::socketcount = 0;
23 sockaddr* ListenSocketBase::sock_us = NULL;
24 sockaddr* ListenSocketBase::client = NULL;
25 sockaddr* ListenSocketBase::raddr = NULL;
27 ListenSocketBase::ListenSocketBase(InspIRCd* Instance, int port, const std::string &addr) : ServerInstance(Instance), desc("plaintext"), bind_addr(addr), bind_port(port)
29 this->SetFd(irc::sockets::OpenTCPSocket(addr.c_str()));
30 if (this->GetFd() > -1)
32 if (!Instance->BindSocket(this->fd,port,addr.c_str()))
35 if ((!*addr.c_str()) || (strchr(addr.c_str(),':')))
36 this->family = AF_INET6;
39 this->family = AF_INET;
40 Instance->SE->AddFd(this);
42 /* Saves needless allocations */
45 /* All instances of ListenSocket share these, so reference count it */
46 ServerInstance->Logs->Log("SOCKET", DEBUG,"Allocate sockaddr structures");
47 sock_us = new sockaddr[2];
48 client = new sockaddr[2];
49 raddr = new sockaddr[2];
54 ListenSocketBase::~ListenSocketBase()
56 if (this->GetFd() > -1)
58 ServerInstance->SE->DelFd(this);
59 ServerInstance->Logs->Log("SOCKET", DEBUG,"Shut down listener on fd %d", this->fd);
60 if (ServerInstance->SE->Shutdown(this, 2) || ServerInstance->SE->Close(this))
61 ServerInstance->Logs->Log("SOCKET", DEBUG,"Failed to cancel listener: %s", strerror(errno));
73 /* Just seperated into another func for tidiness really.. */
74 void ListenSocketBase::AcceptInternal()
76 ServerInstance->Logs->Log("SOCKET",DEBUG,"HandleEvent for Listensoket");
77 socklen_t uslen, length; // length of our port number
81 if (this->family == AF_INET6)
83 uslen = sizeof(sockaddr_in6);
84 length = sizeof(sockaddr_in6);
89 uslen = sizeof(sockaddr_in);
90 length = sizeof(sockaddr_in);
93 incomingSockfd = ServerInstance->SE->Accept(this, (sockaddr*)client, &length);
95 if (incomingSockfd < 0 ||
96 ServerInstance->SE->GetSockName(this, sock_us, &uslen) == -1)
98 ServerInstance->SE->Shutdown(incomingSockfd, 2);
99 ServerInstance->SE->Close(incomingSockfd);
100 ServerInstance->stats->statsRefused++;
105 * this is done as a safety check to keep the file descriptors within range of fd_ref_table.
106 * its a pretty big but for the moment valid assumption:
107 * file descriptors are handed out starting at 0, and are recycled as theyre freed.
108 * therefore if there is ever an fd over 65535, 65536 clients must be connected to the
109 * irc server at once (or the irc server otherwise initiating this many connections, files etc)
110 * which for the time being is a physical impossibility (even the largest networks dont have more
111 * than about 10,000 users on ONE server!)
113 if (incomingSockfd >= ServerInstance->SE->GetMaxFds())
115 ServerInstance->Logs->Log("SOCKET", DEBUG, "Server is full");
116 ServerInstance->SE->Shutdown(incomingSockfd, 2);
117 ServerInstance->SE->Close(incomingSockfd);
118 ServerInstance->stats->statsRefused++;
122 static char buf[MAXBUF];
123 static char target[MAXBUF];
125 *target = *buf = '\0';
128 if (this->family == AF_INET6)
130 inet_ntop(AF_INET6, &((const sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));
131 socklen_t raddrsz = sizeof(sockaddr_in6);
132 if (getsockname(incomingSockfd, (sockaddr*) raddr, &raddrsz) == 0)
133 inet_ntop(AF_INET6, &((const sockaddr_in6*)raddr)->sin6_addr, target, sizeof(target));
135 ServerInstance->Logs->Log("SOCKET", DEBUG, "Can't get peername: %s", strerror(errno));
140 inet_ntop(AF_INET, &((const sockaddr_in*)client)->sin_addr, buf, sizeof(buf));
141 socklen_t raddrsz = sizeof(sockaddr_in);
142 if (getsockname(incomingSockfd, (sockaddr*) raddr, &raddrsz) == 0)
143 inet_ntop(AF_INET, &((const sockaddr_in*)raddr)->sin_addr, target, sizeof(target));
145 ServerInstance->Logs->Log("SOCKET", DEBUG, "Can't get peername: %s", strerror(errno));
148 ServerInstance->SE->NonBlocking(incomingSockfd);
149 ServerInstance->stats->statsAccept++;
150 this->OnAcceptReady(target, incomingSockfd, buf);
153 void ListenSocketBase::HandleEvent(EventType e, int err)
158 ServerInstance->Logs->Log("SOCKET",DEFAULT,"ListenSocket::HandleEvent() received a socket engine error event! well shit! '%s'", strerror(err));
161 ServerInstance->Logs->Log("SOCKET",DEBUG,"*** BUG *** ListenSocket::HandleEvent() got a WRITE event!!!");
164 this->AcceptInternal();
169 void ClientListenSocket::OnAcceptReady(const std::string &ipconnectedto, int nfd, const std::string &incomingip)
171 ServerInstance->Users->AddUser(ServerInstance, nfd, bind_port, false, this->family, client, ipconnectedto);