X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fcommands%2Fcmd_stats.cpp;h=6b21d0db6c8569c8f10396b66510ec80a208977b;hb=41c26a03fac6915c0abcde17bacb6563c50719e5;hp=9e7db92b22d165c3482fb962909c9822d78a0f0a;hpb=f4ea51671f367d6e473049d52919a3c879329c6f;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/commands/cmd_stats.cpp b/src/commands/cmd_stats.cpp index 9e7db92b2..6b21d0db6 100644 --- a/src/commands/cmd_stats.cpp +++ b/src/commands/cmd_stats.cpp @@ -1,114 +1,145 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ +/* + * InspIRCd -- Internet Relay Chat Daemon * - * InspIRCd: (C) 2002-2008 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits + * Copyright (C) 2009-2010 Daniel De Graaf + * Copyright (C) 2007-2008 Craig Edwards + * Copyright (C) 2007 Robin Burchell * - * This program is free but copyrighted software; see - * the file COPYING for details. + * 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 + * License as published by the Free Software Foundation, version 2. * - * --------------------------------------------------- + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ -#include "inspircd.h" -#ifndef WIN32 - #include - /* This is just to be completely certain that the change which fixed getrusage on RH7 doesn't break anything else -- Om */ - #ifndef RUSAGE_SELF - #define RUSAGE_SELF 0 - #endif -#else - #include - #pragma comment(lib, "psapi.lib") -#endif +#include "inspircd.h" #include "xline.h" -#include "commands/cmd_stats.h" #include "commands/cmd_whowas.h" - -extern "C" DllExport Command* init_command(InspIRCd* Instance) -{ - return new CommandStats(Instance); -} - -CmdResult CommandStats::Handle (const std::vector& parameters, User *user) +/** Handle /STATS. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandStats : public Command { - if (IS_LOCAL(user)) + void DoStats(char statschar, User* user, string_list &results); + public: + /** Constructor for stats. + */ + CommandStats ( Module* parent) : Command(parent,"STATS",1,2) { syntax = " []"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh command + * @param user The user issuing the command + * @return A value from CmdResult to indicate command success or failure. + */ + CmdResult Handle(const std::vector& parameters, User *user); + RouteDescriptor GetRouting(User* user, const std::vector& parameters) { - string_list values; - DoStats(this->ServerInstance, parameters[0][0], user, values); - for (size_t i = 0; i < values.size(); i++) - user->Write(":%s", values[i].c_str()); + if (parameters.size() > 1) + return ROUTE_UNICAST(parameters[1]); + return ROUTE_LOCALONLY; } +}; - return CMD_SUCCESS; -} - -DllExport void DoStats(InspIRCd* ServerInstance, char statschar, User* user, string_list &results) +void CommandStats::DoStats(char statschar, User* user, string_list &results) { std::string sn(ServerInstance->Config->ServerName); - if ((!*ServerInstance->Config->UserStats && !IS_OPER(user)) || (!IS_OPER(user) && !ServerInstance->ULine(user->server) && !strchr(ServerInstance->Config->UserStats,statschar))) + bool isPublic = ServerInstance->Config->UserStats.find(statschar) != std::string::npos; + bool isRemoteOper = IS_REMOTE(user) && IS_OPER(user); + bool isLocalOperWithPrivs = IS_LOCAL(user) && user->HasPrivPermission("servers/auspex"); + + if (!isPublic && !isRemoteOper && !isLocalOperWithPrivs) { ServerInstance->SNO->WriteToSnoMask('t', "%s '%c' denied for %s (%s@%s)", (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str()); - results.push_back(sn + " 481 " + user->nick + " :Permission denied - STATS " + statschar + " is oper-only"); + results.push_back(sn + " 481 " + user->nick + " :Permission denied - STATS " + statschar + " requires the servers/auspex priv."); return; } - - int MOD_RESULT = 0; - FOREACH_RESULT(I_OnStats,OnStats(statschar,user,results)); - if (MOD_RESULT) + + ModResult MOD_RESULT; + FIRST_MOD_RESULT(OnStats, MOD_RESULT, (statschar, user, results)); + if (MOD_RESULT == MOD_RES_DENY) + { + results.push_back(sn+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); + ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)", + (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str()); return; + } switch (statschar) { - /* stats p (show listening ports and registered clients on each) */ + /* stats p (show listening ports) */ case 'p': { - for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++) + for (std::vector::const_iterator i = ServerInstance->ports.begin(); i != ServerInstance->ports.end(); ++i) { - std::string ip = ServerInstance->Config->ports[i]->GetIP(); + ListenSocket* ls = *i; + std::string ip = ls->bind_addr; if (ip.empty()) ip.assign("*"); + std::string type = ls->bind_tag->getString("type", "clients"); + std::string hook = ls->bind_tag->getString("ssl", "plaintext"); - results.push_back(sn+" 249 "+user->nick+" :"+ ip + ":"+ConvToStr(ServerInstance->Config->ports[i]->GetPort())+" (client, " + - ServerInstance->Config->ports[i]->GetDescription() + ")"); + results.push_back(sn+" 249 "+user->nick+" :"+ ip + ":"+ConvToStr(ls->bind_port)+ + " (" + type + ", " + hook + ")"); } } break; + /* These stats symbols must be handled by a linking module */ case 'n': case 'c': - { - /* This stats symbol must be handled by a linking module */ - } break; - + case 'i': { - int idx = 0; for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++) { ConnectClass* c = *i; - results.push_back(sn+" 215 "+user->nick+" I NOMATCH * "+c->GetHost()+" "+ConvToStr(c->limit ? c->limit : ServerInstance->SE->GetMaxFds())+" "+ConvToStr(idx)+" "+ServerInstance->Config->ServerName+" *"); - idx++; + std::stringstream res; + res << sn << " 215 " << user->nick << " I " << c->name << ' '; + if (c->type == CC_ALLOW) + res << '+'; + if (c->type == CC_DENY) + res << '-'; + + if (c->type == CC_NAMED) + res << '*'; + else + res << c->host; + + res << ' ' << c->config->getString("port", "*") << ' '; + + res << c->GetRecvqMax() << ' ' << c->GetSendqSoftMax() << ' ' << c->GetSendqHardMax() + << ' ' << c->GetCommandRate() << ' ' << c->GetPenaltyThreshold(); + if (c->fakelag) + res << '*'; + results.push_back(res.str()); } } break; - + case 'Y': { int idx = 0; for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++) { ConnectClass* c = *i; - results.push_back(sn+" 218 "+user->nick+" Y "+ConvToStr(idx)+" "+ConvToStr(c->GetPingTime())+" 0 "+ConvToStr(c->GetSendqMax())+" :"+ - ConvToStr(c->GetFlood())+" "+ConvToStr(c->GetRegTimeout())); + results.push_back(sn+" 215 "+user->nick+" i NOMATCH * "+c->GetHost()+" "+ConvToStr(c->limit ? c->limit : ServerInstance->SE->GetMaxFds())+" "+ConvToStr(idx)+" "+ServerInstance->Config->ServerName+" *"); + results.push_back(sn+" 218 "+user->nick+" Y "+ConvToStr(idx)+" "+ConvToStr(c->GetPingTime())+" 0 "+ConvToStr(c->GetSendqHardMax())+" :"+ + ConvToStr(c->GetRecvqMax())+" "+ConvToStr(c->GetRegTimeout())); idx++; } } @@ -116,19 +147,17 @@ DllExport void DoStats(InspIRCd* ServerInstance, char statschar, User* user, str case 'U': { - char ulined[MAXBUF]; - for (int i = 0; i < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "uline"); i++) + for(std::map::iterator i = ServerInstance->Config->ulines.begin(); i != ServerInstance->Config->ulines.end(); ++i) { - ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "uline","server", i, ulined, MAXBUF); - results.push_back(sn+" 248 "+user->nick+" U "+std::string(ulined)); + results.push_back(sn+" 248 "+user->nick+" U "+std::string(i->first.c_str())); } } break; - + case 'P': { int idx = 0; - for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++) + for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++) { if (IS_OPER(i->second) && !ServerInstance->ULine(i->second->server)) { @@ -140,7 +169,7 @@ DllExport void DoStats(InspIRCd* ServerInstance, char statschar, User* user, str results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(idx)+" OPER(s)"); } break; - + case 'k': ServerInstance->XLines->InvokeStats("K",216,user,results); break; @@ -170,7 +199,7 @@ DllExport void DoStats(InspIRCd* ServerInstance, char statschar, User* user, str if (i->second->use_count) { /* RPL_STATSCOMMANDS */ - results.push_back(sn+" 212 "+user->nick+" "+i->second->command+" "+ConvToStr(i->second->use_count)+" "+ConvToStr(i->second->total_bytes)); + results.push_back(sn+" 212 "+user->nick+" "+i->second->name+" "+ConvToStr(i->second->use_count)+" "+ConvToStr(i->second->total_bytes)); } } break; @@ -178,39 +207,30 @@ DllExport void DoStats(InspIRCd* ServerInstance, char statschar, User* user, str /* stats z (debug and memory info) */ case 'z': { - results.push_back(sn+" 240 "+user->nick+" :InspIRCd(CLASS) "+ConvToStr(sizeof(InspIRCd))+" bytes"); - results.push_back(sn+" 249 "+user->nick+" :Users(HASH_MAP) "+ConvToStr(ServerInstance->Users->clientlist->size())+" ("+ConvToStr(ServerInstance->Users->clientlist->size()*sizeof(User))+" bytes)"); - results.push_back(sn+" 249 "+user->nick+" :Channels(HASH_MAP) "+ConvToStr(ServerInstance->chanlist->size())+" ("+ConvToStr(ServerInstance->chanlist->size()*sizeof(Channel))+" bytes)"); - results.push_back(sn+" 249 "+user->nick+" :Commands(VECTOR) "+ConvToStr(ServerInstance->Parser->cmdlist.size())+" ("+ConvToStr(ServerInstance->Parser->cmdlist.size()*sizeof(Command))+" bytes)"); + results.push_back(sn+" 249 "+user->nick+" :Users: "+ConvToStr(ServerInstance->Users->clientlist->size())); + results.push_back(sn+" 249 "+user->nick+" :Channels: "+ConvToStr(ServerInstance->chanlist->size())); + results.push_back(sn+" 249 "+user->nick+" :Commands: "+ConvToStr(ServerInstance->Parser->cmdlist.size())); if (!ServerInstance->Config->WhoWasGroupSize == 0 && !ServerInstance->Config->WhoWasMaxGroups == 0) { - Command* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS"); - if (whowas_command) + Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so"); + if (whowas) { - std::deque params; - Extensible whowas_stats; - params.push_back(&whowas_stats); - whowas_command->HandleInternal(WHOWAS_STATS, params); - if (whowas_stats.GetExt("stats")) - { - char* stats; - whowas_stats.GetExt("stats", stats); - results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(stats)); - } + WhowasRequest req(NULL, whowas, WhowasRequest::WHOWAS_STATS); + req.user = user; + req.Send(); + results.push_back(sn+" 249 "+user->nick+" :"+req.value); } } - results.push_back(sn+" 249 "+user->nick+" :MOTD(VECTOR) "+ConvToStr(ServerInstance->Config->MOTD.size())+", RULES(VECTOR) "+ConvToStr(ServerInstance->Config->RULES.size())); - float kbitpersec_in, kbitpersec_out, kbitpersec_total; char kbitpersec_in_s[30], kbitpersec_out_s[30], kbitpersec_total_s[30]; ServerInstance->SE->GetStats(kbitpersec_in, kbitpersec_out, kbitpersec_total); - snprintf(kbitpersec_total_s, 30, "%03.5f%%", kbitpersec_total); - snprintf(kbitpersec_out_s, 30, "%03.5f%%", kbitpersec_out); - snprintf(kbitpersec_in_s, 30, "%03.5f%%", kbitpersec_in); + snprintf(kbitpersec_total_s, 30, "%03.5f", kbitpersec_total); + snprintf(kbitpersec_out_s, 30, "%03.5f", kbitpersec_out); + snprintf(kbitpersec_in_s, 30, "%03.5f", kbitpersec_in); results.push_back(sn+" 249 "+user->nick+" :Bandwidth total: "+ConvToStr(kbitpersec_total_s)+" kilobits/sec"); results.push_back(sn+" 249 "+user->nick+" :Bandwidth out: "+ConvToStr(kbitpersec_out_s)+" kilobits/sec"); @@ -231,16 +251,21 @@ DllExport void DoStats(InspIRCd* ServerInstance, char statschar, User* user, str results.push_back(sn+" 249 "+user->nick+" :Swaps: "+ConvToStr(R.ru_nswap)); results.push_back(sn+" 249 "+user->nick+" :Context Switches: Voluntary; "+ConvToStr(R.ru_nvcsw)+" Involuntary; "+ConvToStr(R.ru_nivcsw)); - timeval tv; char percent[30]; - gettimeofday(&tv, NULL); - - float n_elapsed = ((tv.tv_sec - ServerInstance->stats->LastSampled.tv_sec) * 1000000 + tv.tv_usec - ServerInstance->stats->LastSampled.tv_usec); + + float n_elapsed = (ServerInstance->Time() - ServerInstance->stats->LastSampled.tv_sec) * 1000000 + + (ServerInstance->Time_ns() - ServerInstance->stats->LastSampled.tv_nsec) / 1000; float n_eaten = ((R.ru_utime.tv_sec - ServerInstance->stats->LastCPU.tv_sec) * 1000000 + R.ru_utime.tv_usec - ServerInstance->stats->LastCPU.tv_usec); float per = (n_eaten / n_elapsed) * 100; snprintf(percent, 30, "%03.5f%%", per); - results.push_back(sn+" 249 "+user->nick+" :CPU Usage: "+percent); + results.push_back(sn+" 249 "+user->nick+" :CPU Use (now): "+percent); + + n_elapsed = ServerInstance->Time() - ServerInstance->startup_time; + n_eaten = (float)R.ru_utime.tv_sec + R.ru_utime.tv_usec / 100000.0; + per = (n_eaten / n_elapsed) * 100; + snprintf(percent, 30, "%03.5f%%", per); + results.push_back(sn+" 249 "+user->nick+" :CPU Use (total): "+percent); } #else PROCESS_MEMORY_COUNTERS MemCounters; @@ -249,11 +274,12 @@ DllExport void DoStats(InspIRCd* ServerInstance, char statschar, User* user, str results.push_back(sn+" 249 "+user->nick+" :Total allocation: "+ConvToStr((MemCounters.WorkingSetSize + MemCounters.PagefileUsage) / 1024)+"K"); results.push_back(sn+" 249 "+user->nick+" :Pagefile usage: "+ConvToStr(MemCounters.PagefileUsage / 1024)+"K"); results.push_back(sn+" 249 "+user->nick+" :Page faults: "+ConvToStr(MemCounters.PageFaultCount)); + results.push_back(sn+" 249 "+user->nick+" :CPU Usage: " + ConvToStr(getcpu()) + "%"); } #endif } break; - + case 'T': { char buffer[MAXBUF]; @@ -262,42 +288,66 @@ DllExport void DoStats(InspIRCd* ServerInstance, char statschar, User* user, str results.push_back(sn+" 249 "+user->nick+" :nick collisions "+ConvToStr(ServerInstance->stats->statsCollisions)); 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)); results.push_back(sn+" 249 "+user->nick+" :connection count "+ConvToStr(ServerInstance->stats->statsConnects)); - snprintf(buffer,MAXBUF," 249 %s :bytes sent %5.2fK recv %5.2fK",user->nick.c_str(),ServerInstance->stats->statsSent / 1024,ServerInstance->stats->statsRecv / 1024); + snprintf(buffer,MAXBUF," 249 %s :bytes sent %5.2fK recv %5.2fK", + user->nick.c_str(),ServerInstance->stats->statsSent / 1024.0,ServerInstance->stats->statsRecv / 1024.0); results.push_back(sn+buffer); } break; /* stats o */ case 'o': - for (int i = 0; i < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "oper"); i++) + { + ConfigTagList tags = ServerInstance->Config->ConfTags("oper"); + for(ConfigIter i = tags.first; i != tags.second; ++i) { - char LoginName[MAXBUF]; - char HostName[MAXBUF]; - char OperType[MAXBUF]; - ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","name", i, LoginName, MAXBUF); - ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","host", i, HostName, MAXBUF); - ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","type", i, OperType, MAXBUF); - results.push_back(sn+" 243 "+user->nick+" O "+HostName+" * "+LoginName+" "+OperType+" 0"); + ConfigTag* tag = i->second; + results.push_back(sn+" 243 "+user->nick+" O "+tag->getString("host")+" * "+ + tag->getString("name") + " " + tag->getString("type")+" 0"); } + } + break; + case 'O': + { + for(OperIndex::iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); i++) + { + // just the types, not the actual oper blocks... + if (i->first[0] != ' ') + continue; + OperInfo* tag = i->second; + tag->init(); + std::string umodes; + std::string cmodes; + for(char c='A'; c < 'z'; c++) + { + ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_USER); + if (mh && mh->NeedsOper() && tag->AllowedUserModes[c - 'A']) + umodes.push_back(c); + mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL); + if (mh && mh->NeedsOper() && tag->AllowedChanModes[c - 'A']) + cmodes.push_back(c); + } + results.push_back(sn+" 243 "+user->nick+" O "+tag->NameStr() + " " + umodes + " " + cmodes); + } + } break; /* stats l (show user I/O stats) */ case 'l': results.push_back(sn+" 211 "+user->nick+" :nick[ident@host] sendq cmds_out bytes_out cmds_in bytes_in time_open"); - for (std::vector::iterator n = ServerInstance->Users->local_users.begin(); n != ServerInstance->Users->local_users.end(); n++) + for (std::vector::iterator n = ServerInstance->Users->local_users.begin(); n != ServerInstance->Users->local_users.end(); n++) { - User* i = *n; - results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->dhost+"] "+ConvToStr(i->sendqlength)+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age)); + LocalUser* i = *n; + results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->dhost+"] "+ConvToStr(i->eh.getSendQSize())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age)); } break; - /* stats L (show user I/O stats with IP addresses) */ + /* stats L (show user I/O stats with IP addresses) */ case 'L': results.push_back(sn+" 211 "+user->nick+" :nick[ident@ip] sendq cmds_out bytes_out cmds_in bytes_in time_open"); - for (std::vector::iterator n = ServerInstance->Users->local_users.begin(); n != ServerInstance->Users->local_users.end(); n++) + for (std::vector::iterator n = ServerInstance->Users->local_users.begin(); n != ServerInstance->Users->local_users.end(); n++) { - User* i = *n; - results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->GetIPString()+"] "+ConvToStr(i->sendqlength)+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age)); + LocalUser* i = *n; + results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->GetIPString()+"] "+ConvToStr(i->eh.getSendQSize())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age)); } break; @@ -335,3 +385,18 @@ DllExport void DoStats(InspIRCd* ServerInstance, char statschar, User* user, str (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str()); return; } + +CmdResult CommandStats::Handle (const std::vector& parameters, User *user) +{ + if (parameters.size() > 1 && parameters[1] != ServerInstance->Config->ServerName) + return CMD_SUCCESS; + string_list values; + char search = parameters[0][0]; + DoStats(search, user, values); + for (size_t i = 0; i < values.size(); i++) + user->SendText(":%s", values[i].c_str()); + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandStats)