Move stuff around a bit:

- Create FileSystem class:
  * Move ServerConfig::CleanFilename to FileSystem::GetFileName and rewrite.
  * Move ServerConfig::ExpandPath to FileSystem.
  * Move ServerConfig::FileExists to FileSystem.
  * Move ServerConfig::StartsWithWindowsDriveLetter to FileSystem.
- Move FileReader to fileutils.cpp and fix documentation.
- Move UserManager::DoBackgroundUserStuff to usermanager.cpp.
This commit is contained in:
Peter Powell 2013-10-05 04:55:11 +01:00
parent 357d190074
commit 02830985a1
13 changed files with 269 additions and 246 deletions

View File

@ -225,10 +225,10 @@ class CoreExport ServerConfig
, Log(LOG_PATH)
, Module(MOD_PATH) { }
std::string PrependConfig(const std::string& fn) const { return ServerConfig::ExpandPath(Config, fn); }
std::string PrependData(const std::string& fn) const { return ServerConfig::ExpandPath(Data, fn); }
std::string PrependLog(const std::string& fn) const { return ServerConfig::ExpandPath(Log, fn); }
std::string PrependModule(const std::string& fn) const { return ServerConfig::ExpandPath(Module, fn); }
std::string PrependConfig(const std::string& fn) const { return FileSystem::ExpandPath(Config, fn); }
std::string PrependData(const std::string& fn) const { return FileSystem::ExpandPath(Data, fn); }
std::string PrependLog(const std::string& fn) const { return FileSystem::ExpandPath(Log, fn); }
std::string PrependModule(const std::string& fn) const { return FileSystem::ExpandPath(Module, fn); }
};
/** Get a configuration tag
@ -551,30 +551,8 @@ class CoreExport ServerConfig
void Fill();
/** Returns true if the given string starts with a windows drive letter
*/
static bool StartsWithWindowsDriveLetter(const std::string& path);
bool ApplyDisabledCommands(const std::string& data);
/** Clean a filename, stripping the directories (and drives) from string.
* @param name Directory to tidy
* @return The cleaned filename
*/
static const char* CleanFilename(const char* name);
/** Check if a file exists.
* @param file The full path to a file
* @return True if the file exists and is readable.
*/
static bool FileExists(const char* file);
/** Expands a path fragment to a full path.
* @param base The base path to expand from
* @param fragment The path fragment to expand on top of base.
*/
static std::string ExpandPath(const std::string& base, const std::string& fragment);
/** Escapes a value for storage in a configuration key.
* @param str The string to escape.
* @param xml Are we using the XML config format?

87
include/fileutils.h Normal file
View File

@ -0,0 +1,87 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2013 Peter Powell <petpow@saberuk.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
/** Provides an easy method of reading a text file into memory. */
class CoreExport FileReader : public classbase
{
/** The lines of text in the file. */
std::vector<std::string> lines;
/** File size in bytes. */
unsigned long totalSize;
public:
/** Initializes a new file reader. */
FileReader() : totalSize(0) { }
/** Initializes a new file reader and reads the specified file.
* @param filename The file to read into memory.
*/
FileReader(const std::string& filename);
/** Loads a text file from disk.
* @param filename The file to read into memory.
* @throw CoreException The file can not be loaded.
*/
void Load(const std::string& filename);
/** Retrieves the entire contents of the file cache as a single string. */
std::string GetString() const;
/** Retrieves the entire contents of the file cache as a vector of strings. */
const std::vector<std::string>& GetVector() const { return lines; }
/** Retrieves the total size in bytes of the file. */
unsigned long TotalSize() const { return totalSize; }
};
/** Implements methods for file system access */
class CoreExport FileSystem
{
private:
FileSystem() { }
public:
/** Expands a path fragment to a full path.
* @param base The base path to expand from
* @param fragment The path fragment to expand on top of base.
*/
static std::string ExpandPath(const std::string& base, const std::string& fragment);
/**
* Checks whether a file with the specified name exists on the filesystem.
* @param path The path to a file.
* @return True if the file exists; otherwise, false.
*/
static bool FileExists(const std::string& path);
/** Gets the file name segment of a path.
* @param path The path to extract the file name from.
* @return The file name segment of a path.
*/
static std::string GetFileName(const std::string& path);
/** Determines whether the given path starts with a Windows drive letter.
* @param path The path to validate.
* @returns True if the path begins with a Windows drive letter; otherwise, false.
*/
static bool StartsWithWindowsDriveLetter(const std::string& path);
};

