The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download | Blog | Stats
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

cmd_stats.h File Reference

#include "inspircd.h"
#include "users.h"
#include "channels.h"

Include dependency graph for cmd_stats.h:

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

class  cmd_stats
 Handle /STATS. More...

Functions

DllExport void DoStats (InspIRCd *Instance, char statschar, userrec *user, string_list &results)


Function Documentation

DllExport void DoStats InspIRCd Instance,
char  statschar,
userrec user,
string_list results
 

Definition at line 50 of file cmd_stats.cpp.

References classbase::age, connection::bytes_in, connection::bytes_out, InspIRCd::chanlist, ServerConfig::Classes, InspIRCd::clientlist, CommandParser::cmdlist, connection::cmds_in, connection::cmds_out, InspIRCd::Config, ServerConfig::config_data, ServerConfig::ConfValue(), ConvToStr(), userrec::dhost, InspIRCd::factory, FOREACH_RESULT, Extensible::GetExt(), CommandParser::GetHandler(), userrec::GetIPString(), command_t::HandleInternal(), connection::host, I_OnStats, userrec::ident, IS_LOCAL, IS_OPER, InspIRCd::IsNick(), serverstats::LastCPU, serverstats::LastSampled, InspIRCd::local_users, MAXBUF, MAXCLIENTS, InspIRCd::modules, ServerConfig::MOTD, userrec::nick, InspIRCd::Parser, ServerConfig::ports, ServerConfig::RULES, RUSAGE_SELF, userrec::sendq, userrec::server, ServerConfig::ServerName, InspIRCd::SNO, InspIRCd::startup_time, InspIRCd::stats, XLineManager::stats_e(), XLineManager::stats_g(), XLineManager::stats_k(), XLineManager::stats_q(), XLineManager::stats_z(), serverstats::statsAccept, serverstats::statsCollisions, serverstats::statsConnects, serverstats::statsDnsBad, serverstats::statsDnsGood, serverstats::statsRecv, serverstats::statsRefused, serverstats::statsSent, serverstats::statsUnknown, InspIRCd::Time(), InspIRCd::ULine(), ServerConfig::UserStats, WHOWAS_STATS, ServerConfig::WhoWasGroupSize, ServerConfig::WhoWasMaxGroups, SnomaskManager::WriteToSnoMask(), and InspIRCd::XLines.

Referenced by cmd_stats::Handle(), and TreeSocket::Stats().

