]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/inspircd.cpp
A few cpu usage tweaks
[user/henk/code/inspircd.git] / src / inspircd.cpp
index fa7171248e97d658cd13f7393aa12e7f323ce1ef..ff1a9e9da09b51a7c7ce8a0b0ba67a62c882a127 100644 (file)
@@ -181,6 +181,8 @@ typedef std::deque<command_t> command_table;
 // by an integer, meaning there is no need for a scan/search operation.
 userrec* fd_ref_table[65536];
 
+int statsAccept = 0, statsRefused = 0, statsUnknown = 0, statsCollisions = 0, statsDns = 0, statsDnsGood = 0, statsDnsBad = 0, statsConnects = 0, statsSent= 0, statsRecv = 0;
+
 serverrec* me[32];
 
 FILE *log_file;
@@ -216,6 +218,8 @@ std::stringstream config_f(stringstream::in | stringstream::out);
 
 std::vector<userrec*> all_opers;
 
+static char already_sent[65536];
+
 void AddOper(userrec* user)
 {
        log(DEBUG,"Oper added to optimization list");
@@ -590,14 +594,15 @@ void Write(int sock,char *text, ...)
        if (sock != -1)
        {
                int MOD_RESULT = 0;
-               FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 514 ? 514 : bytes));
+               FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 512 ? 512 : bytes));
                if (!MOD_RESULT)
-                       write(sock,tb,bytes > 514 ? 514 : bytes);
+                       write(sock,tb,bytes > 512 ? 512 : bytes);
                if (fd_ref_table[sock])
                {
-                       fd_ref_table[sock]->bytes_out += (bytes > 514 ? 514 : bytes);
+                       fd_ref_table[sock]->bytes_out += (bytes > 512 ? 512 : bytes);
                        fd_ref_table[sock]->cmds_out++;
                }
+               statsSent += (bytes > 512 ? 512 : bytes);
        }
 }
 
@@ -623,14 +628,15 @@ void WriteServ(int sock, char* text, ...)
        if (sock != -1)
        {
                 int MOD_RESULT = 0;
-                FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 514 ? 514 : bytes));
+                FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 512 ? 512 : bytes));
                 if (!MOD_RESULT)
-                        write(sock,tb,bytes > 514 ? 514 : bytes);
+                        write(sock,tb,bytes > 512 ? 512 : bytes);
                 if (fd_ref_table[sock])
                 {
-                        fd_ref_table[sock]->bytes_out += (bytes > 514 ? 514 : bytes);
+                        fd_ref_table[sock]->bytes_out += (bytes > 512 ? 512 : bytes);
                         fd_ref_table[sock]->cmds_out++;
                 }
+               statsSent += (bytes > 512 ? 512 : bytes);
        }
 }
 
@@ -656,14 +662,15 @@ void WriteFrom(int sock, userrec *user,char* text, ...)
        if (sock != -1)
        {
                 int MOD_RESULT = 0;
-                FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 514 ? 514 : bytes));
+                FOREACH_RESULT(OnRawSocketWrite(sock,tb,bytes > 512 ? 512 : bytes));
                 if (!MOD_RESULT)
-                        write(sock,tb,bytes > 514 ? 514 : bytes);
+                        write(sock,tb,bytes > 512 ? 512 : bytes);
                 if (fd_ref_table[sock])
                 {
-                        fd_ref_table[sock]->bytes_out += (bytes > 514 ? 514 : bytes);
+                        fd_ref_table[sock]->bytes_out += (bytes > 512 ? 512 : bytes);
                         fd_ref_table[sock]->cmds_out++;
                 }
+               statsSent += (bytes > 512 ? 512 : bytes);
        }
 }
 
@@ -853,7 +860,9 @@ void WriteCommon(userrec *u, char* text, ...)
        va_end(argsPtr);
 
        // FIX: Stops a message going to the same person more than once
-       std::vector<int> already_sent;
+       bzero(&already_sent,65536);
+
+       bool sent_to_at_least_one = false;
 
         for (int i = 0; i < MAXCHANS; i++)
         {
@@ -864,26 +873,18 @@ void WriteCommon(userrec *u, char* text, ...)
                         {
                                 char* o = (*ulist)[j];
                                 userrec* otheruser = (userrec*)o;
-                               bool do_send = true;
-                               for (int t = 0; t < already_sent.size(); t++)
+                               if (!already_sent[otheruser->fd])
                                {
-                                       if (already_sent[t] == otheruser->fd)
-                                       {
-                                               do_send = false;
-                                               break;
-                                       }
-                               }
-                               if (do_send)
-                               {
-                                       already_sent.push_back(otheruser->fd);
+                                       already_sent[otheruser->fd] = 1;
                                        WriteFrom(otheruser->fd,u,"%s",textbuffer);
+                                       sent_to_at_least_one = true;
                                }
                         }
                 }
         }
        // if the user was not in any channels, no users will receive the text. Make sure the user
        // receives their OWN message for WriteCommon
-       if (!already_sent.size())
+       if (!sent_to_at_least_one)
        {
                WriteFrom(u->fd,u,"%s",textbuffer);
        }
@@ -911,7 +912,7 @@ void WriteCommonExcept(userrec *u, char* text, ...)
        vsnprintf(textbuffer, MAXBUF, text, argsPtr);
        va_end(argsPtr);
 
-       std::vector<int> already_sent;
+        bzero(&already_sent,65536);
 
         for (int i = 0; i < MAXCHANS; i++)
         {
@@ -924,18 +925,9 @@ void WriteCommonExcept(userrec *u, char* text, ...)
                                 userrec* otheruser = (userrec*)o;
                                if (u != otheruser)
                                {
-                                       bool do_send = true;
-                                       for (int t = 0; t < already_sent.size(); t++)
-                                       {
-                                               if (already_sent[t] == otheruser->fd)
-                                               {
-                                                       do_send = false;
-                                                       break;
-                                               }
-                                       }
-                                       if (do_send)
+                                       if (!already_sent[otheruser->fd])
                                        {
-                                               already_sent.push_back(otheruser->fd);
+                                               already_sent[otheruser->fd] = 1;
                                                WriteFrom(otheruser->fd,u,"%s",textbuffer);
                                        }
                                }
@@ -2482,7 +2474,17 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip)
 
        iter = clientlist.find(tempnick);
 
-       if (iter != clientlist.end()) return;
+       // fix by brain.
+       // as these nicknames are 'RFC impossible', we can be sure nobody is going to be
+       // using one as a registered connection. As theyre per fd, we can also safely assume
+       // that we wont have collisions. Therefore, if the nick exists in the list, its only
+       // used by a dead socket, erase the iterator so that the new client may reclaim it.
+       // this was probably the cause of 'server ignores me when i hammer it with reconnects'
+       // issue in earlier alphas/betas
+       if (iter != clientlist.end())
+       {
+               clientlist.erase(iter);
+       }
 
        /*
         * It is OK to access the value here this way since we know
@@ -2537,7 +2539,23 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip)
        }
 
        if (clientlist.size() == MAXCLIENTS)
+       {
                kill_link(clientlist[tempnick],"No more connections allowed in this class");
+               return;
+       }
+
+       // this is done as a safety check to keep the file descriptors within range of fd_ref_table.
+       // its a pretty big but for the moment valid assumption:
+       // file descriptors are handed out starting at 0, and are recycled as theyre freed.
+       // therefore if there is ever an fd over 65535, 65536 clients must be connected to the
+       // irc server at once (or the irc server otherwise initiating this many connections, files etc)
+       // which for the time being is a physical impossibility (even the largest networks dont have more
+       // than about 10,000 users on ONE server!)
+       if (socket > 65535)
+       {
+               kill_link(clientlist[tempnick],"Server is full");
+               return;
+       }
                
 
         char* e = matches_exception(ip);
@@ -2549,6 +2567,7 @@ void AddClient(int socket, char* host, int port, bool iscached, char* ip)
                        char reason[MAXBUF];
                        snprintf(reason,MAXBUF,"Z-Lined: %s",r);
                        kill_link(clientlist[tempnick],reason);
+                       return;
                }
        }
        fd_ref_table[socket] = clientlist[tempnick];
@@ -2661,7 +2680,7 @@ void ShowMOTD(userrec *user)
         WholeMOTD = WholeMOTD + std::string(":") + std::string(ServerName) + std::string(" 376 ") + std::string(user->nick) + std::string(" :End of message of the day.\r\n");
         // only one write operation
         send(user->fd,WholeMOTD.c_str(),WholeMOTD.length(),0);
-
+       statsSent += WholeMOTD.length();
 }
 
 void ShowRULES(userrec *user)
@@ -2682,6 +2701,7 @@ void ShowRULES(userrec *user)
 /* shows the message of the day, and any other on-logon stuff */
 void FullConnectUser(userrec* user)
 {
+       statsConnects++;
         user->registered = 7;
         user->idle_lastmsg = TIME;
         log(DEBUG,"ConnectUser: %s",user->nick);
@@ -2955,11 +2975,13 @@ void force_nickchange(userrec* user,const char* newnick)
 
        FOREACH_RESULT(OnUserPreNick(user,newnick));
        if (MOD_RESULT) {
+               statsCollisions++;
                kill_link(user,"Nickname collision");
                return;
        }
        if (matches_qline(newnick))
        {
+               statsCollisions++;
                kill_link(user,"Nickname collision");
                return;
        }
@@ -3166,6 +3188,7 @@ void process_command(userrec *user, char* cmd)
                        {
                                if (strchr("@!\"$%^&*(){}[]_=+;:'#~,<>/?\\|`",command[x]))
                                {
+                                       statsUnknown++;
                                        WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
                                        return;
                                }
@@ -3288,6 +3311,7 @@ void process_command(userrec *user, char* cmd)
        }
        if ((!cmd_found) && (user))
        {
+               statsUnknown++;
                WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
        }
 }