View File

@ -54,6 +54,7 @@ CoreExport extern InspIRCd* ServerInstance;
#include "caller.h"
#include "cull_list.h"
#include "extensible.h"
#include "fileutils.h"
#include "numerics.h"
#include "uid.h"
#include "users.h"

View File

@ -1078,44 +1078,6 @@ class CoreExport Module : public classbase, public usecountbase
virtual void OnSetUserIP(LocalUser* user);
};
/** Provides an easy method of reading a text file into memory. */
class CoreExport FileReader : public classbase
{
/** The lines of text in the file.
*/
std::vector<std::string> lines;
/** Content size in bytes
*/
unsigned long totalSize;
public:
/** Initializes a new file reader.
*/
FileReader() : totalSize(0) { }
/** Initializes a new file reader and reads the specified file.
* @param filename The file to read into memory.
*/
FileReader(const std::string& filename);
/** Loads a text file from disk.
* @param filename The file to read into memory.
* @throw CoreException The file can not be loaded.
*/
void Load(const std::string& filename);
/** Retrieves the entire contents of the file cache as a single string.
*/
std::string GetString();
/** Retrieves the entire contents of the file cache as a vector of strings.
*/
const std::vector<std::string>& GetVector() { return lines; }
unsigned long TotalSize() { return totalSize; }
};
/** A list of modules
*/
typedef std::vector<Module*> IntModuleList;

View File

@ -75,15 +75,13 @@ CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, Use
// Rehash for me. Try to start the rehash thread
if (!ServerInstance->ConfigThread)
{
std::string m = user->nick + " is rehashing config file " + ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()) + " on " + ServerInstance->Config->ServerName;
std::string m = user->nick + " is rehashing config file " + FileSystem::GetFileName(ServerInstance->ConfigFileName) + " on " + ServerInstance->Config->ServerName;
ServerInstance->SNO->WriteGlobalSno('a', m);
if (IS_LOCAL(user))
user->WriteNumeric(RPL_REHASHING, "%s :Rehashing",
ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()));
user->WriteNumeric(RPL_REHASHING, "%s :Rehashing", FileSystem::GetFileName(ServerInstance->ConfigFileName).c_str());
else
ServerInstance->PI->SendUserNotice(user, std::string("*** Rehashing server ") +
ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()));
ServerInstance->PI->SendUserNotice(user, "*** Rehashing server " + FileSystem::GetFileName(ServerInstance->ConfigFileName));
/* Don't do anything with the logs here -- logs are restarted
* after the config thread has completed.

View File

@ -734,11 +734,6 @@ void ServerConfig::ApplyModules(User* user)
}
}
bool ServerConfig::StartsWithWindowsDriveLetter(const std::string &path)
{
return (path.length() > 2 && isalpha(path[0]) && path[1] == ':');
}
ConfigTag* ServerConfig::ConfValue(const std::string &tag)
{
ConfigTagList found = config_data.equal_range(tag);
@ -757,18 +752,6 @@ ConfigTagList ServerConfig::ConfTags(const std::string& tag)
return config_data.equal_range(tag);
}
bool ServerConfig::FileExists(const char* file)
{
struct stat sb;
if (stat(file, &sb) == -1)
return false;
if ((sb.st_mode & S_IFDIR) > 0)
return false;
return !access(file, F_OK);
}
std::string ServerConfig::Escape(const std::string& str, bool xml)
{
std::string escaped;
@ -793,22 +776,6 @@ std::string ServerConfig::Escape(const std::string& str, bool xml)
return escaped;
}
std::string ServerConfig::ExpandPath(const std::string& base, const std::string& fragment)
{
// The fragment is an absolute path, don't modify it.
if (fragment[0] == '/' || ServerConfig::StartsWithWindowsDriveLetter(fragment))
return fragment;
return base + '/' + fragment;
}
const char* ServerConfig::CleanFilename(const char* name)
{
const char* p = name + strlen(name);
while ((p != name) && (*p != '/') && (*p != '\\')) p--;
return (p != name ? ++p : p);
}
void ConfigReaderThread::Run()
{
Config->Read();

102
src/fileutils.cpp Normal file
View File

@ -0,0 +1,102 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2013 Peter Powell <petpow@saberuk.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "inspircd.h"
#include <fstream>
FileReader::FileReader(const std::string& filename)
{
Load(filename);
}
void FileReader::Load(const std::string& filename)
{
// If the file is stored in the file cache then we used that version instead.
std::string realName = ServerInstance->Config->Paths.PrependConfig(filename);
ConfigFileCache::iterator it = ServerInstance->Config->Files.find(realName);
if (it != ServerInstance->Config->Files.end())
{
this->lines = it->second;
}
else
{
lines.clear();
std::ifstream stream(realName.c_str());
if (!stream.is_open())
throw CoreException(filename + " does not exist or is not readable!");
std::string line;
while (std::getline(stream, line))
{
lines.push_back(line);
totalSize += line.size() + 2;
}
stream.close();
}
}
std::string FileReader::GetString() const
{
std::string buffer;
for (file_cache::const_iterator it = this->lines.begin(); it != this->lines.end(); ++it)
{
buffer.append(*it);
buffer.append("\r\n");
}
return buffer;
}
std::string FileSystem::ExpandPath(const std::string& base, const std::string& fragment)
{
// The fragment is an absolute path, don't modify it.
if (fragment[0] == '/' || FileSystem::StartsWithWindowsDriveLetter(fragment))
return fragment;
return base + '/' + fragment;
}
bool FileSystem::FileExists(const std::string& file)
{
struct stat sb;
if (stat(file.c_str(), &sb) == -1)
return false;
if ((sb.st_mode & S_IFDIR) > 0)
return false;
return !access(file.c_str(), F_OK);
}
std::string FileSystem::GetFileName(const std::string& name)
{
#ifdef _WIN32
size_t pos = name.find_last_of("\\/");
#else
size_t pos = name.rfind('/');
#endif
return pos == std::string::npos ? name : name.substr(++pos);
}
bool FileSystem::StartsWithWindowsDriveLetter(const std::string& path)
{
return (path.length() > 2 && isalpha(path[0]) && path[1] == ':');
}

View File

@ -380,14 +380,14 @@ InspIRCd::InspIRCd(int argc, char** argv) :
Logs->AddLogTypes("*", fls, true);
}
if (!ServerConfig::FileExists(ConfigFileName.c_str()))
if (!FileSystem::FileExists(ConfigFileName))
{
#ifdef _WIN32
/* Windows can (and defaults to) hide file extensions, so let's play a bit nice for windows users. */
std::string txtconf = this->ConfigFileName;
txtconf.append(".txt");
if (ServerConfig::FileExists(txtconf.c_str()))
if (FileSystem::FileExists(txtconf))
{
ConfigFileName = txtconf;
}