00051 {
00052         std::string sn = ServerInstance->Config->ServerName;
00053 
00054         if ((!*ServerInstance->Config->UserStats && !IS_OPER(user)) || (!IS_OPER(user) && !ServerInstance->ULine(user->server) && !strchr(ServerInstance->Config->UserStats,statschar)))
00055         {
00056                 results.push_back(sn+std::string(" 481 ")+user->nick+" :Permission denied - STATS "+statschar+" is oper-only");
00057                 return;
00058         }
00059         
00060         int MOD_RESULT = 0;
00061         FOREACH_RESULT(I_OnStats,OnStats(statschar,user,results));
00062         if (MOD_RESULT)
00063                 return;
00064 
00065         switch (statschar)
00066         {
00067                 /* stats p (show listening ports and registered clients on each) */
00068                 case 'p':
00069                 {
00070                         for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)
00071                         {
00072                                 std::string ip = ServerInstance->Config->ports[i]->GetIP();
00073                                 if (ip.empty())
00074                                         ip.assign("*");
00075 
00076                                 results.push_back(sn+" 249 "+user->nick+" :"+ ip + ":"+ConvToStr(ServerInstance->Config->ports[i]->GetPort())+" (client, " +
00077                                                 ServerInstance->Config->ports[i]->GetDescription() + ")");
00078                         }
00079                 }
00080                 break;
00081 
00082                 case 'n':
00083                 case 'c':
00084                 {
00085                         /* This stats symbol must be handled by a linking module */
00086                 }
00087                 break;
00088         
00089                 case 'i':
00090                 {
00091                         int idx = 0;
00092                         for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
00093                         {
00094                                 results.push_back(sn+" 215 "+user->nick+" I NOMATCH * "+i->GetHost()+" "+ConvToStr(MAXCLIENTS)+" "+ConvToStr(idx)+" "+ServerInstance->Config->ServerName+" *");
00095                                 idx++;
00096                         }
00097                 }
00098                 break;
00099         
00100                 case 'Y':
00101                 {
00102                         int idx = 0;
00103                         for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
00104                         {
00105                                 results.push_back(sn+" 218 "+user->nick+" Y "+ConvToStr(idx)+" "+ConvToStr(i->GetPingTime())+" 0 "+ConvToStr(i->GetSendqMax())+" :"+
00106                                                 ConvToStr(i->GetFlood())+" "+ConvToStr(i->GetRegTimeout()));
00107                                 idx++;
00108                         }
00109                 }
00110                 break;
00111 
00112                 case 'U':
00113                 {
00114                         char ulined[MAXBUF];
00115                         for (int i = 0; i < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "uline"); i++)
00116                         {
00117                                 ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "uline","server", i, ulined, MAXBUF);
00118                                         results.push_back(sn+" 248 "+user->nick+" U "+std::string(ulined));
00119                         }
00120                 }
00121                 break;
00122         
00123                 case 'P':
00124                 {
00125                         int idx = 0;
00126                         for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
00127                         {
00128                                 if (IS_OPER(i->second) && !ServerInstance->ULine(i->second->server))
00129                                 {
00130                                         results.push_back(sn+" 249 "+user->nick+" :"+i->second->nick+" ("+i->second->ident+"@"+i->second->dhost+") Idle: "+
00131                                                         (IS_LOCAL(i->second) ? ConvToStr(ServerInstance->Time() - i->second->idle_lastmsg) + " secs" : "unavailable"));
00132                                         idx++;
00133                                 }
00134                         }
00135                         results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(idx)+" OPER(s)");
00136                 }
00137                 break;
00138  
00139                 case 'k':
00140                         ServerInstance->XLines->stats_k(user,results);
00141                 break;
00142 
00143                 case 'g':
00144                         ServerInstance->XLines->stats_g(user,results);
00145                 break;
00146 
00147                 case 'q':
00148                         ServerInstance->XLines->stats_q(user,results);
00149                 break;
00150 
00151                 case 'Z':
00152                         ServerInstance->XLines->stats_z(user,results);
00153                 break;
00154 
00155                 case 'e':
00156                         ServerInstance->XLines->stats_e(user,results);
00157                 break;
00158 
00159                 /* stats m (list number of times each command has been used, plus bytecount) */
00160                 case 'm':
00161                         for (command_table::iterator i = ServerInstance->Parser->cmdlist.begin(); i != ServerInstance->Parser->cmdlist.end(); i++)
00162                         {
00163                                 if (i->second->use_count)
00164                                 {
00165                                         /* RPL_STATSCOMMANDS */
00166                                         results.push_back(sn+" 212 "+user->nick+" "+i->second->command+" "+ConvToStr(i->second->use_count)+" "+ConvToStr(i->second->total_bytes));
00167                                 }
00168                         }
00169                 break;
00170 
00171                 /* stats z (debug and memory info) */
00172                 case 'z':
00173                 {
00174                         results.push_back(sn+" 240 "+user->nick+" :InspIRCd(CLASS) "+ConvToStr(sizeof(InspIRCd))+" bytes");
00175                         results.push_back(sn+" 249 "+user->nick+" :Users(HASH_MAP) "+ConvToStr(ServerInstance->clientlist->size())+" ("+ConvToStr(ServerInstance->clientlist->size()*sizeof(userrec))+" bytes)");
00176                         results.push_back(sn+" 249 "+user->nick+" :Channels(HASH_MAP) "+ConvToStr(ServerInstance->chanlist->size())+" ("+ConvToStr(ServerInstance->chanlist->size()*sizeof(chanrec))+" bytes)");
00177                         results.push_back(sn+" 249 "+user->nick+" :Commands(VECTOR) "+ConvToStr(ServerInstance->Parser->cmdlist.size())+" ("+ConvToStr(ServerInstance->Parser->cmdlist.size()*sizeof(command_t))+" bytes)");
00178 
00179                         if (!ServerInstance->Config->WhoWasGroupSize == 0 && !ServerInstance->Config->WhoWasMaxGroups == 0)
00180                         {
00181                                 command_t* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");
00182                                 if (whowas_command)
00183                                 {
00184                                         std::deque<classbase*> params;
00185                                         Extensible whowas_stats;
00186                                         params.push_back(&whowas_stats);
00187                                         whowas_command->HandleInternal(WHOWAS_STATS, params);
00188                                         if (whowas_stats.GetExt("stats"))
00189                                         {
00190                                                 char* stats;
00191                                                 whowas_stats.GetExt("stats", stats);
00192                                                 results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(stats));
00193                                         }
00194                                 }
00195                         }
00196 
00197                         results.push_back(sn+" 249 "+user->nick+" :MOTD(VECTOR) "+ConvToStr(ServerInstance->Config->MOTD.size())+", RULES(VECTOR) "+ConvToStr(ServerInstance->Config->RULES.size()));
00198                         results.push_back(sn+" 249 "+user->nick+" :Modules(VECTOR) "+ConvToStr(ServerInstance->modules.size())+" ("+ConvToStr(ServerInstance->modules.size()*sizeof(Module))+" bytes)");
00199                         results.push_back(sn+" 249 "+user->nick+" :ClassFactories(VECTOR) "+ConvToStr(ServerInstance->factory.size())+" ("+ConvToStr(ServerInstance->factory.size()*sizeof(ircd_module))+" bytes)");
00200 
00201 #ifndef WIN32
00202                         /* Moved this down here so all the not-windows stuff (look w00tie, I didn't say win32!) is in one ifndef.
00203                          * Also cuts out some identical code in both branches of the ifndef. -- Om
00204                          */
00205                         rusage R;
00206 
00207                         /* Not sure why we were doing '0' with a RUSAGE_SELF comment rather than just using RUSAGE_SELF -- Om */
00208                         if (!getrusage(RUSAGE_SELF,&R)) /* RUSAGE_SELF */
00209                         {
00210                                 results.push_back(sn+" 249 "+user->nick+" :Total allocation: "+ConvToStr(R.ru_maxrss)+"K");
00211                                 results.push_back(sn+" 249 "+user->nick+" :Signals:          "+ConvToStr(R.ru_nsignals));
00212                                 results.push_back(sn+" 249 "+user->nick+" :Page faults:      "+ConvToStr(R.ru_majflt));
00213                                 results.push_back(sn+" 249 "+user->nick+" :Swaps:            "+ConvToStr(R.ru_nswap));
00214                                 results.push_back(sn+" 249 "+user->nick+" :Context Switches: Voluntary; "+ConvToStr(R.ru_nvcsw)+" Involuntary; "+ConvToStr(R.ru_nivcsw));
00215 
00216                                 timeval tv;
00217                                 char percent[30];
00218                                 gettimeofday(&tv, NULL);
00219                         
00220                                 float n_elapsed = ((tv.tv_sec - ServerInstance->stats->LastSampled.tv_sec) * 1000000 + tv.tv_usec - ServerInstance->stats->LastSampled.tv_usec);
00221                                 float n_eaten = ((R.ru_utime.tv_sec - ServerInstance->stats->LastCPU.tv_sec) * 1000000 + R.ru_utime.tv_usec - ServerInstance->stats->LastCPU.tv_usec);
00222                                 float per = (n_eaten / n_elapsed) * 100;
00223 
00224                                 snprintf(percent, 30, "%03.5f%%", per);
00225                                 results.push_back(sn+" 249 "+user->nick+" :CPU Usage: "+percent);
00226                         }
00227 #endif
00228                 }
00229                 break;
00230         
00231                 case 'T':
00232                 {
00233                         char buffer[MAXBUF];
00234                         results.push_back(sn+" 249 "+user->nick+" :accepts "+ConvToStr(ServerInstance->stats->statsAccept)+" refused "+ConvToStr(ServerInstance->stats->statsRefused));
00235                         results.push_back(sn+" 249 "+user->nick+" :unknown commands "+ConvToStr(ServerInstance->stats->statsUnknown));
00236                         results.push_back(sn+" 249 "+user->nick+" :nick collisions "+ConvToStr(ServerInstance->stats->statsCollisions));
00237                         results.push_back(sn+" 249 "+user->nick+" :dns requests "+ConvToStr(ServerInstance->stats->statsDnsGood+ServerInstance->stats->statsDnsBad)+" succeeded "+ConvToStr(ServerInstance->stats->statsDnsGood)+" failed "+ConvToStr(ServerInstance->stats->statsDnsBad));
00238                         results.push_back(sn+" 249 "+user->nick+" :connection count "+ConvToStr(ServerInstance->stats->statsConnects));
00239                         snprintf(buffer,MAXBUF," 249 %s :bytes sent %5.2fK recv %5.2fK",user->nick,ServerInstance->stats->statsSent / 1024,ServerInstance->stats->statsRecv / 1024);
00240                         results.push_back(sn+buffer);
00241                 }
00242                 break;
00243 
00244                 /* stats o */
00245                 case 'o':
00246                         for (int i = 0; i < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "oper"); i++)
00247                         {
00248                                 char LoginName[MAXBUF];
00249                                 char HostName[MAXBUF];
00250                                 char OperType[MAXBUF];
00251                                 ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","name", i, LoginName, MAXBUF);
00252                                 ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","host", i, HostName, MAXBUF);
00253                                 ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","type", i, OperType, MAXBUF);
00254                                 results.push_back(sn+" 243 "+user->nick+" O "+HostName+" * "+LoginName+" "+OperType+" 0");
00255                         }
00256                 break;
00257 
00258                 /* stats l (show user I/O stats) */
00259                 case 'l':
00260                         results.push_back(sn+" 211 "+user->nick+" :nick[ident@host] sendq cmds_out bytes_out cmds_in bytes_in time_open");
00261                         for (std::vector<userrec*>::iterator n = ServerInstance->local_users.begin(); n != ServerInstance->local_users.end(); n++)
00262                         {
00263                                 userrec* i = *n;
00264                                 if (ServerInstance->IsNick(i->nick))
00265                                 {
00266                                         results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->dhost+"] "+ConvToStr(i->sendq.length())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age));
00267                                 }
00268                         }
00269                 break;
00270 
00271         /* stats L (show user I/O stats with IP addresses) */
00272                 case 'L':
00273                         results.push_back(sn+" 211 "+user->nick+" :nick[ident@ip] sendq cmds_out bytes_out cmds_in bytes_in time_open");
00274                         for (std::vector<userrec*>::iterator n = ServerInstance->local_users.begin(); n != ServerInstance->local_users.end(); n++)
00275                         {
00276                                 userrec* i = *n;
00277                                 if (ServerInstance->IsNick(i->nick))
00278                                 {
00279                                         results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->GetIPString()+"] "+ConvToStr(i->sendq.length())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age));
00280                                 }
00281                         }
00282                 break;
00283 
00284                 /* stats u (show server uptime) */
00285                 case 'u':
00286                 {
00287                         time_t current_time = 0;
00288                         current_time = ServerInstance->Time();
00289                         time_t server_uptime = current_time - ServerInstance->startup_time;
00290                         struct tm* stime;
00291                         stime = gmtime(&server_uptime);
00292                         /* i dont know who the hell would have an ircd running for over a year nonstop, but
00293                          * Craig suggested this, and it seemed a good idea so in it went */
00294                         if (stime->tm_year > 70)
00295                         {
00296                                 char buffer[MAXBUF];
00297                                 snprintf(buffer,MAXBUF," 242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick,(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
00298                                 results.push_back(sn+buffer);
00299                         }
00300                         else
00301                         {
00302                                 char buffer[MAXBUF];
00303                                 snprintf(buffer,MAXBUF," 242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick,stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
00304                                 results.push_back(sn+buffer);
00305                         }
00306                 }
00307                 break;
00308 
00309                 default:
00310                 break;
00311         }
00312 
00313         results.push_back(sn+" 219 "+user->nick+" "+statschar+" :End of /STATS report");
00314         ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host);
00315 
00316         return;
00317 }