@@ -4101,6 +4125,9 @@ int InspIRCd(void)
 
                if ((curr) && (curr->fd != 0))
                {
+#ifdef _POSIX_PRIORITY_SCHEDULING
+        sched_yield();
+#endif
                        // assemble up to 64 sockets into an fd_set
                        // to implement a pooling mechanism.
                        //
@@ -4128,6 +4155,7 @@ int InspIRCd(void)
                                                {
                                                        log(DEBUG,"signon exceed, registered=3, and modules ready, OK");
                                                        curr->dns_done = true;
+                                                       statsDnsBad++;
                                                        FullConnectUser(curr);
                                                        goto label;
                                                }
@@ -4189,9 +4217,9 @@ int InspIRCd(void)
                                        }
                                        else result = result2;
                                        log(DEBUG,"Read result: %d",result);
-       
                                        if (result)
                                        {
+                                               statsRecv += result;
                                                // perform a check on the raw buffer as an array (not a string!) to remove
                                                // characters 0 and 7 which are illegal in the RFC - replace them with spaces.
                                                // hopefully this should stop even more people whining about "Unknown command: *"
@@ -4289,6 +4317,8 @@ int InspIRCd(void)
                                                                process_buffer(sanitized,current);
                                                                // look for the user's record in case it's changed... if theyve quit,
                                                                // we cant do anything more with their buffer, so bail.
+                                                               // there used to be an ugly, slow loop here. Now we have a reference
+                                                               // table, life is much easier (and FASTER)
                                                                if (!fd_ref_table[currfd])
                                                                        goto label;
 
@@ -4362,10 +4392,12 @@ int InspIRCd(void)
                                {
                                        WriteOpers("*** WARNING: Accept failed on port %lu (%s)",(unsigned long)ports[count],target);
                                        log(DEBUG,"InspIRCd: accept failed: %lu",(unsigned long)ports[count]);
+                                       statsRefused++;
                                }
                                else
                                {
                                        FOREACH_MOD OnRawSocketAccept(incomingSockfd, resolved, ports[count]);
+                                       statsAccept++;
                                        AddClient(incomingSockfd, resolved, ports[count], false, inet_ntoa (client.sin_addr));
                                        log(DEBUG,"InspIRCd: adding client on port %lu fd=%lu",(unsigned long)ports[count],(unsigned long)incomingSockfd);
                                }
@@ -4377,6 +4409,7 @@ int InspIRCd(void)
        if (0) {};
 #ifdef _POSIX_PRIORITY_SCHEDULING
         sched_yield();
+       sched_yield();
 #endif
 }
 /* not reached */