View File

@ -39,7 +39,7 @@ bool ModuleManager::Load(const std::string& filename, bool defer)
const std::string moduleFile = ServerInstance->Config->Paths.PrependModule(filename);
if (!ServerConfig::FileExists(moduleFile.c_str()))
if (!FileSystem::FileExists(moduleFile))
{
LastModuleError = "Module file could not be found: " + filename;
ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);

View File

@ -25,7 +25,6 @@
#include <iostream>
#include <fstream>
#include "inspircd.h"
#include "xline.h"
#include "socket.h"
@ -708,47 +707,3 @@ Module* ModuleManager::Find(const std::string &name)
else
return modfind->second;
}
FileReader::FileReader(const std::string& filename)
{
Load(filename);
}
void FileReader::Load(const std::string& filename)
{
// If the file is stored in the file cache then we used that version instead.
std::string realName = ServerInstance->Config->Paths.PrependConfig(filename);
ConfigFileCache::iterator it = ServerInstance->Config->Files.find(realName);
if (it != ServerInstance->Config->Files.end())
{
this->lines = it->second;
}
else
{
lines.clear();
std::ifstream stream(realName.c_str());
if (!stream.is_open())
throw CoreException(filename + " does not exist or is not readable!");
std::string line;
while (std::getline(stream, line))
{
lines.push_back(line);
totalSize += line.size() + 2;
}
stream.close();
}
}
std::string FileReader::GetString()
{
std::string buffer;
for (file_cache::iterator it = this->lines.begin(); it != this->lines.end(); ++it)
{
buffer.append(*it);
buffer.append("\r\n");
}
return buffer;
}

View File

@ -156,7 +156,7 @@ class ModuleXLineDB : public Module
bool ReadDatabase()
{
// If the xline database doesn't exist then we don't need to load it.
if (!ServerConfig::FileExists(xlinedbpath.c_str()))
if (!FileSystem::FileExists(xlinedbpath))
return true;
std::ifstream stream(xlinedbpath.c_str());

View File

@ -337,3 +337,71 @@ bool UserManager::AllModulesReportReady(LocalUser* user)
FIRST_MOD_RESULT(OnCheckReady, res, (user));
return (res == MOD_RES_PASSTHRU);
}
/**
* This function is called once a second from the mainloop.
* It is intended to do background checking on all the user structs, e.g.
* stuff like ping checks, registration timeouts, etc.
*/
void UserManager::DoBackgroundUserStuff()
{
/*
* loop over all local users..
*/
for (LocalUserList::iterator i = local_users.begin(); i != local_users.end(); ++i)
{
LocalUser* curr = *i;
if (curr->quitting)
continue;
if (curr->CommandFloodPenalty || curr->eh.getSendQSize())
{
unsigned int rate = curr->MyClass->GetCommandRate();
if (curr->CommandFloodPenalty > rate)
curr->CommandFloodPenalty -= rate;
else
curr->CommandFloodPenalty = 0;
curr->eh.OnDataReady();
}
switch (curr->registered)
{
case REG_ALL:
if (ServerInstance->Time() > curr->nping)
{
// This user didn't answer the last ping, remove them
if (!curr->lastping)
{
time_t time = ServerInstance->Time() - (curr->nping - curr->MyClass->GetPingTime());
const std::string message = "Ping timeout: " + ConvToStr(time) + (time == 1 ? " seconds" : " second");
this->QuitUser(curr, message);
continue;
}
curr->Write("PING :" + ServerInstance->Config->ServerName);
curr->lastping = 0;
curr->nping = ServerInstance->Time() + curr->MyClass->GetPingTime();
}
break;
case REG_NICKUSER:
if (AllModulesReportReady(curr))
{
/* User has sent NICK/USER, modules are okay, DNS finished. */
curr->FullConnect();
continue;
}
break;
}
if (curr->registered != REG_ALL && (ServerInstance->Time() > (curr->age + curr->MyClass->GetRegTimeout())))
{
/*
* registration timeout -- didnt send USER/NICK/HOST
* in the time specified in their connection class.
*/
this->QuitUser(curr, "Registration timeout");
continue;
}
}
}

View File

@ -1,95 +0,0 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
* Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
* Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc>
* Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
* Copyright (C) 2006 Craig McLure <craig@chatspike.net>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "inspircd.h"
#include "xline.h"
#include "socketengine.h"
#include "command_parse.h"
/**
* This function is called once a second from the mainloop.
* It is intended to do background checking on all the user structs, e.g.
* stuff like ping checks, registration timeouts, etc.
*/
void UserManager::DoBackgroundUserStuff()
{
/*
* loop over all local users..
*/
for (LocalUserList::iterator i = local_users.begin(); i != local_users.end(); ++i)
{
LocalUser* curr = *i;
if (curr->quitting)
continue;
if (curr->CommandFloodPenalty || curr->eh.getSendQSize())
{
unsigned int rate = curr->MyClass->GetCommandRate();
if (curr->CommandFloodPenalty > rate)
curr->CommandFloodPenalty -= rate;
else
curr->CommandFloodPenalty = 0;
curr->eh.OnDataReady();
}
switch (curr->registered)
{
case REG_ALL:
if (ServerInstance->Time() > curr->nping)
{
// This user didn't answer the last ping, remove them
if (!curr->lastping)
{
time_t time = ServerInstance->Time() - (curr->nping - curr->MyClass->GetPingTime());
const std::string message = "Ping timeout: " + ConvToStr(time) + (time == 1 ? " seconds" : " second");
this->QuitUser(curr, message);
continue;
}
curr->Write("PING :" + ServerInstance->Config->ServerName);
curr->lastping = 0;
curr->nping = ServerInstance->Time() + curr->MyClass->GetPingTime();
}
break;
case REG_NICKUSER:
if (AllModulesReportReady(curr))
{
/* User has sent NICK/USER, modules are okay, DNS finished. */
curr->FullConnect();
continue;
}
break;
}
if (curr->registered != REG_ALL && (ServerInstance->Time() > (curr->age + curr->MyClass->GetRegTimeout())))
{
/*
* registration timeout -- didnt send USER/NICK/HOST
* in the time specified in their connection class.
*/
this->QuitUser(curr, "Registration timeout");
continue;
}
}
}