add upstream source (adch++ 2.12.1 from sourceforge)

This commit is contained in:
2020-03-22 01:45:29 -07:00
parent 3574617350
commit 2cfbcf1301
9637 changed files with 1934407 additions and 0 deletions

263
src/adchpp/AdcCommand.cpp Normal file
View File

@@ -0,0 +1,263 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "AdcCommand.h"
#include "Text.h"
namespace adchpp {
#ifdef __GNUC__ /// @todo go figure why some GCCs need these...
const char AdcCommand::TYPE_BROADCAST;
const char AdcCommand::TYPE_CLIENT;
const char AdcCommand::TYPE_DIRECT;
const char AdcCommand::TYPE_ECHO;
const char AdcCommand::TYPE_FEATURE;
const char AdcCommand::TYPE_INFO;
const char AdcCommand::TYPE_HUB;
const char AdcCommand::TYPE_UDP;
#endif
using namespace std;
AdcCommand::AdcCommand() : cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(TYPE_INFO) { }
AdcCommand::AdcCommand(Severity sev, Error err, const string& desc, char aType /* = TYPE_INFO */) : cmdInt(CMD_STA), priority(PRIORITY_NORMAL), from(HUB_SID), to(INVALID_SID), type(aType) {
addParam(Util::toString(sev * 100 + err));
addParam(desc);
}
void AdcCommand::escape(const string& s, string& out) {
out.reserve(out.length() + static_cast<size_t>(s.length() * 1.1));
for(string::const_iterator i = s.begin(), iend = s.end(); i != iend; ++i) {
switch(*i) {
case ' ': out += '\\'; out += 's'; break;
case '\n': out += '\\'; out += 'n'; break;
case '\\': out += '\\'; out += '\\'; break;
default: out += *i;
}
}
}
void AdcCommand::parse(const char* buf, size_t len) throw(ParseException) {
if(len < 5) {
throw ParseException("Command too short");
}
type = buf[0];
if(type != TYPE_BROADCAST && type != TYPE_CLIENT && type != TYPE_DIRECT && type != TYPE_ECHO && type != TYPE_FEATURE && type != TYPE_INFO && type != TYPE_HUB && type != TYPE_UDP) {
throw ParseException("Invalid type");
}
if(type == TYPE_HUB) {
to = HUB_SID;
}
cmd[0] = buf[1];
cmd[1] = buf[2];
cmd[2] = buf[3];
if(buf[4] != ' ') {
throw ParseException("Missing space after command");
}
// Skip trailing LF
len--;
parameters.reserve(8);
string cur;
cur.reserve(64);
bool toSet = false;
bool featureSet = false;
bool fromSet = false;
string::size_type i = 5;
while(i < len) {
switch(buf[i]) {
case '\\':
++i;
if(i == len)
throw ParseException("Escape at eol");
if(buf[i] == 's')
cur += ' ';
else if(buf[i] == 'n')
cur += '\n';
else if(buf[i] == '\\')
cur += '\\';
else
throw ParseException("Unknown escape");
break;
case ' ':
// New parameter...
{
if((type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) && !fromSet) {
if(cur.length() != 4) {
throw ParseException("Invalid SID length");
}
from = toSID(cur);
fromSet = true;
} else if((type == TYPE_DIRECT || type == TYPE_ECHO) && !toSet) {
if(cur.length() != 4) {
throw ParseException("Invalid SID length");
}
to = toSID(cur);
toSet = true;
} else if(type == TYPE_FEATURE && !featureSet) {
if(cur.length() % 5 != 0) {
throw ParseException("Invalid feature length");
}
features = cur;
featureSet = true;
} else {
if(!Text::validateUtf8(cur)) {
throw ParseException("Invalid UTF-8 sequence");
}
parameters.push_back(cur);
}
cur.clear();
}
break;
default:
cur += buf[i];
}
++i;
}
if(!cur.empty()) {
if((type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) && !fromSet) {
if(cur.length() != 4) {
throw ParseException("Invalid SID length");
}
from = toSID(cur);
fromSet = true;
} else if((type == TYPE_DIRECT || type == TYPE_ECHO) && !toSet) {
if(cur.length() != 4) {
throw ParseException("Invalid SID length");
}
to = toSID(cur);
toSet = true;
} else if(type == TYPE_FEATURE && !featureSet) {
if(cur.length() % 5 != 0) {
throw ParseException("Invalid feature length");
}
features = cur;
featureSet = true;
} else {
if(!Text::validateUtf8(cur)) {
throw ParseException("Invalid UTF-8 sequence");
}
parameters.push_back(cur);
}
}
if((type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) && !fromSet) {
throw ParseException("Missing from_sid");
}
if(type == TYPE_FEATURE && !featureSet) {
throw ParseException("Missing feature");
}
if((type == TYPE_DIRECT || type == TYPE_ECHO) && !toSet) {
throw ParseException("Missing to_sid");
}
}
const BufferPtr& AdcCommand::getBuffer() const {
if(!buffer) {
buffer = make_shared<Buffer>(toString());
}
return buffer;
}
string AdcCommand::toString() const {
if(buffer) {
return string((char*)buffer->data(), buffer->size());
}
string tmp;
tmp.reserve(128);
tmp += type;
tmp += cmdChar;
if(type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) {
tmp += ' ';
appendSID(tmp, from);
}
if(type == TYPE_DIRECT || type == TYPE_ECHO) {
tmp += ' ';
appendSID(tmp, to);
}
if(type == TYPE_FEATURE) {
tmp += ' ';
tmp += features;
}
for(StringIterC i = getParameters().begin(); i != getParameters().end(); ++i) {
tmp += ' ';
escape(*i, tmp);
}
tmp += '\n';
return tmp;
}
bool AdcCommand::getParam(const char* name, size_t start, string& ret) const {
for(string::size_type i = start; i < getParameters().size(); ++i) {
if(toField(name) == toField(getParameters()[i].c_str())) {
ret = getParameters()[i].substr(2);
return true;
}
}
return false;
}
bool AdcCommand::delParam(const char* name, size_t start) {
for(string::size_type i = start; i < getParameters().size(); ++i) {
if(toField(name) == toField(getParameters()[i].c_str())) {
getParameters().erase(getParameters().begin() + i);
resetBuffer();
return true;
}
}
return false;
}
bool AdcCommand::hasFlag(const char* name, size_t start) const {
for(string::size_type i = start; i < getParameters().size(); ++i) {
if(toField(name) == toField(getParameters()[i].c_str()) &&
getParameters()[i].size() == 3 &&
getParameters()[i][2] == '1')
{
return true;
}
}
return false;
}
}

238
src/adchpp/AdcCommand.h Normal file
View File

@@ -0,0 +1,238 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_ADC_COMMAND_H
#define ADCHPP_ADC_COMMAND_H
#include "common.h"
#include "Exception.h"
#include "Util.h"
#include "Buffer.h"
namespace adchpp {
STANDARD_EXCEPTION(ParseException);
class AdcCommand : private boost::noncopyable {
public:
template<uint32_t T>
struct Type {
enum { CMD = T };
};
enum Error {
ERROR_GENERIC = 0,
ERROR_HUB_GENERIC = 10,
ERROR_HUB_FULL = 11,
ERROR_HUB_DISABLED = 12,
ERROR_LOGIN_GENERIC = 20,
ERROR_NICK_INVALID = 21,
ERROR_NICK_TAKEN = 22,
ERROR_BAD_PASSWORD = 23,
ERROR_CID_TAKEN = 24,
ERROR_COMMAND_ACCESS = 25,
ERROR_REGGED_ONLY = 26,
ERROR_INVALID_PID = 27,
ERROR_BANNED_GENERIC = 30,
ERROR_PERM_BANNED = 31,
ERROR_TEMP_BANNED = 32,
ERROR_PROTOCOL_GENERIC = 40,
ERROR_PROTOCOL_UNSUPPORTED = 41,
ERROR_CONNECT_FAILED = 42,
ERROR_INF_MISSING = 43,
ERROR_BAD_STATE = 44,
ERROR_FEATURE_MISSING = 45,
ERROR_BAD_IP = 46,
ERROR_NO_HUB_HASH = 47,
ERROR_TRANSFER_GENERIC = 50,
ERROR_FILE_NOT_AVAILABLE = 51,
ERROR_FILE_PART_NOT_AVAILABLE = 52,
ERROR_SLOTS_FULL = 53,
ERROR_NO_CLIENT_HASH = 54
};
enum Severity {
SEV_SUCCESS = 0,
SEV_RECOVERABLE = 1,
SEV_FATAL = 2
};
enum Priority {
PRIORITY_NORMAL, ///< Default priority, command will be sent out normally
PRIORITY_LOW, ///< Low priority, command will only be sent if connection isn't saturated
PRIORITY_IGNORE ///< Ignore, command will not be put in send queue
};
static const char TYPE_BROADCAST = 'B';
static const char TYPE_CLIENT = 'C';
static const char TYPE_DIRECT = 'D';
static const char TYPE_ECHO = 'E';
static const char TYPE_FEATURE = 'F';
static const char TYPE_INFO = 'I';
static const char TYPE_HUB = 'H';
static const char TYPE_UDP = 'U';
// Known commands...
#define C(n, a, b, c) static const uint32_t CMD_##n = (((uint32_t)a) | (((uint32_t)b)<<8) | (((uint32_t)c)<<16)); typedef Type<CMD_##n> n
// Base commands
C(SUP, 'S','U','P');
C(STA, 'S','T','A');
C(INF, 'I','N','F');
C(MSG, 'M','S','G');
C(SCH, 'S','C','H');
C(RES, 'R','E','S');
C(CTM, 'C','T','M');
C(RCM, 'R','C','M');
C(GPA, 'G','P','A');
C(PAS, 'P','A','S');
C(QUI, 'Q','U','I');
C(GET, 'G','E','T');
C(GFI, 'G','F','I');
C(SND, 'S','N','D');
C(SID, 'S','I','D');
// Extensions
C(CMD, 'C','M','D');
C(NAT, 'N','A','T');
C(RNT, 'R','N','T');
#undef C
static const uint32_t HUB_SID = static_cast<uint32_t>(-1);
static const uint32_t INVALID_SID = static_cast<uint32_t>(-2);
static uint32_t toSID(const std::string& aSID) { return *reinterpret_cast<const uint32_t*>(aSID.data()); }
static std::string fromSID(const uint32_t aSID) { return std::string(reinterpret_cast<const char*>(&aSID), sizeof(aSID)); }
static void appendSID(std::string& str, uint32_t aSID) { str.append(reinterpret_cast<const char*>(&aSID), sizeof(aSID)); }
static uint32_t toCMD(uint8_t a, uint8_t b, uint8_t c) { return (((uint32_t)a) | (((uint32_t)b)<<8) | (((uint32_t)c)<<16)); }
static uint32_t toCMD(const char* str) { return toCMD(str[0], str[1], str[2]); }
static uint16_t toField(const char* x) { return *((uint16_t*)x); }
static std::string fromField(const uint16_t aField) { return std::string(reinterpret_cast<const char*>(&aField), sizeof(aField)); }
static uint32_t toFourCC(const char* x) { return *reinterpret_cast<const uint32_t*>(x); }
static std::string fromFourCC(uint32_t x) { return std::string(reinterpret_cast<const char*>(&x), sizeof(x)); }
ADCHPP_DLL AdcCommand();
ADCHPP_DLL explicit AdcCommand(Severity sev, Error err, const std::string& desc, char aType = TYPE_INFO);
explicit AdcCommand(uint32_t cmd, char aType = TYPE_INFO, uint32_t aFrom = HUB_SID) : cmdInt(cmd), priority(PRIORITY_NORMAL), from(aFrom), to(INVALID_SID), type(aType) { }
explicit AdcCommand(const std::string& aLine) throw(ParseException) : cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(0) { parse(aLine); }
explicit AdcCommand(const BufferPtr& buffer_) throw(ParseException) : buffer(buffer_), cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(0) { parse((const char*)buffer->data(), buffer->size()); }
void parse(const std::string& str) throw(ParseException) { parse(str.data(), str.size()); }
ADCHPP_DLL void parse(const char* buf, size_t len) throw(ParseException);
uint32_t getCommand() const { return cmdInt; }
char getType() const { return type; }
std::string getFourCC() const { std::string tmp(4, 0); tmp[0] = type; tmp[1] = cmd[0]; tmp[2] = cmd[1]; tmp[3] = cmd[2]; return tmp; }
StringList& getParameters() { return parameters; }
const StringList& getParameters() const { return parameters; }
ADCHPP_DLL std::string toString() const;
AdcCommand& addParam(const std::string& param) {
parameters.push_back(param);
resetBuffer();
return *this;
}
AdcCommand& addParam(const std::string& name, const std::string& value) {
return addParam(name + value);
}
const std::string& getParam(size_t n) const {
return getParameters().size() > n ? getParameters()[n] : Util::emptyString;
}
void resetBuffer() { buffer.reset(); }
const std::string& getFeatures() const { return features; }
/** Return a named parameter where the name is a two-letter code */
ADCHPP_DLL bool getParam(const char* name, size_t start, std::string& ret) const;
ADCHPP_DLL bool delParam(const char* name, size_t start);
ADCHPP_DLL bool hasFlag(const char* name, size_t start) const;
bool operator==(uint32_t aCmd) const { return cmdInt == aCmd; }
ADCHPP_DLL static void escape(const std::string& s, std::string& out);
ADCHPP_DLL const BufferPtr& getBuffer() const;
uint32_t getTo() const { return to; }
void setTo(uint32_t aTo) { to = aTo; }
uint32_t getFrom() const { return from; }
void setFrom(uint32_t aFrom) { from = aFrom; }
Priority getPriority() const { return priority; }
void setPriority(Priority priority_) { priority = priority_; }
private:
StringList parameters;
std::string features;
mutable BufferPtr buffer;
union {
char cmdChar[4];
uint8_t cmd[4];
uint32_t cmdInt;
};
Priority priority;
uint32_t from;
uint32_t to;
char type;
};
class Client;
class Entity;
template<class T>
class CommandHandler {
public:
bool dispatch(Entity& c, AdcCommand& cmd) {
#define C(n) case AdcCommand::CMD_##n: return ((T*)this)->handle(AdcCommand::n(), c, cmd); break;
switch(cmd.getCommand()) {
C(SUP);
C(STA);
C(INF);
C(MSG);
C(SCH);
C(RES);
C(CTM);
C(RCM);
C(GPA);
C(PAS);
C(QUI);
C(GET);
C(GFI);
C(SND);
C(SID);
C(CMD);
C(NAT);
C(RNT);
default:
dcdebug("Unknown ADC command: %.50s\n", cmd.toString().c_str());
return true;
#undef C
}
}
};
}
#endif // ADC_COMMAND_H

43
src/adchpp/AsyncStream.h Normal file
View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <boost/system/error_code.hpp>
#include "Buffer.h"
namespace adchpp {
class AsyncStream : private boost::noncopyable {
public:
typedef std::function<void (const boost::system::error_code& ec, size_t)> Handler;
virtual size_t available() = 0;
virtual void init(const std::function<void ()>& postInit) = 0;
virtual void setOptions(size_t bufferSize) = 0;
virtual std::string getIp() = 0;
virtual void prepareRead(const BufferPtr& buf, const Handler& handler) = 0;
virtual size_t read(const BufferPtr& buf) = 0;
virtual void write(const BufferList& bufs, const Handler& handler) = 0;
virtual void shutdown(const Handler& handler) = 0;
virtual void close() = 0;
virtual ~AsyncStream() { }
};
typedef shared_ptr<AsyncStream> AsyncStreamPtr;
}

63
src/adchpp/Bot.cpp Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "Bot.h"
#include "ClientManager.h"
#include "SocketManager.h"
#include "Core.h"
namespace adchpp {
// TODO replace with lambda
struct BotRemover {
BotRemover(Bot* bot_,Util::Reason reason, const std::string &info) : bot(bot_), reason(reason), info(info) { }
void operator()() {
bot->die(reason, info);
}
Bot* bot;
Util::Reason reason;
std::string info;
};
Bot::Bot(ClientManager &cm, uint32_t sid, const Bot::SendHandler& handler_) : Entity(cm, sid), handler(handler_), disconnecting(false) {
setFlag(FLAG_BOT);
// Fake a CID, the script can change this if it wants to
setCID(CID::generate());
}
void Bot::disconnect(Util::Reason reason, const std::string &info) throw() {
if(!disconnecting) {
disconnecting = true;
handler = SendHandler();
cm.getCore().addJob(BotRemover(this, reason, info));
}
}
void Bot::die(Util::Reason reason, const std::string &info) {
cm.removeEntity(*this, reason, info);
delete this;
}
}

52
src/adchpp/Bot.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef BOT_H_
#define BOT_H_
#include "forward.h"
#include "Entity.h"
namespace adchpp {
struct BotRemover;
class ADCHPP_VISIBLE Bot : public Entity {
public:
typedef std::function<void (Bot& bot, const BufferPtr& cmd)> SendHandler;
ADCHPP_DLL Bot(ClientManager &cm, uint32_t sid, const SendHandler& handler_);
virtual void send(const BufferPtr& cmd) { if(handler) handler(*this, cmd); }
ADCHPP_DLL virtual void disconnect(Util::Reason reason, const std::string &info) throw();
using Entity::send;
private:
friend struct BotRemover;
SendHandler handler;
bool disconnecting;
void die(Util::Reason reason, const std::string &info);
};
}
#endif /* BOT_H_ */

37
src/adchpp/Buffer.cpp Normal file
View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "Buffer.h"
namespace adchpp {
size_t Buffer::defaultBufferSize = 128;
SimplePool<ByteVector, Buffer::Clear> Buffer::pool;
void Buffer::Clear::operator()(ByteVector& v) {
if(v.capacity() > static_cast<size_t>(getDefaultBufferSize())) {
ByteVector().swap(v);
} else {
v.clear();
}
}
}

77
src/adchpp/Buffer.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef BUFFER_H_
#define BUFFER_H_
#include "Pool.h"
#include "FastAlloc.h"
namespace adchpp {
/**
* Reference-counted buffer
*/
class Buffer :
public FastAlloc<Buffer>,
private boost::noncopyable
{
public:
Buffer(const std::string& str) : bufp(pool.get()) { append((uint8_t*)str.data(), (uint8_t*)str.data() + str.size()); }
Buffer(const void* ptr, const size_t size) : bufp(pool.get()) { append((uint8_t*) ptr, ((uint8_t*)ptr)+size); }
Buffer(const size_t size) : bufp(pool.get()) { resize(size); }
operator const ByteVector&() const { return buf(); }
operator ByteVector&() { return buf(); }
void resize(size_t new_size) { buf().resize(new_size); }
size_t size() const { return buf().size(); }
const uint8_t* data() const { return &buf()[0]; }
uint8_t* data() { return &buf()[0]; }
/** Erase the first n bytes */
void erase_first(size_t n) { buf().erase(buf().begin(), buf().begin() + n); }
template<typename InputIterator>
void append(InputIterator start, InputIterator end) { buf().insert(buf().end(), start, end); }
static void setDefaultBufferSize(size_t newSize) { defaultBufferSize = newSize; }
static size_t getDefaultBufferSize() { return defaultBufferSize; }
virtual ~Buffer() { pool.put(bufp); }
private:
static size_t defaultBufferSize;
const ByteVector& buf() const { return *bufp; }
ByteVector& buf() { return *bufp; }
ByteVector* bufp;
struct Clear {
ADCHPP_DLL void operator()(ByteVector& x);
};
ADCHPP_DLL static SimplePool<ByteVector, Clear> pool;
};
typedef shared_ptr<Buffer> BufferPtr;
typedef std::vector<BufferPtr> BufferList;
}
#endif /*BUFFER_H_*/

76
src/adchpp/CID.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_CID_H
#define ADCHPP_CID_H
#include "Util.h"
#include "Encoder.h"
namespace adchpp {
class CID {
public:
enum { SIZE = 192 / 8 };
enum { BASE32_SIZE = 39 };
CID() { memset(cid, 0, sizeof(cid)); }
explicit CID(const uint8_t* data) { memcpy(cid, data, sizeof(cid)); }
explicit CID(const std::string& base32) { Encoder::fromBase32(base32.c_str(), cid, sizeof(cid)); }
CID(const CID& rhs) { memcpy(cid, rhs.cid, sizeof(cid)); }
CID& operator=(const CID& rhs) { memcpy(cid, rhs.cid, sizeof(cid)); return *this; }
bool operator==(const CID& rhs) const { return memcmp(cid, rhs.cid, sizeof(cid)) == 0; }
bool operator<(const CID& rhs) const { return memcmp(cid, rhs.cid, sizeof(cid)) < 0; }
std::string toBase32() const { return Encoder::toBase32(cid, sizeof(cid)); }
std::string& toBase32(std::string& tmp) const { return Encoder::toBase32(cid, sizeof(cid), tmp); }
size_t toHash() const { static_assert(sizeof(cid) >= sizeof(cidHash), "cid too small, cidHash invalid"); return cidHash; }
const uint8_t* data() const { return cid; }
bool isZero() const { return std::find_if(cid, cid+SIZE, std::bind2nd(std::not_equal_to<uint8_t>(), 0)) == (cid+SIZE); }
static CID generate() {
uint8_t data[CID::SIZE];
for(size_t i = 0; i < sizeof(data); ++i) {
data[i] = (uint8_t)Util::rand();
}
return CID(data);
}
private:
union {
uint8_t cid[SIZE];
size_t cidHash;
};
};
}
namespace std {
template<>
struct hash<adchpp::CID> {
size_t operator()(const adchpp::CID& cid) const {
return cid.toHash();
}
};
}
#endif

174
src/adchpp/Client.cpp Normal file
View File

@@ -0,0 +1,174 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "Client.h"
#include "ClientManager.h"
#include "TimeUtil.h"
#include "SocketManager.h"
#include "Core.h"
namespace adchpp {
using namespace std;
using namespace std::placeholders;
Client* Client::create(ClientManager &cm, const ManagedSocketPtr& ms, uint32_t sid) throw() {
Client* c = new Client(cm, sid);
c->setSocket(ms);
return c;
}
Client::Client(ClientManager &cm, uint32_t sid_) throw() :
Entity(cm, sid_),
disconnecting(false),
dataBytes(0)
{
}
Client::~Client() {
}
namespace {
// Lightweight call forwarders, instead of std::bind
template<void (Client::*F)()>
struct Handler0 {
Handler0(Client* c_) : c(c_) { }
void operator()() { (c->*F)(); }
Client* c;
};
template<typename T, void (Client::*F)(const T&)>
struct Handler1 {
Handler1(Client* c_) : c(c_) { }
void operator()(const T& bv) { (c->*F)(bv); }
Client* c;
};
template<typename T, typename T2, void (Client::*F)(T, const T2&)>
struct Handler2 {
Handler2(Client* c_) : c(c_) { }
void operator()(const T& t, const T2& t2) { (c->*F)(t, t2); }
Client* c;
};
}
void Client::setSocket(const ManagedSocketPtr& aSocket) throw() {
dcassert(!socket);
socket = aSocket;
socket->setConnectedHandler(Handler0<&Client::onConnected>(this));
socket->setReadyHandler(Handler0<&Client::onReady>(this));
socket->setDataHandler(Handler1<BufferPtr, &Client::onData>(this));
socket->setFailedHandler(Handler2<Util::Reason, std::string, &Client::onFailed>(this));
}
void Client::onConnected() throw() {
cm.onConnected(*this);
}
void Client::onReady() throw() {
cm.onReady(*this);
}
void Client::onData(const BufferPtr& buf) throw() {
uint8_t* data = buf->data();
size_t done = 0;
size_t len = buf->size();
while(!disconnecting && done < len) {
if(dataBytes > 0) {
size_t n = (size_t)min(dataBytes, (int64_t)(len - done));
dataHandler(*this, data + done, n);
dataBytes -= n;
done += n;
} else {
size_t j = done;
while(j < len && data[j] != '\n')
++j;
if(j == len) {
if(!buffer) {
if(done == 0) {
buffer = buf;
} else {
buffer = make_shared<Buffer>(data + done, len - done);
}
} else {
buffer->append(data + done, data + len);
}
return;
} else if(!buffer) {
if(done == 0 && j == len-1) {
buffer = buf;
} else {
buffer = make_shared<Buffer>(data + done, j - done + 1);
}
} else {
buffer->append(data + done, data + j + 1);
}
done = j + 1;
if(cm.getMaxCommandSize() > 0 && buffer->size() > cm.getMaxCommandSize()) {
send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC, "Command too long"));
disconnect(Util::REASON_MAX_COMMAND_SIZE);
return;
}
if(buffer->size() == 1) {
buffer.reset();
continue;
}
try {
AdcCommand cmd(buffer);
if(cmd.getType() == 'H') {
cmd.setFrom(getSID());
} else if(cmd.getFrom() != getSID()) {
disconnect(Util::REASON_INVALID_SID);
return;
}
cm.onReceive(*this, cmd);
} catch(const ParseException&) {
cm.onBadLine(*this, string((char*)buffer->data(), buffer->size()));
}
buffer.reset();
}
}
}
void Client::disconnect(Util::Reason reason, const std::string &info) throw() {
dcassert(socket);
if(!disconnecting) {
dcdebug("%s disconnecting because %d\n", AdcCommand::fromSID(getSID()).c_str(), reason);
disconnecting = true;
socket->disconnect(reason, info);
}
}
void Client::onFailed(Util::Reason reason, const std::string &info) throw() {
cm.onFailed(*this, reason, info);
delete this;
}
}

79
src/adchpp/Client.h Normal file
View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_CLIENT_H
#define ADCHPP_CLIENT_H
#include "common.h"
#include "ManagedSocket.h"
#include "FastAlloc.h"
#include "AdcCommand.h"
#include "CID.h"
#include "Entity.h"
namespace adchpp {
/**
* The client represents one connection to a user.
*/
class ADCHPP_VISIBLE Client : public Entity, public FastAlloc<Client> {
public:
static Client* create(ClientManager &cm, const ManagedSocketPtr& ms_, uint32_t sid_) throw();
using Entity::send;
virtual void send(const BufferPtr& command) { socket->write(command); }
/** @param reason The statistic to update */
ADCHPP_DLL virtual void disconnect(Util::Reason reason, const std::string &info = Util::emptyString) throw();
const std::string& getIp() const throw() { return socket->getIp(); }
/**
* Set data mode for aBytes bytes.
* May only be called from on(ClientListener::Command...).
*/
typedef std::function<void (Client&, const uint8_t*, size_t)> DataFunction;
void setDataMode(const DataFunction& handler, int64_t aBytes) { dataHandler = handler; dataBytes = aBytes; }
virtual size_t getQueuedBytes() const { return socket->getQueuedBytes(); }
virtual time::ptime getOverflow() const { return socket->getOverflow(); }
private:
Client(ClientManager &cm, uint32_t sid_) throw();
virtual ~Client();
bool disconnecting;
BufferPtr buffer;
ManagedSocketPtr socket;
int64_t dataBytes;
DataFunction dataHandler;
void setSocket(const ManagedSocketPtr& aSocket) throw();
void onConnected() throw();
void onReady() throw();
void onData(const BufferPtr&) throw();
void onFailed(Util::Reason reason, const std::string &info) throw();
};
}
#endif // CLIENT_H

View File

@@ -0,0 +1,647 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "ClientManager.h"
#include "File.h"
#include "Client.h"
#include "LogManager.h"
#include "SocketManager.h"
#include "TigerHash.h"
#include "Encoder.h"
#include "version.h"
#include <boost/asio/ip/address.hpp>
#include <boost/asio/ip/address_v4.hpp>
#include <boost/asio/ip/address_v6.hpp>
#include <boost/locale.hpp>
namespace adchpp {
using namespace std;
const string ClientManager::className = "ClientManager";
ClientManager::ClientManager(Core &core) throw() :
core(core),
hub(*this),
maxCommandSize(16 * 1024),
logTimeout(30 * 1000)
{
hub.addSupports(AdcCommand::toFourCC("BASE"));
hub.addSupports(AdcCommand::toFourCC("TIGR"));
}
Bot* ClientManager::createBot(const Bot::SendHandler& handler) {
Bot* ret = new Bot(*this, makeSID(), handler);
return ret;
}
void ClientManager::regBot(Bot& bot) {
enterIdentify(bot, false);
enterNormal(bot, false, true);
cids.insert(make_pair(bot.getCID(), &bot));
nicks.insert(make_pair(bot.getField("NI"), &bot));
}
void ClientManager::send(const AdcCommand& cmd) throw() {
if(cmd.getPriority() == AdcCommand::PRIORITY_IGNORE) {
return;
}
bool all = false;
switch(cmd.getType()) {
case AdcCommand::TYPE_BROADCAST:
all = true; // Fallthrough
case AdcCommand::TYPE_FEATURE: {
for(EntityIter i = entities.begin(); i != entities.end(); ++i) {
if(all || !i->second->isFiltered(cmd.getFeatures())) {
maybeSend(*i->second, cmd);
}
}
}
break;
case AdcCommand::TYPE_DIRECT: // Fallthrough
case AdcCommand::TYPE_ECHO: {
Entity* e = getEntity(cmd.getTo());
if(e) {
maybeSend(*e, cmd);
if(cmd.getType() == AdcCommand::TYPE_ECHO) {
e = getEntity(cmd.getFrom());
if(e) {
maybeSend(*e, cmd);
}
}
}
}
break;
}
}
void ClientManager::maybeSend(Entity& c, const AdcCommand& cmd) {
bool ok = true;
signalSend_(c, cmd, ok);
if(ok) {
c.send(cmd);
}
}
void ClientManager::sendToAll(const BufferPtr& buf) throw() {
for(EntityIter i = entities.begin(); i != entities.end(); ++i) {
i->second->send(buf);
}
}
size_t ClientManager::getQueuedBytes() throw() {
size_t total = 0;
for(EntityIter i = entities.begin(); i != entities.end(); ++i) {
total += i->second->getQueuedBytes();
}
return total;
}
void ClientManager::sendTo(const BufferPtr& buffer, uint32_t to) {
EntityIter i = entities.find(to);
if(i != entities.end()) {
i->second->send(buffer);
}
}
void ClientManager::handleIncoming(const ManagedSocketPtr& socket) throw() {
Client::create(*this, socket, makeSID());
}
uint32_t ClientManager::makeSID() {
while(true) {
union {
uint32_t sid;
char chars[4];
} sid;
sid.chars[0] = Encoder::base32Alphabet[Util::rand(sizeof(Encoder::base32Alphabet))];
sid.chars[1] = Encoder::base32Alphabet[Util::rand(sizeof(Encoder::base32Alphabet))];
sid.chars[2] = Encoder::base32Alphabet[Util::rand(sizeof(Encoder::base32Alphabet))];
sid.chars[3] = Encoder::base32Alphabet[Util::rand(sizeof(Encoder::base32Alphabet))];
if(sid.sid != 0 && entities.find(sid.sid) == entities.end()) {
return sid.sid;
}
}
}
void ClientManager::onConnected(Client& c) throw() {
dcdebug("%s connected\n", AdcCommand::fromSID(c.getSID()).c_str());
// First let's check if any clients have passed the login timeout...
auto timeout = time::now() - time::millisec(getLogTimeout());
while(!logins.empty() && (timeout > logins.front().second)) {
Client* cc = logins.front().first;
dcdebug("ClientManager: Login timeout in state %d\n", cc->getState());
cc->disconnect(Util::REASON_LOGIN_TIMEOUT);
logins.pop_front();
}
logins.push_back(make_pair(&c, time::now()));
signalConnected_(c);
}
void ClientManager::onReady(Client& c) throw() {
dcdebug("%s ready\n", AdcCommand::fromSID(c.getSID()).c_str());
signalReady_(c);
}
void ClientManager::onReceive(Entity& c, AdcCommand& cmd) throw() {
if(c.isSet(Entity::FLAG_GHOST)) {
return;
}
if(!(cmd.getType() == AdcCommand::TYPE_BROADCAST || cmd.getType() == AdcCommand::TYPE_DIRECT || cmd.getType()
== AdcCommand::TYPE_ECHO || cmd.getType() == AdcCommand::TYPE_FEATURE || cmd.getType() == AdcCommand::TYPE_HUB))
{
disconnect(c, Util::REASON_INVALID_COMMAND_TYPE, "Invalid command type");
return;
}
bool ok = true;
signalReceive_(c, cmd, ok);
if(ok) {
if(!dispatch(c, cmd)) {
return;
}
}
send(cmd);
}
void ClientManager::onBadLine(Client& c, const string& aLine) throw() {
if(c.isSet(Entity::FLAG_GHOST)) {
return;
}
signalBadLine_(c, aLine);
}
void ClientManager::badState(Entity& c, const AdcCommand& cmd) throw() {
disconnect(c, Util::REASON_BAD_STATE, "Invalid state for command", AdcCommand::ERROR_BAD_STATE, "FC" + cmd.getFourCC());
}
bool ClientManager::handleDefault(Entity& c, AdcCommand& cmd) throw() {
if(c.getState() != Entity::STATE_NORMAL) {
badState(c, cmd);
return false;
}
return true;
}
bool ClientManager::handle(AdcCommand::SUP, Entity& c, AdcCommand& cmd) throw() {
if(!verifySUP(c, cmd)) {
return false;
}
if(c.getState() == Entity::STATE_PROTOCOL) {
enterIdentify(c, true);
} else if(c.getState() != Entity::STATE_NORMAL) {
badState(c, cmd);
return false;
}
return true;
}
bool ClientManager::verifySUP(Entity& c, AdcCommand& cmd) throw() {
c.updateSupports(cmd);
if(!c.hasSupport(AdcCommand::toFourCC("BASE"))) {
disconnect(c, Util::REASON_NO_BASE_SUPPORT, "This hub requires BASE support");
return false;
}
if(!c.hasSupport(AdcCommand::toFourCC("TIGR"))) {
disconnect(c, Util::REASON_NO_TIGR_SUPPORT, "This hub requires TIGR support");
return false;
}
return true;
}
bool ClientManager::verifyINF(Entity& c, AdcCommand& cmd) throw() {
Client* cc = dynamic_cast<Client*>(&c);
if(cc) {
if(!verifyIp(*cc, cmd))
return false;
}
if(!verifyCID(c, cmd))
return false;
if(!verifyNick(c, cmd))
return false;
if(cmd.getParam("DE", 0, strtmp)) {
if(!Util::validateCharset(strtmp, 32)) {
disconnect(c, Util::REASON_INVALID_DESCRIPTION, "Invalid character in description");
return false;
}
}
c.updateFields(cmd);
return true;
}
bool ClientManager::verifyPassword(Entity& c, const string& password, const ByteVector& salt,
const string& suppliedHash, TigerHash&& tiger) {
tiger.update(&password[0], password.size());
tiger.update(&salt[0], salt.size());
uint8_t tmp[TigerHash::BYTES];
Encoder::fromBase32(suppliedHash.c_str(), tmp, TigerHash::BYTES);
if(memcmp(tiger.finalize(), tmp, TigerHash::BYTES) == 0) {
return true;
}
return false;
}
bool ClientManager::verifyPassword(Entity& c, const string& password, const ByteVector& salt,
const string& suppliedHash) {
return verifyPassword(c, password, salt, suppliedHash, TigerHash());
}
bool ClientManager::verifyHashedPassword(Entity& c, const ByteVector& hashedPassword, int64_t hashedPasswordLen,
const ByteVector& salt, const string& suppliedHash) {
// hashedPassword must be in little-endian order; this code itself is endian-independent.
uint64_t initial_res[TigerHash::BYTES/8];
for (auto i = 0; i < 3; ++i) {
initial_res[i] = 0;
for (auto j = 0; j < 8; ++j)
initial_res[i] = initial_res[i] * 256 + hashedPassword[8*i+(7-j)];
}
return verifyPassword(c, "", salt, suppliedHash, TigerHash(hashedPasswordLen, initial_res));
}
bool ClientManager::verifyOverflow(Entity& c) {
size_t overflowing = 0;
for(EntityIter i = entities.begin(), iend = entities.end(); i != iend; ++i) {
if(!i->second->getOverflow().is_not_a_date_time()) {
overflowing++;
}
}
if(overflowing > 3 && overflowing > (entities.size() / 4)) {
disconnect(c, Util::REASON_NO_BANDWIDTH, "Not enough bandwidth available, please try again later", AdcCommand::ERROR_HUB_FULL);
return false;
}
return true;
}
bool ClientManager::handle(AdcCommand::INF, Entity& c, AdcCommand& cmd) throw() {
if(c.getState() != Entity::STATE_IDENTIFY && c.getState() != Entity::STATE_NORMAL) {
badState(c, cmd);
return false;
}
if(!verifyINF(c, cmd))
return false;
if(c.getState() == Entity::STATE_IDENTIFY) {
if(!verifyOverflow(c)) {
return false;
}
enterNormal(c, true, true);
return false;
}
return true;
}
bool ClientManager::verifyIp(Client& c, AdcCommand& cmd) throw() {
if(c.isSet(Entity::FLAG_OK_IP))
return true;
using namespace boost::asio::ip;
auto remote = address::from_string(c.getIp());
std::string ip;
if(remote.is_v4() || (remote.is_v6() && remote.to_v6().is_v4_mapped())) {
auto v4 = remote.is_v4() ? remote.to_v4() : remote.to_v6().to_v4();
if(cmd.getParam("I4", 0, ip)) {
dcdebug("%s verifying IP %s\n", AdcCommand::fromSID(c.getSID()).c_str(), ip.c_str());
if(ip.empty() || address_v4::from_string(ip) == address_v4::any()) {
cmd.delParam("I4", 0);
} else if(address_v4::from_string(ip) != v4 && !Util::isPrivateIp(c.getIp())) {
disconnect(c, Util::REASON_INVALID_IP, "Your IP is " + c.getIp() +
", reconfigure your client settings", AdcCommand::ERROR_BAD_IP, "IP" + c.getIp());
return false;
} else {
return true;
}
}
if(!c.hasField("I4")) {
c.setField("I4", v4.to_string());
}
if(c.getState() != Entity::STATE_NORMAL) {
cmd.addParam("I4", v4.to_string());
}
cmd.delParam("I6", 0); // We can't check this so we remove it instead...fix?
} else if(remote.is_v6()) {
if(cmd.getParam("I6", 0, ip)) {
dcdebug("%s verifying IPv6 %s\n", AdcCommand::fromSID(c.getSID()).c_str(), ip.c_str());
if(ip.empty() || address_v6::from_string(ip) == address_v6::any()) {
cmd.delParam("I6", 0);
} else if(address_v6::from_string(ip) != remote.to_v6() && !Util::isPrivateIp(c.getIp())) {
disconnect(c, Util::REASON_INVALID_IP, "Your IP is " + c.getIp() +
", reconfigure your client settings", AdcCommand::ERROR_BAD_IP, "IP" + c.getIp());
return false;
} else {
return true;
}
}
if(!c.hasField("I6")) {
c.setField("I6", c.getIp());
}
if(c.getState() != Entity::STATE_NORMAL) {
cmd.addParam("I6", c.getIp());
}
cmd.delParam("I4", 0); // We can't check this so we remove it instead...fix?
}
return true;
}
bool ClientManager::verifyCID(Entity& c, AdcCommand& cmd) throw() {
if(cmd.getParam("ID", 0, strtmp)) {
dcdebug("%s verifying CID %s\n", AdcCommand::fromSID(c.getSID()).c_str(), strtmp.c_str());
if(c.getState() != Entity::STATE_IDENTIFY) {
disconnect(c, Util::REASON_CID_CHANGE, "CID changes not allowed");
return false;
}
if(strtmp.size() != CID::BASE32_SIZE) {
disconnect(c, Util::REASON_PID_CID_LENGTH, "Invalid CID length");
return false;
}
CID cid(strtmp);
strtmp.clear();
if(!cmd.getParam("PD", 0, strtmp)) {
disconnect(c, Util::REASON_PID_MISSING, "PID missing", AdcCommand::ERROR_INF_MISSING, "FLPD");
return false;
}
if(strtmp.size() != CID::BASE32_SIZE) {
disconnect(c, Util::REASON_PID_CID_LENGTH, "Invalid PID length");
return false;
}
CID pid(strtmp);
TigerHash th;
th.update(pid.data(), CID::SIZE);
if(!(CID(th.finalize()) == cid)) {
disconnect(c, Util::REASON_PID_CID_MISMATCH, "PID does not correspond to CID", AdcCommand::ERROR_INVALID_PID);
return false;
}
auto other = cids.find(cid);
if(other != cids.end()) {
// disconnect the ghost
disconnect(*other->second, Util::REASON_CID_TAKEN, "CID taken", AdcCommand::ERROR_CID_TAKEN);
removeEntity(*other->second, Util::REASON_CID_TAKEN, Util::emptyString);
}
c.setCID(cid);
cids.insert(make_pair(c.getCID(), &c));
cmd.delParam("PD", 0);
}
if(cmd.getParam("PD", 0, strtmp)) {
disconnect(c, Util::REASON_PID_WITHOUT_CID, "CID required when sending PID");
return false;
}
return true;
}
namespace {
bool validateNickF(wchar_t c) { /// @todo lambda
// the following are explicitly allowed (isprint sometimes differs)
if(c >= L'\u2100' && c <= L'\u214F' /* letter-like symbols */) {
return false;
}
// the following are explicitly disallowed (isprint sometimes differs)
if(c == L'\u00AD' /* soft hyphen */) {
return true;
}
static std::locale loc = boost::locale::generator().generate("");
return !std::isprint(c, loc);
}
bool validateNick(const string& nick) {
if(!Util::validateCharset(nick, 33)) { // chars < 33 forbidden (including the space char)
return false;
}
// avoid impersonators
std::wstring nickW = boost::locale::conv::utf_to_utf<wchar_t>(nick);
if(std::find_if(nickW.begin(), nickW.end(), validateNickF) != nickW.end()) {
return false;
}
return true;
}
}
bool ClientManager::verifyNick(Entity& c, const AdcCommand& cmd) throw() {
if(cmd.getParam("NI", 0, strtmp)) {
dcdebug("%s verifying nick %s\n", AdcCommand::fromSID(c.getSID()).c_str(), strtmp.c_str());
if(!validateNick(strtmp)) {
disconnect(c, Util::REASON_NICK_INVALID, "Invalid character in nick", AdcCommand::ERROR_NICK_INVALID);
return false;
}
const string& oldNick = c.getField("NI");
if(!oldNick.empty())
nicks.erase(oldNick);
if(nicks.find(strtmp) != nicks.end()) {
disconnect(c, Util::REASON_NICK_TAKEN, "Nick taken, please pick another one", AdcCommand::ERROR_NICK_TAKEN);
return false;
}
nicks.insert(make_pair(strtmp, &c));
}
return true;
}
void ClientManager::setState(Entity& c, Entity::State newState) throw() {
Entity::State oldState = c.getState();
c.setState(newState);
signalState_(c, oldState);
}
void ClientManager::disconnect(Entity& c, Util::Reason reason, const std::string& info, AdcCommand::Error error, const std::string& staParam) {
// send a fatal STA
AdcCommand sta(AdcCommand::SEV_FATAL, error, info);
if(!staParam.empty())
sta.addParam(staParam);
c.send(sta);
// send a QUI
c.send(AdcCommand(AdcCommand::CMD_QUI).addParam(AdcCommand::fromSID(c.getSID()))
.addParam("DI", "1").addParam("MS", info).addParam("TL", "-1"));
c.disconnect(reason);
}
void ClientManager::enterIdentify(Entity& c, bool sendData) throw() {
dcassert(c.getState() == Entity::STATE_PROTOCOL);
dcdebug("%s entering IDENTIFY\n", AdcCommand::fromSID(c.getSID()).c_str());
if(sendData) {
c.send(hub.getSUP());
c.send(AdcCommand(AdcCommand::CMD_SID).addParam(AdcCommand::fromSID(c.getSID())));
c.send(hub.getINF());
}
setState(c, Entity::STATE_IDENTIFY);
}
ByteVector ClientManager::enterVerify(Entity& c, bool sendData) throw() {
dcassert(c.getState() == Entity::STATE_IDENTIFY);
dcdebug("%s entering VERIFY\n", AdcCommand::fromSID(c.getSID()).c_str());
ByteVector challenge;
challenge.reserve(32);
for(int i = 0; i < 32 / 4; ++i) {
uint32_t r = Util::rand();
challenge.insert(challenge.end(), (uint8_t*) &r, 4 + (uint8_t*) &r);
}
if(sendData) {
c.send(AdcCommand(AdcCommand::CMD_GPA).addParam(Encoder::toBase32(&challenge[0], challenge.size())));
}
setState(c, Entity::STATE_VERIFY);
return challenge;
}
bool ClientManager::enterNormal(Entity& c, bool sendData, bool sendOwnInf) throw() {
dcassert(c.getState() == Entity::STATE_IDENTIFY || c.getState() == Entity::STATE_VERIFY);
dcdebug("%s entering NORMAL\n", AdcCommand::fromSID(c.getSID()).c_str());
if(sendData) {
for(EntityIter i = entities.begin(); i != entities.end(); ++i) {
c.send(i->second->getINF());
}
}
if(sendOwnInf) {
sendToAll(c.getINF());
if(sendData) {
c.send(c.getINF());
}
}
removeLogins(c);
entities.insert(make_pair(c.getSID(), &c));
setState(c, Entity::STATE_NORMAL);
return true;
}
void ClientManager::removeLogins(Entity& e) throw() {
Client* c = dynamic_cast<Client*>(&e);
if(!c) {
return;
}
auto i = find_if(logins.begin(), logins.end(), CompareFirst<Client*, time::ptime> (c));
if(i != logins.end()) {
logins.erase(i);
}
}
void ClientManager::removeEntity(Entity& c, Util::Reason reason, const std::string &info) throw() {
if(c.isSet(Entity::FLAG_GHOST))
return;
dcdebug("Removing %s - %s\n", AdcCommand::fromSID(c.getSID()).c_str(), c.getCID().toBase32().c_str());
c.setFlag(Entity::FLAG_GHOST);
signalDisconnected_(c, reason, info);
if(c.getState() == Entity::STATE_NORMAL) {
entities.erase(c.getSID());
sendToAll(AdcCommand(AdcCommand::CMD_QUI).addParam(AdcCommand::fromSID(c.getSID())).addParam("DI", "1").getBuffer());
} else {
removeLogins(c);
}
nicks.erase(c.getField("NI"));
cids.erase(c.getCID());
}
Entity* ClientManager::getEntity(uint32_t aSid) throw() {
switch(aSid) {
case AdcCommand::INVALID_SID: return nullptr;
case AdcCommand::HUB_SID: return &hub;
default:
{
EntityIter i = entities.find(aSid);
return (i == entities.end()) ? nullptr : i->second;
}
}
}
uint32_t ClientManager::getSID(const string& aNick) const throw() {
NickMap::const_iterator i = nicks.find(aNick);
return (i == nicks.end()) ? AdcCommand::INVALID_SID : i->second->getSID();
}
uint32_t ClientManager::getSID(const CID& cid) const throw() {
CIDMap::const_iterator i = cids.find(cid);
return (i == cids.end()) ? AdcCommand::INVALID_SID : i->second->getSID();
}
void ClientManager::onFailed(Client& c, Util::Reason reason, const std::string &info) throw() {
removeEntity(c, reason, info);
}
}

243
src/adchpp/ClientManager.h Normal file
View File

@@ -0,0 +1,243 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_CLIENTMANAGER_H
#define ADCHPP_CLIENTMANAGER_H
#include "CID.h"
#include "AdcCommand.h"
#include "Signal.h"
#include "Client.h"
#include "Hub.h"
#include "Bot.h"
#include "TimeUtil.h"
#include "TigerHash.h"
#include "forward.h"
namespace adchpp {
class ManagedSocket;
/**
* The ClientManager takes care of all protocol details, clients and so on. This is the very
* heart of ADCH++ together with SocketManager and ManagedSocket.
*/
class ClientManager : public CommandHandler<ClientManager>
{
public:
typedef std::unordered_map<uint32_t, Entity*> EntityMap;
typedef EntityMap::iterator EntityIter;
/** @return SID of entity or AdcCommand::INVALID_SID if not found */
ADCHPP_DLL uint32_t getSID(const std::string& nick) const throw();
/** @return SID of entity or AdcCommand::INVALID_SID if not found */
ADCHPP_DLL uint32_t getSID(const CID& cid) const throw();
/** @return The entity associated with a certain SID, NULL if not found */
ADCHPP_DLL Entity* getEntity(uint32_t aSid) throw();
/** @return A new Bot instance in STATE_IDENTIFY; set CID, nick etc and call regBot */
ADCHPP_DLL Bot* createBot(const Bot::SendHandler& handler);
ADCHPP_DLL void regBot(Bot& bot);
/**
* Get a list of all currently connected clients. (Don't change it, it's non-const
* so that you'll be able to get non-const clients out of it...)!!!)
*/
EntityMap& getEntities() throw() { return entities; }
/** Send a command to according to its type */
ADCHPP_DLL void send(const AdcCommand& cmd) throw();
/** Send a buffer to all connected entities */
ADCHPP_DLL void sendToAll(const BufferPtr& buffer) throw();
/** Send buffer to a single client regardless of type */
ADCHPP_DLL void sendTo(const BufferPtr& buffer, uint32_t to);
/**
* Enter IDENTIFY state.
* Call this if you stop the SUP command when in PROTOCOL state.
*
* @param sendData Send ISUP & IINF.
*/
ADCHPP_DLL void enterIdentify(Entity& c, bool sendData) throw();
/**
* Enter VERIFY state. Call this if you stop
* an INF in the IDENTIFY state and want to check a password.
*
* @param sendData Send GPA.
* @return The random data that was sent to the client (if sendData was true, undefined otherwise).
*/
ADCHPP_DLL ByteVector enterVerify(Entity& c, bool sendData) throw();
/**
* Enter NORMAL state. Call this if you stop an INF of a password-less
* client in IDENTIFY state or a PAS in VERIFY state.
*
* @param sendData Send all data as mandated by the protocol, including list of connected clients.
* @param sendOwnInf Set to true to broadcast the client's inf (i e when a plugin asks
* for password)
* @return false if the client was disconnected
*/
ADCHPP_DLL bool enterNormal(Entity& c, bool sendData, bool sendOwnInf) throw();
/**
* Do all SUP verifications and update client data. Call if you stop SUP but still want the default processing.
*/
ADCHPP_DLL bool verifySUP(Entity& c, AdcCommand& cmd) throw();
/**
* Do all INF verifications and update client data. Call if you stop INF but still want the default processing.
*/
ADCHPP_DLL bool verifyINF(Entity& c, AdcCommand& cmd) throw();
/**
* Verify nick on INF (check that its not a dupe etc...)
* @return false if the client was disconnected
*/
ADCHPP_DLL bool verifyNick(Entity& c, const AdcCommand& cmd) throw();
/**
* Verify password
*/
ADCHPP_DLL bool verifyPassword(Entity& c, const std::string& password, const ByteVector& salt, const std::string& suppliedHash);
bool verifyPassword(Entity& c, const std::string& password, const ByteVector& salt,
const std::string& suppliedHash, TigerHash&& tiger);
/**
* Verify hashed password; based on http://www.dcbase.org/forums/viewtopic.php?p=2861#p2861
*/
ADCHPP_DLL bool verifyHashedPassword(Entity& c, const ByteVector& hashedPassword, int64_t hashedPasswordLen,
const ByteVector& salt, const std::string& suppliedHash);
/**
* Verify that IP is correct and replace any zero addresses.
*/
ADCHPP_DLL bool verifyIp(Client& c, AdcCommand& cmd) throw();
/**
* Verify that CID is correct and corresponds to PID
*/
ADCHPP_DLL bool verifyCID(Entity& c, AdcCommand& cmd) throw();
/**
* Verify that there aren't too many sockets overflowing (indicates lack of bandwidth)
*/
ADCHPP_DLL bool verifyOverflow(Entity& c);
/** Update the state of c (this fires signalState as well) */
ADCHPP_DLL void setState(Entity& c, Entity::State newState) throw();
ADCHPP_DLL size_t getQueuedBytes() throw();
typedef SignalTraits<void (Entity&)> SignalConnected;
typedef SignalTraits<void (Entity&)> SignalReady;
typedef SignalTraits<void (Entity&, AdcCommand&, bool&)> SignalReceive;
typedef SignalTraits<void (Entity&, const std::string&)> SignalBadLine;
typedef SignalTraits<void (Entity&, const AdcCommand&, bool&)> SignalSend;
typedef SignalTraits<void (Entity&, int)> SignalState;
typedef SignalTraits<void (Entity&, Util::Reason, const std::string&)> SignalDisconnected;
/** A client has just connected. */
SignalConnected::Signal& signalConnected() { return signalConnected_; }
/** A client is now ready for read / write operations (TLS handshake completed). */
SignalConnected::Signal& signalReady() { return signalReady_; }
SignalReceive::Signal& signalReceive() { return signalReceive_; }
SignalBadLine::Signal& signalBadLine() { return signalBadLine_; }
SignalSend::Signal& signalSend() { return signalSend_; }
SignalState::Signal& signalState() { return signalState_; }
SignalDisconnected::Signal& signalDisconnected() { return signalDisconnected_; }
void setMaxCommandSize(size_t newSize) { maxCommandSize = newSize; }
size_t getMaxCommandSize() const { return maxCommandSize; }
void setLogTimeout(size_t millis) { logTimeout = millis; }
size_t getLogTimeout() const { return logTimeout; }
Core &getCore() const { return core; }
private:
friend class Core;
friend class Client;
friend class Entity;
friend class Bot;
Core &core;
std::list<std::pair<Client*, time::ptime> > logins;
EntityMap entities;
typedef std::unordered_map<std::string, Entity*> NickMap;
NickMap nicks;
typedef std::unordered_map<CID, Entity*> CIDMap;
CIDMap cids;
Hub hub;
size_t maxCommandSize;
size_t logTimeout;
// Temporary string to use whenever a temporary string is needed (to avoid (de)allocating memory all the time...)
std::string strtmp;
static const std::string className;
friend class CommandHandler<ClientManager>;
uint32_t makeSID();
void maybeSend(Entity& c, const AdcCommand& cmd);
void removeLogins(Entity& c) throw();
void removeEntity(Entity& c, Util::Reason reason, const std::string &info) throw();
bool handle(AdcCommand::SUP, Entity& c, AdcCommand& cmd) throw();
bool handle(AdcCommand::INF, Entity& c, AdcCommand& cmd) throw();
bool handleDefault(Entity& c, AdcCommand& cmd) throw();
template<typename T> bool handle(T, Entity& c, AdcCommand& cmd) throw() { return handleDefault(c, cmd); }
void handleIncoming(const ManagedSocketPtr& sock) throw();
void onConnected(Client&) throw();
void onReady(Client&) throw();
void onReceive(Entity&, AdcCommand&) throw();
void onBadLine(Client&, const std::string&) throw();
void onFailed(Client&, Util::Reason reason, const std::string &info) throw();
void badState(Entity& c, const AdcCommand& cmd) throw();
/** send a fatal STA, a QUI with TL-1, then disconnect. */
void disconnect(Entity& c, Util::Reason reason, const std::string& info,
AdcCommand::Error error = AdcCommand::ERROR_PROTOCOL_GENERIC, const std::string& staParam = Util::emptyString);
SignalConnected::Signal signalConnected_;
SignalReady::Signal signalReady_;
SignalReceive::Signal signalReceive_;
SignalBadLine::Signal signalBadLine_;
SignalSend::Signal signalSend_;
SignalState::Signal signalState_;
SignalDisconnected::Signal signalDisconnected_;
ClientManager(Core &core) throw();
};
}
#endif // CLIENTMANAGER_H

93
src/adchpp/Core.cpp Normal file
View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "Core.h"
#include "LogManager.h"
#include "SocketManager.h"
#include "ClientManager.h"
#include "PluginManager.h"
namespace adchpp {
shared_ptr<Core> Core::create(const std::string &configPath) {
auto ret = shared_ptr<Core>(new Core(configPath));
ret->init();
return ret;
}
Core::Core(const std::string &configPath) : configPath(configPath), startTime(time::now())
{
}
Core::~Core() {
lm->log("core", "Shutting down...");
// Order is significant...
pm.reset();
cm.reset();
sm.reset();
lm.reset();
}
void Core::init() {
lm.reset(new LogManager(*this));
sm.reset(new SocketManager(*this));
cm.reset(new ClientManager(*this));
pm.reset(new PluginManager(*this));
sm->setIncomingHandler(std::bind(&ClientManager::handleIncoming, cm.get(), std::placeholders::_1));
//lm->log("core", "Core initialized"); @todo logfile path setting isn't processed yet so this may litter log files to unwanted places, see L#907372
printf("\nCore initialized\n"); // Console print only for now...
}
void Core::run() {
pm->load();
sm->run();
}
void Core::shutdown() {
// make sure we run shutdown routines from the right thread.
addJob(std::bind(&Core::doShutdown, this));
}
void Core::doShutdown() {
sm->shutdown();
pm->shutdown();
}
const std::string &Core::getConfigPath() const { return configPath; }
LogManager &Core::getLogManager() { return *lm; }
SocketManager &Core::getSocketManager() { return *sm; }
PluginManager &Core::getPluginManager() { return *pm; }
ClientManager &Core::getClientManager() { return *cm; }
void Core::addJob(const Callback& callback) throw() { sm->addJob(callback); }
void Core::addJob(const long msec, const Callback& callback) { sm->addJob(msec, callback); }
void Core::addJob(const std::string& time, const Callback& callback) { sm->addJob(time, callback); }
Core::Callback Core::addTimedJob(const long msec, const Callback& callback) { return sm->addTimedJob(msec, callback); }
Core::Callback Core::addTimedJob(const std::string& time, const Callback& callback) { return sm->addTimedJob(time, callback); }
}

93
src/adchpp/Core.h Normal file
View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_ADCHPP_CORE_H_
#define ADCHPP_ADCHPP_CORE_H_
#include "common.h"
#include "TimeUtil.h"
#include "forward.h"
namespace adchpp {
/** A single instance of an entire hub with plugins, settings and listening sockets */
class Core {
public:
typedef std::function<void()> Callback;
ADCHPP_DLL ~Core();
ADCHPP_DLL static shared_ptr<Core> create(const std::string &configPath);
ADCHPP_DLL void run();
ADCHPP_DLL void shutdown();
ADCHPP_DLL LogManager &getLogManager();
ADCHPP_DLL SocketManager &getSocketManager();
ADCHPP_DLL PluginManager &getPluginManager();
ADCHPP_DLL ClientManager &getClientManager();
ADCHPP_DLL const std::string &getConfigPath() const;
/** execute a function asynchronously */
ADCHPP_DLL void addJob(const Callback& callback) throw();
/** execute a function after the specified amount of time
* @param msec milliseconds
*/
ADCHPP_DLL void addJob(const long msec, const Callback& callback);
/** execute a function after the specified amount of time
* @param time a string that obeys to the "[-]h[h][:mm][:ss][.fff]" format
*/
ADCHPP_DLL void addJob(const std::string& time, const Callback& callback);
/** execute a function at regular intervals
* @param msec milliseconds
* @return function one must call to cancel the timer (its callback will still be executed)
*/
ADCHPP_DLL Callback addTimedJob(const long msec, const Callback& callback);
/** execute a function at regular intervals
* @param time a string that obeys to the "[-]h[h][:mm][:ss][.fff]" format
* @return function one must call to cancel the timer (its callback will still be executed)
*/
ADCHPP_DLL Callback addTimedJob(const std::string& time, const Callback& callback);
time::ptime getStartTime() const { return startTime; }
private:
Core(const std::string &configPath);
void init();
void doShutdown(); /// @todo remove when we have lambdas
std::unique_ptr<LogManager> lm;
std::unique_ptr<SocketManager> sm;
std::unique_ptr<PluginManager> pm;
std::unique_ptr<ClientManager> cm;
std::string configPath;
time::ptime startTime;
};
}
#endif /* CORE_H_ */

115
src/adchpp/Encoder.cpp Normal file
View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "Encoder.h"
#include "common.h"
namespace adchpp {
using namespace std;
const int8_t Encoder::base32Table[256] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
};
const char Encoder::base32Alphabet[32] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '2', '3', '4', '5', '6', '7'
};
string& Encoder::toBase32(const uint8_t* src, size_t len, string& dst) {
// Code snagged from the bitzi bitcollider
size_t i, index;
uint8_t word;
dst.reserve(((len * 8) / 5) + 1);
for(i = 0, index = 0; i < len;) {
/* Is the current word going to span a byte boundary? */
if (index > 3) {
word = (uint8_t)(src[i] & (0xFF >> index));
index = (index + 5) % 8;
word <<= index;
if ((i + 1) < len)
word |= src[i + 1] >> (8 - index);
i++;
} else {
word = (uint8_t)(src[i] >> (8 - (index + 5))) & 0x1F;
index = (index + 5) % 8;
if (index == 0)
i++;
}
dcassert(word < 32);
dst += base32Alphabet[word];
}
return dst;
}
void Encoder::fromBase32(const char* src, uint8_t* dst, size_t len) {
size_t i, index, offset;
memset(dst, 0, len);
for(i = 0, index = 0, offset = 0; src[i]; i++) {
// Skip what we don't recognise
int8_t tmp = base32Table[(unsigned char)src[i]];
if(tmp == -1)
continue;
if (index <= 3) {
index = (index + 5) % 8;
if (index == 0) {
dst[offset] |= tmp;
offset++;
if(offset == len)
break;
} else {
dst[offset] |= tmp << (8 - index);
}
} else {
index = (index + 5) % 8;
dst[offset] |= (tmp >> index);
offset++;
if(offset == len)
break;
dst[offset] |= tmp << (8 - index);
}
}
}
}

41
src/adchpp/Encoder.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_ENCODER_H
#define ADCHPP_ENCODER_H
namespace adchpp {
class Encoder
{
public:
ADCHPP_DLL static std::string& toBase32(const uint8_t* src, size_t len, std::string& tgt);
static std::string toBase32(const uint8_t* src, size_t len) {
std::string tmp;
return toBase32(src, len, tmp);
}
ADCHPP_DLL static void fromBase32(const char* src, uint8_t* dst, size_t len);
ADCHPP_DLL static const int8_t base32Table[256];
ADCHPP_DLL static const char base32Alphabet[32];
private:
};
}
#endif // _ENCODER

218
src/adchpp/Entity.cpp Normal file
View File

@@ -0,0 +1,218 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "Entity.h"
#include "ClientManager.h"
namespace adchpp {
Entity::~Entity() {
for(PluginDataMap::iterator i = pluginData.begin(), iend = pluginData.end(); i != iend; ++i) {
(*i->first)(i->second);
}
}
void Entity::inject(AdcCommand& cmd) {
cm.onReceive(*this, cmd);
}
const std::string& Entity::getField(const char* name) const {
auto i = fields.find(AdcCommand::toField(name));
return i == fields.end() ? Util::emptyString : i->second;
}
bool Entity::hasField(const char* name) const {
return fields.find(AdcCommand::toField(name)) != fields.end();
}
void Entity::setField(const char* name, const std::string& value) {
uint16_t code = AdcCommand::toField(name);
if(code == AdcCommand::toField("SU")) {
filters.clear();
if((value.size() + 1) % 5 == 0) {
filters.reserve((value.size() + 1) / 5);
for(size_t i = 0; i < value.size(); i += 5) {
filters.push_back(AdcCommand::toFourCC(value.data() + i));
}
}
}
if(value.empty()) {
fields.erase(code);
} else {
fields[code] = value;
}
INF = BufferPtr();
}
bool Entity::getAllFields(AdcCommand& cmd) const throw() {
for(auto i = fields.begin(); i != fields.end(); ++i)
cmd.addParam(AdcCommand::fromField(i->first), i->second);
return !fields.empty();
}
void Entity::updateFields(const AdcCommand& cmd) {
dcassert(cmd.getCommand() == AdcCommand::CMD_INF);
for(StringIterC j = cmd.getParameters().begin(); j != cmd.getParameters().end(); ++j) {
if(j->size() < 2)
continue;
setField(j->c_str(), j->substr(2));
}
}
const BufferPtr& Entity::getINF() const {
if(!INF) {
AdcCommand cmd(AdcCommand::CMD_INF, getSID() == AdcCommand::HUB_SID ? AdcCommand::TYPE_INFO : AdcCommand::TYPE_BROADCAST, getSID());
getAllFields(cmd);
INF = cmd.getBuffer();
}
return INF;
}
bool Entity::addSupports(uint32_t feature) {
if(std::find(supports.begin(), supports.end(), feature) != supports.end()) {
return false;
}
supports.push_back(feature);
SUP = BufferPtr();
return true;
}
StringList Entity::getSupportList() const {
StringList ret(supports.size());
for(size_t i = 0; i < supports.size(); ++i) {
ret[i] = AdcCommand::fromFourCC(supports[i]);
}
return ret;
}
bool Entity::removeSupports(uint32_t feature) {
std::vector<uint32_t>::iterator i = std::find(supports.begin(), supports.end(), feature);
if(i == supports.end()) {
return false;
}
supports.erase(i);
SUP = BufferPtr();
return true;
}
const BufferPtr& Entity::getSUP() const {
if(!SUP) {
AdcCommand cmd(AdcCommand::CMD_SUP, getSID() == AdcCommand::HUB_SID ? AdcCommand::TYPE_INFO : AdcCommand::TYPE_BROADCAST, getSID());
for(std::vector<uint32_t>::const_iterator i = supports.begin(), iend = supports.end(); i != iend; ++i) {
cmd.addParam("AD", AdcCommand::fromFourCC(*i));
}
SUP = cmd.getBuffer();
}
return SUP;
}
bool Entity::hasSupport(uint32_t feature) const {
return find(supports.begin(), supports.end(), feature) != supports.end();
}
void Entity::updateSupports(const AdcCommand& cmd) throw() {
for(StringIterC i = cmd.getParameters().begin(); i != cmd.getParameters().end(); ++i) {
const std::string& str = *i;
if(str.size() != 6) {
continue;
}
if(str[0] == 'A' && str[1] == 'D') {
addSupports(AdcCommand::toFourCC(str.c_str() + 2));
} else if(str[0] == 'R' && str[1] == 'M') {
removeSupports(AdcCommand::toFourCC(str.c_str() + 2));
}
}
}
bool Entity::isFiltered(const std::string& features) const {
if(filters.empty()) {
return true;
}
for(size_t i = 0; i < features.size(); i += 5) {
if(features[i] == '-') {
if(std::find(filters.begin(), filters.end(), AdcCommand::toFourCC(features.data() + i + 1)) != filters.end()) {
return true;
}
} else if(features[i] == '+') {
if(std::find(filters.begin(), filters.end(), AdcCommand::toFourCC(features.data() + i + 1)) == filters.end()) {
return true;
}
}
}
return false;
}
void Entity::setPluginData(const PluginDataHandle& handle, void* data) throw() {
clearPluginData(handle);
pluginData.insert(std::make_pair(handle, data));
}
void* Entity::getPluginData(const PluginDataHandle& handle) const throw() {
PluginDataMap::const_iterator i = pluginData.find(handle);
return i == pluginData.end() ? 0 : i->second;
}
void Entity::clearPluginData(const PluginDataHandle& handle) throw() {
PluginDataMap::iterator i = pluginData.find(handle);
if(i == pluginData.end()) {
return;
}
(*i->first)(i->second);
pluginData.erase(i);
}
void Entity::setFlag(size_t flag) {
flags.setFlag(flag);
if(flag & MASK_CLIENT_TYPE) {
setField("CT", Util::toString(flags.getFlags() & MASK_CLIENT_TYPE));
}
}
void Entity::unsetFlag(size_t flag) {
flags.unsetFlag(flag);
if(flag & MASK_CLIENT_TYPE) {
setField("CT", Util::toString(flags.getFlags() & MASK_CLIENT_TYPE));
}
}
size_t Entity::getQueuedBytes() const {
return 0;
}
time::ptime Entity::getOverflow() const {
return time::not_a_date_time;
}
}

173
src/adchpp/Entity.h Normal file
View File

@@ -0,0 +1,173 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_ENTITY_H
#define ADCHPP_ENTITY_H
#include "forward.h"
#include "Buffer.h"
#include "AdcCommand.h"
#include "Plugin.h"
#include "CID.h"
#include "TimeUtil.h"
namespace adchpp {
class ADCHPP_VISIBLE Entity : private boost::noncopyable {
public:
enum State {
/** Initial protocol negotiation (wait for SUP) */
STATE_PROTOCOL,
/** Identify the connecting client (wait for INF) */
STATE_IDENTIFY,
/** Verify the client (wait for PAS) */
STATE_VERIFY,
/** Normal operation */
STATE_NORMAL,
/** Binary data transfer */
STATE_DATA
};
enum Flag {
FLAG_BOT = 0x01,
FLAG_REGISTERED = 0x02,
FLAG_OP = 0x04,
FLAG_SU = 0x08,
FLAG_OWNER = 0x10,
FLAG_HUB = 0x20,
FLAG_HIDDEN = 0x40,
MASK_CLIENT_TYPE = FLAG_BOT | FLAG_REGISTERED | FLAG_OP | FLAG_SU | FLAG_OWNER | FLAG_HUB | FLAG_HIDDEN,
FLAG_PASSWORD = 0x100,
/** Extended away, no need to send msg */
FLAG_EXT_AWAY = 0x200,
/** Plugins can use these flags to disable various checks */
/** Bypass ip check */
FLAG_OK_IP = 0x400,
/** This entity is now a ghost being disconnected, totally ignored by ADCH++ */
FLAG_GHOST = 0x800
};
Entity(ClientManager &cm, uint32_t sid_) : sid(sid_), state(STATE_PROTOCOL), cm(cm) { }
void send(const AdcCommand& cmd) { send(cmd.getBuffer()); }
virtual void send(const BufferPtr& cmd) = 0;
ADCHPP_DLL virtual void inject(AdcCommand& cmd);
ADCHPP_DLL const std::string& getField(const char* name) const;
ADCHPP_DLL bool hasField(const char* name) const;
ADCHPP_DLL void setField(const char* name, const std::string& value);
/** Add any flags that have been updated to the AdcCommand (type etc is not set) */
ADCHPP_DLL bool getAllFields(AdcCommand& cmd) const throw();
ADCHPP_DLL const BufferPtr& getINF() const;
ADCHPP_DLL bool addSupports(uint32_t feature);
ADCHPP_DLL StringList getSupportList() const;
ADCHPP_DLL bool hasSupport(uint32_t feature) const;
ADCHPP_DLL bool removeSupports(uint32_t feature);
ADCHPP_DLL const BufferPtr& getSUP() const;
uint32_t getSID() const { return sid; }
ADCHPP_DLL bool isFiltered(const std::string& features) const;
ADCHPP_DLL void updateFields(const AdcCommand& cmd);
ADCHPP_DLL void updateSupports(const AdcCommand& cmd) throw();
/**
* Set PSD (plugin specific data). This allows a plugin to store arbitrary
* per-client data, and retrieve it later on. The life cycle of the data follows
* that of the client unless explicitly removed. Any data referenced by the plugin
* will have its delete function called when the Entity is deleted.
* @param id Id as retrieved from PluginManager::getPluginId()
* @param data Data to store, this can be pretty much anything
*/
ADCHPP_DLL void setPluginData(const PluginDataHandle& handle, void* data) throw();
/**
* @param handle Plugin data handle, as returned by PluginManager::registerPluginData
* @return Value stored, NULL if none found
*/
ADCHPP_DLL void* getPluginData(const PluginDataHandle& handle) const throw();
/**
* Clear any data referenced by the handle, calling the registered delete function.
*/
ADCHPP_DLL void clearPluginData(const PluginDataHandle& handle) throw();
const CID& getCID() const { return cid; }
void setCID(const CID& cid_) { cid = cid_; }
State getState() const { return state; }
void setState(State state_) { state = state_; }
bool isSet(size_t aFlag) const { return flags.isSet(aFlag); }
bool isAnySet(size_t aFlag) const { return flags.isAnySet(aFlag); }
ADCHPP_DLL void setFlag(size_t aFlag);
ADCHPP_DLL void unsetFlag(size_t aFlag);
ADCHPP_DLL virtual void disconnect(Util::Reason reason, const std::string &info = Util::emptyString) = 0;
/** The number of bytes in the write buffer */
ADCHPP_DLL virtual size_t getQueuedBytes() const;
/** The time that this entity's write buffer size exceeded the maximum buffer size, 0 if no overflow */
ADCHPP_DLL virtual time::ptime getOverflow() const;
protected:
virtual ~Entity();
typedef std::map<PluginDataHandle, void*> PluginDataMap;
CID cid;
uint32_t sid;
Flags flags;
State state;
/** SUP items */
std::vector<uint32_t> supports;
/** INF SU */
std::vector<uint32_t> filters;
/** INF fields */
std::map<uint16_t, std::string> fields;
/** Plugin data, see PluginManager::registerPluginData */
PluginDataMap pluginData;
/** Latest INF cached */
mutable BufferPtr INF;
/** Latest SUP cached */
mutable BufferPtr SUP;
/** ClientManager that owns this entity */
ClientManager &cm;
};
}
#endif /* ADCHPP_ENTITY_H */

60
src/adchpp/Exception.h Normal file
View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_EXCEPTION_H
#define ADCHPP_EXCEPTION_H
#include "common.h"
namespace adchpp {
class ADCHPP_VISIBLE Exception : public std::exception
{
public:
Exception() { }
Exception(const std::string& aError) throw() : error(aError) { dcdebug("Thrown: %s\n", error.c_str()); }
virtual ~Exception() throw() { }
const std::string& getError() const throw() { return error; }
virtual const char* what() const throw() { return error.c_str(); }
protected:
std::string error;
};
#ifndef NDEBUG
#define STANDARD_EXCEPTION(name) class ADCHPP_VISIBLE name : public Exception { \
public:\
name() throw() : Exception(#name) { } \
name(const std::string& aError) throw() : Exception(#name ": " + aError) { } \
virtual ~name() throw() { } \
}
#else // NDEBUG
#define STANDARD_EXCEPTION(name) class ADCHPP_VISIBLE name : public Exception { \
public:\
name() throw() : Exception() { } \
name(const std::string& aError) throw() : Exception(aError) { } \
virtual ~name() throw() { } \
}
#endif
}
#endif // EXCEPTION_H

100
src/adchpp/FastAlloc.h Normal file
View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_FASTALLOC_H
#define ADCHPP_FASTALLOC_H
#include "Mutex.h"
namespace adchpp {
#ifdef NDEBUG
struct FastAllocBase {
ADCHPP_DLL static FastMutex mtx;
};
/**
* Fast new/delete replacements for constant sized objects, that also give nice
* reference locality...
*/
template<class T>
struct FastAlloc : public FastAllocBase {
// Custom new & delete that (hopefully) use the node allocator
static void* operator new(size_t s) {
if(s != sizeof(T))
return ::operator new(s);
return allocate();
}
// Avoid hiding placement new that's needed by the stl containers...
static void* operator new(size_t, void* m) {
return m;
}
// ...and the warning about missing placement delete...
static void operator delete(void*, void*) {
// ? We didn't allocate so...
}
static void operator delete(void* m, size_t s) {
if (s != sizeof(T)) {
::operator delete(m);
} else if(m != NULL) {
deallocate((uint8_t*)m);
}
}
private:
static void* allocate() {
FastMutex::Lock l(mtx);
if(freeList == NULL) {
grow();
}
void* tmp = freeList;
freeList = *((void**)freeList);
return tmp;
}
static void deallocate(void* p) {
FastMutex::Lock l(mtx);
*(void**)p = freeList;
freeList = p;
}
static void* freeList;
static void grow() {
dcassert(sizeof(T) >= sizeof(void*));
// We want to grow by approximately 128kb at a time...
size_t items = ((128*1024 + sizeof(T) - 1)/sizeof(T));
freeList = new uint8_t[sizeof(T)*items];
uint8_t* tmp = (uint8_t*)freeList;
for(size_t i = 0; i < items - 1; i++) {
*(void**)tmp = tmp + sizeof(T);
tmp += sizeof(T);
}
*(void**)tmp = NULL;
}
};
template<class T> void* FastAlloc<T>::freeList = 0;
#else
template<class T> struct FastAlloc { };
#endif
}
#endif // FASTALLOC_H

188
src/adchpp/File.cpp Normal file
View File

@@ -0,0 +1,188 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "File.h"
namespace adchpp {
using namespace std;
string File::read(uint32_t len) throw(FileException) {
string tmp;
tmp.resize(len);
uint32_t x = read(&tmp[0], len);
tmp.resize(x);
return tmp;
}
#ifdef _WIN32
File::File(const string& aFileName, int access, int mode) throw(FileException) {
dcassert(access == WRITE || access == READ || access == (READ | WRITE));
int m = 0;
if(mode & OPEN) {
if(mode & CREATE) {
m = (mode & TRUNCATE) ? CREATE_ALWAYS : OPEN_ALWAYS;
} else {
m = (mode & TRUNCATE) ? TRUNCATE_EXISTING : OPEN_EXISTING;
}
} else {
if(mode & CREATE) {
m = (mode & TRUNCATE) ? CREATE_ALWAYS : CREATE_NEW;
} else {
dcassert(0);
}
}
int a = 0;
if(access & READ)
a |= GENERIC_READ;
if(access & WRITE)
a |= GENERIC_WRITE;
h = ::CreateFile(aFileName.c_str(), a, FILE_SHARE_READ, NULL, m, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if(h == INVALID_HANDLE_VALUE) {
throw FileException(Util::translateError(GetLastError()));
}
}
int64_t File::getSize() {
DWORD x;
DWORD l = ::GetFileSize(h, &x);
if( (l == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
return -1;
return (int64_t)l | ((int64_t)x)<<32;
}
int64_t File::getSize(const string& aFileName) {
WIN32_FIND_DATA fd;
HANDLE hFind;
hFind = FindFirstFile(aFileName.c_str(), &fd);
if (hFind == INVALID_HANDLE_VALUE) {
return -1;
} else {
FindClose(hFind);
return ((int64_t)fd.nFileSizeHigh << 32 | (int64_t)fd.nFileSizeLow);
}
}
string File::getFilePath(const string& path) throw() {
string::size_type i = path.find_last_of("\\/");
return (i != string::npos) ? path.substr(0, i) : path;
}
string File::getFileName(const string& path) throw() {
string::size_type i = path.find_last_of("\\/");
return (i != string::npos) ? path.substr(i + 1) : path;
}
bool File::isAbsolutePath(const string& path) throw() {
return (path.length() >= 3 && path[1] == ':' && (path[2] == '\\' || path[2] == '/')) ||
(path.length() >= 1 && (path[0] == '\\' || path[0] == '/'));
}
void File::ensureDirectory(const string& aFile) throw() {
string::size_type start = 0;
while( (start = aFile.find_first_of("\\/", start)) != string::npos) {
::CreateDirectory(aFile.substr(0, start+1).c_str(), NULL);
start++;
}
}
#else // _WIN32
File::File(const string& aFileName, int access, int mode) throw(FileException) {
dcassert(access == WRITE || access == READ || access == (READ | WRITE));
int m = 0;
if(access == READ)
m |= O_RDONLY;
else if(access == WRITE)
m |= O_WRONLY;
else
m |= O_RDWR;
if(mode & CREATE) {
m |= O_CREAT;
}
if(mode & TRUNCATE) {
m |= O_TRUNC;
}
h = open(aFileName.c_str(), m, S_IRUSR | S_IWUSR);
if(h == -1)
throw FileException("Could not open file");
}
int64_t File::getSize() {
struct stat s;
if(fstat(h, &s) == -1)
return -1;
return (int64_t)s.st_size;
}
int64_t File::getSize(const string& aFileName) {
struct stat s;
if(stat(aFileName.c_str(), &s) == -1)
return -1;
return s.st_size;
}
string File::getFilePath(const string& path) throw() {
string::size_type i = path.rfind('/');
return (i != string::npos) ? path.substr(0, i) : path;
}
string File::getFileName(const string& path) throw() {
string::size_type i = path.rfind('/');
return (i != string::npos) ? path.substr(i + 1) : path;
}
bool File::isAbsolutePath(const string& path) throw() {
return path.length() >= 1 && path[0] == '/';
}
void File::ensureDirectory(const string& aFile) throw() {
string::size_type start = 0;
while( (start = aFile.find('/', start)) != string::npos) {
::mkdir(aFile.substr(0, start+1).c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
start++;
}
}
#endif
std::string File::makeAbsolutePath(const std::string& filename) {
return makeAbsolutePath(Util::getAppPath() + PATH_SEPARATOR, filename);
}
std::string File::makeAbsolutePath(const std::string& path, const std::string& filename) {
return isAbsolutePath(filename) ? filename : path + filename;
}
}

193
src/adchpp/File.h Normal file
View File

@@ -0,0 +1,193 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_FILE_H
#define ADCHPP_FILE_H
#include "Exception.h"
#include "Util.h"
#ifndef _WIN32
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif
namespace adchpp {
STANDARD_EXCEPTION(FileException);
class File
{
public:
enum {
READ = 0x01,
WRITE = 0x02
};
enum {
OPEN = 0x01,
CREATE = 0x02,
TRUNCATE = 0x04
};
ADCHPP_DLL File(const std::string& aFileName, int access, int mode = OPEN) throw(FileException);
ADCHPP_DLL int64_t getSize();
ADCHPP_DLL static int64_t getSize(const std::string& aFileName);
ADCHPP_DLL std::string read(uint32_t len) throw(FileException);
/** Returns the directory part of the full path */
ADCHPP_DLL static std::string getFilePath(const std::string& name) throw();
/** Returns the filename part of the full path */
ADCHPP_DLL static std::string getFileName(const std::string& name) throw();
ADCHPP_DLL static bool isAbsolutePath(const std::string& name) throw();
ADCHPP_DLL static std::string makeAbsolutePath(const std::string& filename);
ADCHPP_DLL static std::string makeAbsolutePath(const std::string& path, const std::string& filename);
ADCHPP_DLL static void ensureDirectory(const std::string& aFile) throw();
#ifdef _WIN32
void close() {
if(h != INVALID_HANDLE_VALUE) {
CloseHandle(h);
h = INVALID_HANDLE_VALUE;
}
}
int64_t getPos() {
LONG x = 0;
DWORD l = ::SetFilePointer(h, 0, &x, FILE_CURRENT);
return (int64_t)l | ((int64_t)x)<<32;
}
void setPos(int64_t pos) {
LONG x = (LONG) (pos>>32);
::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_BEGIN);
}
void setEndPos(int64_t pos) {
LONG x = (LONG) (pos>>32);
::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_END);
}
void movePos(int64_t pos) {
LONG x = (LONG) (pos>>32);
::SetFilePointer(h, (DWORD)(pos & 0xffffffff), &x, FILE_CURRENT);
}
uint32_t read(void* buf, uint32_t len) throw(FileException) {
DWORD x;
if(!::ReadFile(h, buf, len, &x, NULL)) {
throw(FileException(Util::translateError(GetLastError())));
}
return x;
}
void write(const void* buf, size_t len) throw(FileException) {
DWORD x;
if(!::WriteFile(h, buf, (DWORD)len, &x, NULL)) {
throw FileException(Util::translateError(GetLastError()));
}
if(x < len) {
throw FileException("Unable to write, disk full?");
}
}
void setEOF() throw(FileException) {
dcassert(h != NULL);
if(!SetEndOfFile(h)) {
throw FileException(Util::translateError(GetLastError()));
}
}
static void deleteFile(const std::string& aFileName) { ::DeleteFile(aFileName.c_str()); };
static void renameFile(const std::string& source, const std::string& target) { ::MoveFile(source.c_str(), target.c_str()); };
#else // WIN32
void close() {
if(h != -1) {
::close(h);
h = -1;
}
}
int64_t getPos() { return (int64_t) lseek(h, 0, SEEK_CUR); }
void setPos(int64_t pos) { lseek(h, (off_t)pos, SEEK_SET); };
void setEndPos(int64_t pos) { lseek(h, (off_t)pos, SEEK_END); };
void movePos(int64_t pos) { lseek(h, (off_t)pos, SEEK_CUR); };
uint32_t read(void* buf, uint32_t len) throw(FileException) {
ssize_t x = ::read(h, buf, (size_t)len);
if(x == -1)
throw FileException(Util::translateError(errno));
return (uint32_t)x;
}
void write(const void* buf, uint32_t len) throw(FileException) {
ssize_t x;
x = ::write(h, buf, len);
if(x == -1)
throw FileException(Util::translateError(errno));
if(x < (ssize_t)len)
throw FileException("Unable to write, disk full?");
}
/**
* @todo fix for unix...
*/
void setEOF() throw(FileException) {
}
static void deleteFile(const std::string& aFileName) { ::unlink(aFileName.c_str()); };
static void renameFile(const std::string& source, const std::string& target) { ::rename(source.c_str(), target.c_str()); };
#endif // WIN32
~File() {
close();
}
std::string read() throw(FileException) {
setPos(0);
return read((uint32_t)getSize());
}
void write(const std::string& aString) throw(FileException) {
write((void*)aString.data(), aString.size());
}
private:
File(const File&);
File& operator=(const File&);
#ifdef _WIN32
HANDLE h;
#else
int h;
#endif
};
}
#endif // FILE_H

36
src/adchpp/Hub.cpp Normal file
View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "Hub.h"
#include "AdcCommand.h"
#include "version.h"
namespace adchpp {
Hub::Hub(ClientManager &cm) : Entity(cm, AdcCommand::HUB_SID) {
setField("NI", "adchpp");
setField("HI", "1");
setField("DE", appName + ' ' + versionString);
setField("AP", appName);
setField("VE", versionString);
setFlag(FLAG_HUB);
}
}

39
src/adchpp/Hub.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef HUB_H_
#define HUB_H_
#include "forward.h"
#include "Entity.h"
namespace adchpp {
class ADCHPP_VISIBLE Hub : public Entity {
public:
ADCHPP_DLL Hub(ClientManager &cm);
virtual void send(const BufferPtr& cmd) { }
virtual void disconnect(Util::Reason reason, const std::string &) throw() { }
private:
};
}
#endif /* HUB_H_ */

69
src/adchpp/LogManager.cpp Normal file
View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "LogManager.h"
#include "File.h"
#include "Core.h"
namespace adchpp {
using namespace std;
LogManager::LogManager(Core &core) : logFile("logs/adchpp%Y%m.log"), enabled(true), core(core) { }
void LogManager::log(const string& area, const string& msg) throw() {
char buf[64];
time_t now = std::time(NULL);
size_t s = strftime(buf, 64, "%Y-%m-%d %H:%M:%S: ", localtime(&now));
string tmp(buf, s);
tmp += area;
tmp += ": ";
tmp += msg;
dolog(tmp);
}
void LogManager::dolog(const string& msg) throw() {
dcdebug("Logging: %s\n", msg.c_str());
signalLog_(msg);
if(getEnabled()) {
string logFile = Util::formatTime(File::makeAbsolutePath(core.getConfigPath(), getLogFile()));
FastMutex::Lock l(mtx);
try {
File f(logFile, File::WRITE, File::OPEN | File::CREATE);
f.setEndPos(0);
f.write(msg + "\r\n");
return;
} catch(const FileException& e) {
dcdebug("LogManager::log: %s\n", e.getError().c_str());
}
try {
File::ensureDirectory(logFile);
File f(logFile, File::WRITE, File::OPEN | File::CREATE);
f.setEndPos(0);
f.write(msg + "\r\n");
} catch(const FileException& ee) {
dcdebug("LogManager::log2: %s\n", ee.getError().c_str());
}
}
}
}

70
src/adchpp/LogManager.h Normal file
View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_LOGMANAGER_H
#define ADCHPP_LOGMANAGER_H
#include "forward.h"
#include "Mutex.h"
#include "Signal.h"
namespace adchpp {
/**
* Log writing utilities.
*/
class LogManager
{
public:
/**
* Add a line to the log.
* @param area Name of the module that generated the error.
* @param msg Message to log.
*/
ADCHPP_DLL void log(const std::string& area, const std::string& msg) throw();
void setLogFile(const std::string& fileName) { logFile = fileName; }
const std::string& getLogFile() const { return logFile; }
void setEnabled(bool enabled_) { enabled = enabled_; }
bool getEnabled() const { return enabled; }
typedef SignalTraits<void (const std::string&)> SignalLog;
SignalLog::Signal& signalLog() { return signalLog_; }
private:
friend class Core;
FastMutex mtx;
std::string logFile;
bool enabled;
LogManager(Core &core);
SignalLog::Signal signalLog_;
Core &core;
ADCHPP_DLL void dolog(const std::string& msg) throw();
};
#define LOGC(core, area, msg) (core).getLogManager().log(area, msg)
#define LOG(area, msg) LOGC(core, area, msg)
}
#endif // LOGMANAGER_H

View File

@@ -0,0 +1,278 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "ManagedSocket.h"
#include "SocketManager.h"
namespace adchpp {
using namespace std;
using namespace boost::asio;
ManagedSocket::ManagedSocket(SocketManager &sm, const AsyncStreamPtr &sock_) :
sock(sock_),
overflow(time::not_a_date_time),
disc(time::not_a_date_time),
lastWrite(time::not_a_date_time),
sm(sm)
{ }
ManagedSocket::~ManagedSocket() throw() {
dcdebug("ManagedSocket deleted\n");
}
static size_t sum(const BufferList& l) {
size_t bytes = 0;
for(BufferList::const_iterator i = l.begin(); i != l.end(); ++i) {
bytes += (*i)->size();
}
return bytes;
}
size_t ManagedSocket::getQueuedBytes() const {
return sum(outBuf);
}
void ManagedSocket::write(const BufferPtr& buf, bool lowPrio /* = false */) throw() {
if(buf->size() == 0 || disconnecting())
return;
size_t queued = getQueuedBytes();
if(sm.getMaxBufferSize() > 0 && queued + buf->size() > sm.getMaxBufferSize()) {
if(lowPrio) {
return;
} else if(!overflow.is_not_a_date_time() && overflow + time::millisec(sm.getOverflowTimeout()) < time::now()) {
disconnect(Util::REASON_WRITE_OVERFLOW);
return;
} else {
overflow = time::now();
}
}
sm.getStats().queueBytes += buf->size();
sm.getStats().queueCalls++;
outBuf.push_back(buf);
prepareWrite();
}
// Simplified handlers to avoid bind complexity
namespace {
/** Keeper keeps a reference to the managed socket */
struct Keeper {
Keeper(const ManagedSocketPtr& ms_) : ms(ms_) { }
ManagedSocketPtr ms;
void operator()(const boost::system::error_code& ec, size_t bytes) { }
};
template<void (ManagedSocket::*F)(const boost::system::error_code&, size_t)>
struct Handler : Keeper {
Handler(const ManagedSocketPtr& ms) : Keeper(ms) { }
void operator()(const boost::system::error_code& ec, size_t bytes) {
(ms.get()->*F)(ec, bytes);
}
};
struct Disconnector {
Disconnector(const AsyncStreamPtr& stream_) : stream(stream_) { }
void operator()() { stream->close(); }
AsyncStreamPtr stream;
};
}
void ManagedSocket::prepareWrite() throw() {
if(!writing()) { // Not writing
if(!outBuf.empty()) {
lastWrite = time::now();
sock->write(outBuf, Handler<&ManagedSocket::completeWrite>(shared_from_this()));
}
} else if(time::now() > lastWrite + time::seconds(60)) {
disconnect(Util::REASON_WRITE_TIMEOUT);
}
}
void ManagedSocket::completeWrite(const boost::system::error_code& ec, size_t bytes) throw() {
lastWrite = time::not_a_date_time;
if(!ec) {
sm.getStats().sendBytes += bytes;
sm.getStats().sendCalls++;
while(bytes > 0) {
BufferPtr& p = *outBuf.begin();
if(p->size() <= bytes) {
bytes -= p->size();
outBuf.erase(outBuf.begin());
} else {
p = make_shared<Buffer>(p->data() + bytes, p->size() - bytes);
bytes = 0;
}
}
if(!overflow.is_not_a_date_time()) {
size_t left = getQueuedBytes();
if(left < sm.getMaxBufferSize()) {
overflow = time::not_a_date_time;
}
}
if(disconnecting() && outBuf.empty()) {
sock->shutdown(Keeper(shared_from_this()));
} else {
prepareWrite();
}
} else {
fail(Util::REASON_SOCKET_ERROR, ec.message());
}
}
void ManagedSocket::prepareRead() throw() {
// We first send in an empty buffer to get notification when there's data available
sock->prepareRead(BufferPtr(), Handler<&ManagedSocket::prepareRead2>(shared_from_this()));
}
void ManagedSocket::prepareRead2(const boost::system::error_code& ec, size_t) throw() {
if(!ec) {
// ADC commands are typically small - using a small buffer
// helps with fairness
// Calling available() on an ASIO socket seems to be terribly slow
// Also, we might end up here if the socket has been closed, in which
// case available would return 0 bytes...
// We can't make a synchronous receive here because when using SSL
// there might be data on the socket that won't translate into user data
// and thus read_some will block
// If there's no user data, this will effectively post a read operation
// with a buffer and waste memory...to be continued.
inBuf = make_shared<Buffer>(64);
sock->prepareRead(inBuf, Handler<&ManagedSocket::completeRead>(shared_from_this()));
} else {
fail(Util::REASON_SOCKET_ERROR, ec.message());
}
}
void ManagedSocket::completeRead(const boost::system::error_code& ec, size_t bytes) throw() {
if(!ec) {
try {
sm.getStats().recvBytes += bytes;
sm.getStats().recvCalls++;
inBuf->resize(bytes);
if(dataHandler) {
dataHandler(inBuf);
}
inBuf.reset();
prepareRead();
} catch(const boost::system::system_error& e) {
fail(Util::REASON_SOCKET_ERROR, e.code().message());
}
} else {
inBuf.reset();
fail(Util::REASON_SOCKET_ERROR, ec.message());
}
}
void ManagedSocket::completeAccept(const boost::system::error_code& ec) throw() {
if(!ec) {
if(connectedHandler)
connectedHandler();
sock->init(std::bind(&ManagedSocket::ready, shared_from_this()));
} else {
fail(Util::REASON_SOCKET_ERROR, ec.message());
}
}
void ManagedSocket::ready() throw() {
if(readyHandler)
readyHandler();
prepareRead();
}
void ManagedSocket::fail(Util::Reason reason, const std::string &info) throw() {
if(failedHandler) {
failedHandler(reason, info);
// using nullptr fails on older GCCs for which we're using nullptr.h; using 0 fails on VS...
#ifndef FAKE_NULLPTR
connectedHandler = nullptr;
readyHandler = nullptr;
dataHandler = nullptr;
failedHandler = nullptr;
#else
connectedHandler = 0;
readyHandler = 0;
dataHandler = 0;
failedHandler = 0;
#endif
}
}
struct Reporter {
Reporter(ManagedSocketPtr ms, void (ManagedSocket::*f)(Util::Reason reason, const std::string &info), Util::Reason reason, const std::string &info) :
ms(ms), f(f), reason(reason), info(info) { }
void operator()() { (ms.get()->*f)(reason, info); }
ManagedSocketPtr ms;
void (ManagedSocket::*f)(Util::Reason reason, const std::string &info);
Util::Reason reason;
std::string info;
};
void ManagedSocket::disconnect(Util::Reason reason, const std::string &info) throw() {
if(disconnecting()) {
return;
}
const auto timeout = sm.getDisconnectTimeout();
disc = time::now() + time::millisec(timeout);
sm.addJob(Reporter(shared_from_this(), &ManagedSocket::fail, reason, info));
if(!writing()) {
sock->shutdown(Keeper(shared_from_this()));
}
sm.addJob(timeout, Disconnector(sock));
}
bool ManagedSocket::disconnecting() const {
return !disc.is_not_a_date_time();
}
bool ManagedSocket::writing() const {
return !lastWrite.is_not_a_date_time();
}
}

117
src/adchpp/ManagedSocket.h Normal file
View File

@@ -0,0 +1,117 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_MANAGEDSOCKET_H
#define ADCHPP_MANAGEDSOCKET_H
#include "common.h"
#include "forward.h"
#include "Signal.h"
#include "Util.h"
#include "Buffer.h"
#include "AsyncStream.h"
#include "TimeUtil.h"
namespace adchpp {
/**
* An asynchronous socket managed by SocketManager.
*/
class ManagedSocket : private boost::noncopyable, public enable_shared_from_this<ManagedSocket> {
public:
ManagedSocket(SocketManager &sm, const AsyncStreamPtr& sock_);
/** Asynchronous write */
ADCHPP_DLL void write(const BufferPtr& buf, bool lowPrio = false) throw();
/** Returns the number of bytes in the output buffer; buffers must be locked */
ADCHPP_DLL size_t getQueuedBytes() const;
/** Asynchronous disconnect. Pending data will be written within the limits of the
* DisconnectTimeout setting, but no more data will be read. */
ADCHPP_DLL void disconnect(Util::Reason reason, const std::string &info = Util::emptyString) throw();
const std::string& getIp() const { return ip; }
void setIp(const std::string& ip_) { ip = ip_; }
typedef std::function<void()> ConnectedHandler;
void setConnectedHandler(const ConnectedHandler& handler) { connectedHandler = handler; }
typedef std::function<void()> ReadyHandler;
void setReadyHandler(const ReadyHandler& handler) { readyHandler = handler; }
typedef std::function<void(const BufferPtr&)> DataHandler;
void setDataHandler(const DataHandler& handler) { dataHandler = handler; }
typedef std::function<void(Util::Reason, const std::string &)> FailedHandler;
void setFailedHandler(const FailedHandler& handler) { failedHandler = handler; }
time::ptime getOverflow() { return overflow; }
time::ptime getLastWrite() { return lastWrite; }
~ManagedSocket() throw();
private:
friend class SocketManager;
friend class SocketFactory;
void completeAccept(const boost::system::error_code&) throw();
void ready() throw();
void prepareWrite() throw();
void completeWrite(const boost::system::error_code& ec, size_t bytes) throw();
void prepareRead() throw();
void prepareRead2(const boost::system::error_code& ec, size_t bytes) throw();
void completeRead(const boost::system::error_code& ec, size_t bytes) throw();
void fail(Util::Reason reason, const std::string &info) throw();
bool disconnecting() const;
bool writing() const;
AsyncStreamPtr sock;
/** Output buffer, for storing data that's waiting to be transmitted */
BufferList outBuf;
/** Input buffer used when receiving data */
BufferPtr inBuf;
/** Overflow timer, the time when the socket started to overflow */
time::ptime overflow;
/** Time when this socket will be disconnected regardless of buffers */
time::ptime disc;
/** Last time that a write started, 0 if no active write */
time::ptime lastWrite;
std::string ip;
ConnectedHandler connectedHandler;
ReadyHandler readyHandler;
DataHandler dataHandler;
FailedHandler failedHandler;
SocketManager &sm;
};
}
#endif // MANAGEDSOCKET_H

108
src/adchpp/Mutex.h Normal file
View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_MUTEX_H_
#define ADCHPP_MUTEX_H_
#include "Thread.h"
namespace adchpp {
template<typename Mutex>
class ScopedLock {
public:
ScopedLock(Mutex& m_) : m(m_) { m.lock(); }
~ScopedLock() { m.unlock(); }
private:
Mutex& m;
};
#if defined(_WIN32)
class RecursiveMutex : private boost::noncopyable {
public:
RecursiveMutex() { InitializeCriticalSection(&cs); }
~RecursiveMutex() { DeleteCriticalSection(&cs); }
void lock() { EnterCriticalSection(&cs); }
void unlock() { LeaveCriticalSection(&cs); }
typedef ScopedLock<RecursiveMutex> Lock;
private:
CRITICAL_SECTION cs;
};
class FastMutex : private boost::noncopyable {
public:
FastMutex() : val(0) { }
~FastMutex() { }
void lock() { while(InterlockedExchange(&val, 1) == 1) Thread::yield(); }
void unlock() { InterlockedExchange(&val, 0); }
typedef ScopedLock<FastMutex> Lock;
private:
long val;
};
#elif defined(HAVE_PTHREAD)
class RecursiveMutex : private boost::noncopyable {
public:
RecursiveMutex() throw() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mtx, &attr);
pthread_mutexattr_destroy(&attr);
}
~RecursiveMutex() throw() { pthread_mutex_destroy(&mtx); }
void lock() throw() { pthread_mutex_lock(&mtx); }
void unlock() throw() { pthread_mutex_unlock(&mtx); }
typedef ScopedLock<RecursiveMutex> Lock;
private:
pthread_mutex_t mtx;
};
class FastMutex : private boost::noncopyable {
public:
FastMutex() throw() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
pthread_mutex_init(&mtx, &attr);
pthread_mutexattr_destroy(&attr);
}
~FastMutex() throw() { pthread_mutex_destroy(&mtx); }
void lock() throw() { pthread_mutex_lock(&mtx); }
void unlock() throw() { pthread_mutex_unlock(&mtx); }
typedef ScopedLock<FastMutex> Lock;
private:
pthread_mutex_t mtx;
};
#else
#error No mutex found
#endif
}
#endif /*MUTEX_H_*/

62
src/adchpp/Plugin.h Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_PLUGIN_H_
#define ADCHPP_PLUGIN_H_
#include "forward.h"
namespace adchpp {
/**
* Public plugin interface, for plugin intercom.
* Plugins that register a public interface must inherit from this class.
* Plugins requesting another plugins interface will get a pointer to this
* class and must upcast it (using dynamic_cast<> and check NULL to be safe).
*/
class Plugin {
public:
virtual ~Plugin() { }
/** @return API version for a plugin (incremented every time API changes) */
virtual int getVersion() = 0;
protected:
Plugin() { }
};
typedef std::function<void (void*)> PluginDataDeleter;
class PluginData {
public:
template<typename T>
static void simpleDataDeleter(void* p) { delete reinterpret_cast<T*>(p); }
private:
friend class PluginManager;
friend class Entity;
PluginData(const PluginDataDeleter& deleter_) : deleter(deleter_) { }
void operator()(void* p) { if(deleter) deleter(p); }
PluginDataDeleter deleter;
};
typedef shared_ptr<PluginData> PluginDataHandle;
}
#endif /* PLUGIN_H_ */

View File

@@ -0,0 +1,214 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "PluginManager.h"
#include "SimpleXML.h"
#include "LogManager.h"
#include "SocketManager.h"
#include "version.h"
#include "File.h"
#include "Text.h"
#include "Core.h"
#ifdef _WIN32
#define PLUGIN_EXT _T(".dll")
#define PM_LOAD_LIBRARY(filename) ::LoadLibrary(filename)
#define PM_UNLOAD_LIBRARY(lib) ::FreeLibrary(lib)
#define PM_GET_ADDRESS(lib, name) ::GetProcAddress(lib, name)
#define PM_GET_ERROR_STRING() Util::translateError(GetLastError())
#else
#include "dlfcn.h"
#define PLUGIN_EXT ".so"
#define PM_LOAD_LIBRARY(filename) ::dlopen(filename, RTLD_LAZY | RTLD_GLOBAL)
#define PM_UNLOAD_LIBRARY(lib) ::dlclose(lib)
#define PM_GET_ADDRESS(lib, name) ::dlsym(lib, name)
#define PM_GET_ERROR_STRING() ::dlerror()
#endif
namespace adchpp {
using namespace std;
using std::placeholders::_1;
const string PluginManager::className = "PluginManager";
PluginManager::PluginManager(Core &core) throw() : core(core) {
}
void PluginManager::attention(const function<void()>& f) {
core.addJob(f);
}
void PluginManager::load() {
for(StringIter i = plugins.begin(); i != plugins.end(); ++i) {
loadPlugin(*i + PLUGIN_EXT);
}
}
bool PluginManager::loadPlugin(const string& file) {
if(file.length() < 3) {
return false;
}
plugin_t h;
#ifndef _WIN32
if(!File::isAbsolutePath(file)) {
h = PM_LOAD_LIBRARY((pluginPath + file).c_str());
} else {
h = PM_LOAD_LIBRARY(file.c_str());
}
#else
if(!File::isAbsolutePath(file)) {
h = LoadLibraryEx((pluginPath + file).c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES);
} else {
h = LoadLibraryEx(file.c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES);
}
#endif
if(h == NULL) {
LOG(className, "Failed to load " + Text::utf8ToAcp(file) + ": " + PM_GET_ERROR_STRING());
return false;
}
PLUGIN_GET_VERSION v = (PLUGIN_GET_VERSION)PM_GET_ADDRESS(h, "pluginGetVersion");
if(v != NULL) {
double ver = v();
if(ver == PLUGINVERSION) {
#ifdef _WIN32
// Reload plugin with references resolved...
FreeLibrary(h);
if(!File::isAbsolutePath(file)) {
h = PM_LOAD_LIBRARY((pluginPath + file).c_str());
} else {
h = PM_LOAD_LIBRARY(file.c_str());
}
if(h == NULL) {
LOG(className, "Failed to load " + Text::utf8ToAcp(file) + ": " + PM_GET_ERROR_STRING());
return false;
}
#endif
PLUGIN_LOAD l = (PLUGIN_LOAD)PM_GET_ADDRESS(h, "pluginLoad");
PLUGIN_UNLOAD u = (PLUGIN_UNLOAD)PM_GET_ADDRESS(h, "pluginUnload");
if(l != NULL && u != NULL) {
int i = l(this);
if(i != 0) {
LOG(className, "Failed to load plugin " + Text::utf8ToAcp(file) + " (Error " + Util::toString(i) + ")");
} else {
// Wonderful, we have a plugin...
active.push_back(PluginInfo(h, v, l, u));
LOG(className, Text::utf8ToAcp(file) + " loaded");
return true;
}
} else {
LOG(className, Text::utf8ToAcp(file) + " is not a valid ADCH++ plugin");
}
} else {
LOG(className, Text::utf8ToAcp(file) + " is for another version of ADCH++ (" + Util::toString(ver) + "), please get the correct one from the author");
}
} else {
LOG(className, Text::utf8ToAcp(file) + " is not a valid ADCH++ plugin");
}
PM_UNLOAD_LIBRARY(h);
return false;
}
void PluginManager::shutdown() {
registry.clear();
for(PluginList::reverse_iterator i = active.rbegin(); i != active.rend(); ++i)
i->pluginUnload();
#ifndef HAVE_BROKEN_MTALLOC
for(PluginList::reverse_iterator i = active.rbegin(); i != active.rend(); ++i)
PM_UNLOAD_LIBRARY(i->handle);
#endif
active.clear();
}
PluginManager::CommandDispatch::CommandDispatch(PluginManager& pm, const std::string& name_, const PluginManager::CommandSlot& f_) :
name('+' + name_),
f(f_),
pm(&pm)
{
}
void PluginManager::CommandDispatch::operator()(Entity& e, AdcCommand& cmd, bool& ok) {
if(e.getState() != Entity::STATE_NORMAL) {
return;
}
if(cmd.getCommand() != AdcCommand::CMD_MSG) {
return;
}
if(cmd.getParameters().size() < 1) {
return;
}
StringList l;
Util::tokenize(l, cmd.getParameters()[0], ' ');
if(l[0] != name) {
return;
}
l[0] = name.substr(1);
if(!pm->handleCommand(e, l)) {
return;
}
cmd.setPriority(AdcCommand::PRIORITY_IGNORE);
f(e, l, ok);
}
ClientManager::SignalReceive::Connection PluginManager::onCommand(const std::string& commandName, const CommandSlot& f) {
return core.getClientManager().signalReceive().connect(CommandDispatch(*this, commandName, f));
}
PluginManager::CommandSignal& PluginManager::getCommandSignal(const std::string& commandName) {
CommandHandlers::iterator i = commandHandlers.find(commandName);
if(i == commandHandlers.end())
return commandHandlers.insert(make_pair(commandName, CommandSignal())).first->second;
return i->second;
}
bool PluginManager::handleCommand(Entity& e, const StringList& l) {
CommandHandlers::iterator i = commandHandlers.find(l[0]);
if(i == commandHandlers.end())
return true;
bool ok = true;
i->second(e, l, ok);
return ok;
}
Core &PluginManager::getCore() { return core; }
}

257
src/adchpp/PluginManager.h Normal file
View File

@@ -0,0 +1,257 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**
* @page PluginAPI Plugin API Information
* @section General General
*
* ADCH++ contains a rather powerful plugin API that can be used to create advanced
* plugins that change or add to ADCH++'s behaviour. Most plugins will need
* PluginManager.h, ClientManager.h and Client.h included to work, even though the
* other header files are available as well (they're more likely to change in future
* versions though). You can use any method that is declared as DLL or is inline, the
* others are meant to be internal to ADCH++, very likely to change/disappear and will
* generate link errors (when compiling under windows anyway). When starting a plugin
* project I strongly recommend that you take one of the existing plugins and modify
* it to your needs (to get all compiler settings and base code right).
*
* @section Versions Versions
*
* Due to C++ name mangling, plugins are generally valid only for a certain version
* of the ADCH++ plugin API. This version usually follows the main ADCH++ version,
* unless a small update is made that I judge shouldn't affect plugins in any way.
* Most of the time, recompiling the plugin should be enough, unless any major changes
* have been made, and your plugin doesn't rely on the nasty internals.
*
* @section Threads Threads
*
* ADCH++ has two main threads running when operating. One handles all network
* communication while the other does all other work (handle protocol data and
* so on). All plugins are run in the worker thread, which is the only thread
* visible to the API. You are only allowed to interact with ADCH++ from this
* thread, as none of the API is thread safe, unless otherwise noted. This has a
* few important consequences. First off, you can assume that your plugin will
* only be called by this thread, which means that you don't have to worry about
* multithreading issues unless you start threads by yourself. Second, any work you
* do in a plugin halts <b>all</b> of ADCH++'s processing (apart from receiving/sending
* buffered data), in other words, don't do any lengthy processing in the on methods,
* as the whole of ADCH++ will suffer. Third, if you indeed start another thread, make
* sure you don't use any API functions from it apart from those explicitly marked
* as thread safe. To indicate from a plugin that you have work to do in the main
* worker thread, call PluginManager::attention().
*/
#ifndef ADCHPP_PLUGINMANAGER_H
#define ADCHPP_PLUGINMANAGER_H
#include "version.h"
#include "Signal.h"
#include "ClientManager.h"
#include "Plugin.h"
namespace adchpp {
class SimpleXML;
#ifdef _WIN32
#ifdef BUILDING_ADCHPP
#define PLUGIN_API
#else
#define PLUGIN_API __declspec(dllexport)
#endif
typedef HMODULE plugin_t;
#else // WIN32
#ifdef BUILDING_ADCHPP
#define PLUGIN_API
#else
#define PLUGIN_API __attribute__ ((visibility("default")))
#endif
typedef void* plugin_t;
#endif // WIN32
/**
* PLUGIN_API double pluginGetVersion()
* This function should just return the constant PLUGINVERSIONFLOAT
* so that the pluginmanager can determine if this plugin should
* be loaded or not
*/
typedef int (*PLUGIN_GET_VERSION)();
/**
* PLUGIN_API void pluginLoad()
* This function is called when the hub is starting up and loading the plugin.
* Here you should load any data your plugin might need and connect to any
* Managers you might be interested in. Note; you also have to connect to
* PluginManager itself to receive its events.
* @return 0 if the plugin was loaded ok, != 0 otherwise (the number will be logged,
* use as error code). Plugin dll will get unloaded without calling pluginUnload if the return
* value is not 0 here.
* @see pluginUnload
*/
typedef int (*PLUGIN_LOAD)(PluginManager *);
/**
* PLUGIN_API void pluginUnload()
* Called when the hub is shutting down
* @see pluginLoad
*/
typedef void (*PLUGIN_UNLOAD)();
class PluginManager
{
public:
typedef std::unordered_map<std::string, shared_ptr<Plugin>> Registry;
/**
* This is a thread-safe method to call when you need to perform some work
* in the main ADCH++ worker thread. Your job will be executed once, when
* time permits.
*/
ADCHPP_DLL void attention(const std::function<void()>& f);
/**
* Get a list of currently loaded plugins
*/
const StringList& getPluginList() const {
return plugins;
}
void setPluginList(const StringList& pluginList) { plugins = pluginList; }
/**
* Get the plugin path as set in adchpp.xml
*/
const std::string& getPluginPath() const {
return pluginPath;
}
void setPluginPath(const std::string& path) { pluginPath = path; }
/**
* Register a plugin data type to be used with Client::setPSD and friends.
* When data is removed, the deleter function will automatically be called
* with the data as parameter, allowing automatic life cycle managment for
* plugin-specific data.
*/
PluginDataHandle registerPluginData(const PluginDataDeleter& deleter_) { return PluginDataHandle(new PluginData(deleter_)); }
/**
* Register a plugin interface under a name.
* @return false if name was already registered and call fails
*/
bool registerPlugin(const std::string& name, shared_ptr<Plugin> ptr) {
return registry.insert(std::make_pair(name, ptr)).second;
}
/** @return True if the plugin existed and was thus unregistered */
bool unregisterPlugin(const std::string& name) {
return registry.erase(name) > 0;
}
/**
* @return Plugin interface, or an empty pointer if not found
*/
shared_ptr<Plugin> getPlugin(const std::string& name) {
auto i = registry.find(name);
return i == registry.end() ? shared_ptr<Plugin>() : i->second;
}
/**
* The full map of registered plugins.
*/
const Registry& getPlugins() const {
return registry;
}
typedef SignalTraits<void (Entity&, const StringList&, bool&)>::Signal CommandSignal;
typedef CommandSignal::Slot CommandSlot;
/**
* Utility function to handle +-commands from clients
* The parameters are the same as ClientManager::signalReceive, only that the parameters will
* have been parsed already, and the function will only be called if the command name matches
*/
ADCHPP_DLL ClientManager::SignalReceive::Connection onCommand(const std::string& commandName, const CommandSlot& f);
/// Handle +-commands set by another script, and possibly prevent them from being dispatched
ADCHPP_DLL CommandSignal& getCommandSignal(const std::string& commandName);
/** @internal */
void load();
/** @internal */
void shutdown();
ADCHPP_DLL Core &getCore();
private:
friend class Core;
PluginManager(Core &core) throw();
class PluginInfo {
public:
PluginInfo(plugin_t h, PLUGIN_GET_VERSION v, PLUGIN_LOAD l, PLUGIN_UNLOAD u) :
handle(h), pluginGetVersion(v), pluginLoad(l), pluginUnload(u) { }
plugin_t handle;
PLUGIN_GET_VERSION pluginGetVersion;
PLUGIN_LOAD pluginLoad;
PLUGIN_UNLOAD pluginUnload;
};
struct CommandDispatch {
CommandDispatch(PluginManager &pm, const std::string& name_, const PluginManager::CommandSlot& f_);
void operator()(Entity& e, AdcCommand& cmd, bool& ok);
private:
std::string name;
PluginManager::CommandSlot f;
PluginManager *pm;
};
friend struct CommandDispatch;
typedef std::vector<PluginInfo> PluginList;
typedef PluginList::iterator PluginIter;
PluginList active;
Registry registry;
StringList plugins;
std::string pluginPath;
Core &core;
static const std::string className;
bool loadPlugin(const std::string& file);
typedef std::unordered_map<std::string, CommandSignal> CommandHandlers;
CommandHandlers commandHandlers;
bool handleCommand(Entity& e, const StringList& l);
};
}
#endif // PLUGINMANAGER_H

94
src/adchpp/Pool.h Normal file
View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_POOL_H
#define ADCHPP_POOL_H
#include "Mutex.h"
namespace adchpp {
template<class T>
struct PoolDummy {
void operator()(T&) { }
};
template<typename T, class Clear = PoolDummy<T> >
class SimplePool {
public:
SimplePool() : busy(0) { }
~SimplePool() { dcdebug("Busy pool objects: %d\n", (int)busy); }
T* get() {
busy++;
if(!free.empty()) {
T* tmp = free.back();
free.pop_back();
return tmp;
} else {
return new T;
}
}
void put(T* item) {
dcassert(busy > 0);
busy--;
Clear()(*item);
// Remove some objects every now and then...
if(free.size() > (2*busy) && free.size() > 32) {
dcdebug("Clearing pool\n");
while(free.size() > busy / 2) {
delete free.back();
free.pop_back();
}
}
free.push_back(item);
}
private:
size_t busy;
std::vector<T*> free;
};
/** A thread safe object pool */
template<class T, class Clear = PoolDummy<T> >
class Pool {
public:
Pool() { }
~Pool() { }
T* get() {
FastMutex::Lock l(mtx);
return pool.get();
}
void put(T* obj) {
FastMutex::Lock l(mtx);
pool.put(obj);
}
private:
Pool(const Pool&);
Pool& operator=(const Pool&);
FastMutex mtx;
SimplePool<T, Clear> pool;
};
}
#endif //POOL_H_

68
src/adchpp/SConscript Normal file
View File

@@ -0,0 +1,68 @@
# vim: set filetype=py
def getRevision(env):
"""Attempt to get information about the repository, via the "hg log"
command. Its output is formatted via the "-T" parameter (see "hg templates"
for details).
:return: Version information string, or "[unknown]" on failure.
:rtype: str.
"""
try:
import subprocess
ret = subprocess.check_output(
'hg log -r tip -T "{node | short} - {date | isodate}"',
shell=True
)
if ret:
return ret
except:
pass
return '[unknown]'
Import('dev source_path')
env, target, sources = dev.prepare_build(source_path, 'adchpp', shared_precompiled_header = 'adchpp')
env.Append(CPPPATH = ['.'])
env.Append(CPPDEFINES=["BUILDING_ADCHPP=1"])
if env['CC'] == 'cl': # MSVC
env.Append(LIBS = ['advapi32', 'user32'])
if 'HAVE_DL' in env['CPPDEFINES']:
env.Append(LIBS = ['dl'])
if 'HAVE_PTHREAD' in env['CPPDEFINES']:
env.Append(LIBS = ['pthread'])
if 'HAVE_OPENSSL' in env['CPPDEFINES']:
if dev.is_win32():
if env['CC'] == 'cl': # MSVC
if env['mode'] == 'debug':
env.Prepend(LIBS = ['ssleay32d', 'libeay32d'])
else:
env.Prepend(LIBS = ['ssleay32', 'libeay32'])
else:
env.Prepend(LIBS = ['ssl', 'crypto'])
env.Append(LIBS = ['gdi32']) # something in OpenSSL uses CreateDC etc...
env.Append(CPPPATH=['#/openssl/include'])
openssl_lib = '#/openssl/lib/'
if env['arch'] != 'x86':
openssl_lib += env['arch'] + '/'
env.Append(LIBPATH=[openssl_lib])
else:
env.Prepend(LIBS = ['ssl', 'crypto'])
for i, source in enumerate(sources):
if source.find("version.cpp") != -1:
rev = ['ADCHPP_REVISION=' + getRevision(env)]
sources[i] = env.SharedObject(source, CPPDEFINES=env['CPPDEFINES'] + rev)
headers=dev.get_sources(source_path, "*.h")
ret = env.SharedLibrary(target, sources)
Return('ret')

45
src/adchpp/ServerInfo.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_SERVER_INFO_H
#define ADCHPP_SERVER_INFO_H
namespace adchpp {
struct ServerInfo {
std::string ip;
std::string port;
struct TLSInfo {
std::string cert;
std::string pkey;
std::string trustedPath;
std::string dh;
private:
friend struct ServerInfo;
bool secure() const {
return !cert.empty() && !pkey.empty() && !trustedPath.empty() && !dh.empty();
}
} TLSParams;
bool secure() const { return TLSParams.secure(); }
};
}
#endif

124
src/adchpp/Signal.h Normal file
View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_SIGNAL_H
#define ADCHPP_SIGNAL_H
namespace adchpp {
struct Connection : private boost::noncopyable {
public:
Connection() { }
virtual ~Connection() { }
virtual void disconnect() = 0;
};
typedef std::unique_ptr<Connection> ConnectionPtr;
template<typename F>
class Signal {
public:
typedef std::function<F> Slot;
typedef std::list<Slot> SlotList;
typedef F FunctionType;
template<typename T0>
void operator()(T0&& t0) {
for(auto i = slots.begin(), iend = slots.end(); i != iend;) {
(*i++)(std::forward<T0>(t0));
}
}
template<typename T0, typename T1>
void operator()(T0&& t0, T1&& t1) {
for(auto i = slots.begin(), iend = slots.end(); i != iend;) {
(*i++)(std::forward<T0>(t0), std::forward<T1>(t1));
}
}
template<typename T0, typename T1, typename T2>
void operator()(T0&& t0, T1&& t1, T2&& t2) {
for(auto i = slots.begin(), iend = slots.end(); i != iend;) {
(*i++)(std::forward<T0>(t0), std::forward<T1>(t1), std::forward<T2>(t2));
}
}
template<typename T>
ConnectionPtr connect(const T& f) { return ConnectionPtr(new SlotConnection(this, slots.insert(slots.end(), f))); }
~Signal() { }
private:
SlotList slots;
void disconnect(const typename SlotList::iterator& i) {
slots.erase(i);
}
struct SlotConnection : public Connection {
SlotConnection(Signal<F>* sig_, const typename SlotList::iterator& i_) : sig(sig_), i(i_) { }
virtual void disconnect() { if(sig) sig->disconnect(i), sig = 0; }
Signal<F>* sig;
typename Signal<F>::SlotList::iterator i;
};
};
struct ManagedConnection : private boost::noncopyable {
ManagedConnection(ConnectionPtr&& conn_) : conn(move(conn_)) {
}
void disconnect() {
if(conn.get()) {
conn->disconnect();
conn.reset();
}
}
void release() {
conn.reset();
}
~ManagedConnection() {
disconnect();
}
private:
ConnectionPtr conn;
};
typedef shared_ptr<ManagedConnection> ManagedConnectionPtr;
template<typename F1, typename F2>
inline ManagedConnectionPtr manage(Signal<F1>* signal, const F2& f) {
return make_shared<ManagedConnection>(signal->connect(f));
}
inline ManagedConnectionPtr manage(ConnectionPtr && conn) {
return make_shared<ManagedConnection>(move(conn));
}
template<typename F>
struct SignalTraits {
typedef adchpp::Signal<F> Signal;
typedef adchpp::ConnectionPtr Connection;
typedef adchpp::ManagedConnectionPtr ManagedConnection;
};
}
#endif // SIGNAL_H

349
src/adchpp/SimpleXML.cpp Normal file
View File

@@ -0,0 +1,349 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "SimpleXML.h"
namespace adchpp {
using namespace std;
SimpleXML::SimpleXML(int numAttribs) : attribs(numAttribs), found(false) {
root = current = new Tag("BOGUSROOT", Util::emptyString, NULL);
}
SimpleXML::~SimpleXML() {
delete root;
}
void SimpleXML::escape(string& aString, bool aAttrib, bool aLoading /* = false */) {
string::size_type i = 0;
const char* chars = aAttrib ? "<&>'\"" : "<&>";
if(aLoading) {
while((i = aString.find('&', i)) != string::npos) {
if(aString.compare(i+1, 3, "lt;") == 0) {
aString.replace(i, 4, 1, '<');
} else if(aString.compare(i+1, 4, "amp;") == 0) {
aString.replace(i, 5, 1, '&');
} else if(aString.compare(i+1, 3, "gt;") == 0) {
aString.replace(i, 4, 1, '>');
} else if(aAttrib) {
if(aString.compare(i+1, 5, "apos;") == 0) {
aString.replace(i, 6, 1, '\'');
} else if(aString.compare(i+1, 5, "quot;") == 0) {
aString.replace(i, 6, 1, '"');
}
}
i++;
}
i = 0;
if( (i = aString.find('\n')) != string::npos) {
if(i > 0 && aString[i-1] != '\r') {
// This is a unix \n thing...convert it...
i = 0;
while( (i = aString.find('\n', i) ) != string::npos) {
if(aString[i-1] != '\r')
aString.insert(i, 1, '\r');
i+=2;
}
}
}
} else {
while( (i = aString.find_first_of(chars, i)) != string::npos) {
switch(aString[i]) {
case '<': aString.replace(i, 1, "&lt;"); i+=4; break;
case '&': aString.replace(i, 1, "&amp;"); i+=5; break;
case '>': aString.replace(i, 1, "&gt;"); i+=4; break;
case '\'': aString.replace(i, 1, "&apos;"); i+=6; break;
case '"': aString.replace(i, 1, "&quot;"); i+=6; break;
default: dcasserta(0);
}
}
}
}
void SimpleXML::Tag::appendAttribString(string& tmp) {
for(AttribIter i = attribs.begin(); i!= attribs.end(); ++i) {
tmp.append(i->first);
tmp.append("=\"", 2);
if(needsEscape(i->second, true)) {
string tmp2(i->second);
escape(tmp2, true);
tmp.append(tmp2);
} else {
tmp.append(i->second);
}
tmp.append("\" ", 2);
}
tmp.erase(tmp.size()-1);
}
string SimpleXML::Tag::toXML(int indent) {
if(children.empty() && data.empty()) {
string tmp;
tmp.reserve(indent + name.length() + 30);
tmp.append(indent, '\t');
tmp.append(1, '<');
tmp.append(name);
tmp.append(1, ' ');
appendAttribString(tmp);
tmp.append("/>\r\n", 4);
return tmp;
} else {
string tmp;
tmp.append(indent, '\t');
tmp.append(1, '<');
tmp.append(name);
tmp.append(1, ' ');
appendAttribString(tmp);
if(children.empty()) {
tmp.append(1, '>');
if(needsEscape(data, false)) {
string tmp2(data);
escape(tmp2, false);
tmp.append(tmp2);
} else {
tmp.append(data);
}
} else {
tmp.append(">\r\n", 3);
for(Iter i = children.begin(); i!=children.end(); ++i) {
tmp.append((*i)->toXML(indent + 1));
}
tmp.append(indent, '\t');
}
tmp.append("</", 2);
tmp.append(name);
tmp.append(">\r\n", 3);
return tmp;
}
}
bool SimpleXML::findChild(const string& aName) const throw() {
dcassert(current != NULL);
if(found && currentChild != current->children.end())
currentChild++;
while(currentChild!=current->children.end()) {
if(aName.empty() || (*currentChild)->name == aName) {
found = true;
return true;
} else
currentChild++;
}
return false;
}
void SimpleXML::stepIn() const throw(SimpleXMLException) {
checkChildSelected();
current = *currentChild;
currentChild = current->children.begin();
found = false;
}
void SimpleXML::stepOut() const throw(SimpleXMLException) {
if(current == root)
throw SimpleXMLException("Already at lowest level");
dcassert(current->parent != NULL);
currentChild = find(current->parent->children.begin(), current->parent->children.end(), current);
current = current->parent;
found = true;
}
string::size_type SimpleXML::Tag::loadAttribs(const string& tmp, string::size_type start) throw(SimpleXMLException) {
string::size_type i = start;
string::size_type j;
for(;;) {
j = tmp.find('=', i);
if(j == string::npos) {
throw SimpleXMLException("Missing '=' in " + name);
}
if(tmp[j+1] != '"' && tmp[j+1] != '\'') {
throw SimpleXMLException("Invalid character after '=' in " + name);
}
string::size_type x = j + 2;
string::size_type y = tmp.find(tmp[j+1], x);
if(y == string::npos) {
throw SimpleXMLException("Missing '" + string(1, tmp[j+1]) + "' in " + name);
}
// Ok, we have an attribute...
attribs.push_back(make_pair(tmp.substr(i, j-i), tmp.substr(x, y-x)));
escape(attribs.back().second, true, true);
i = tmp.find_first_not_of("\r\n\t ", y + 1);
if(tmp[i] == '/' || tmp[i] == '>')
return i;
}
}
string::size_type SimpleXML::Tag::fromXML(const string& tmp, string::size_type start, int aa, bool isRoot /* = false */) throw(SimpleXMLException) {
string::size_type i = start;
string::size_type j;
bool hasChildren = false;
dcassert(tmp.size() > 0);
for(;;) {
j = tmp.find('<', i);
if(j == string::npos) {
if(isRoot) {
throw SimpleXMLException("Invalid XML file, missing root tag");
} else {
throw SimpleXMLException("Missing end tag in " + name);
}
}
// Check that we have at least 3 more characters as the shortest valid xml tag is <a/>...
if((j + 3) > tmp.size()) {
throw SimpleXMLException("Missing end tag in " + name);
}
Ptr child = NULL;
i = j + 1;
if(tmp[i] == '?') {
// <? processing instruction ?>, ignore...
i = tmp.find("?>", i);
if(i == string::npos) {
throw SimpleXMLException("Missing '?>' in " + name);
}
i+= 2;
continue;
}
if(tmp[i] == '!' && tmp[i+1] == '-' && tmp[i+2] == '-') {
// <!-- comment -->, ignore...
i = tmp.find("-->", i);
if(i == string::npos) {
throw SimpleXMLException("Missing '-->' in " + name);
}
continue;
}
// Check if we reached the end tag
if(tmp[i] == '/') {
i++;
if( (tmp.compare(i, name.length(), name) == 0) &&
(tmp[i + name.length()] == '>') )
{
if(!hasChildren) {
data = tmp.substr(start, i - start - 2);
escape(data, false, true);
}
return i + name.length() + 1;
} else {
throw SimpleXMLException("Missing end tag in " + name);
}
}
// Alright, we have a real tag for sure...now get the name of it.
j = tmp.find_first_of("\r\n\t />", i);
if(j == string::npos) {
throw SimpleXMLException("Missing '>' in " + name);
}
child = new Tag(tmp.substr(i, j-i), Util::emptyString, this, aa);
// Put it here immideately to avoid mem leaks
children.push_back(child);
if(tmp[j] == ' ')
j = tmp.find_first_not_of("\r\n\t ", j+1);
if(j == string::npos) {
throw SimpleXMLException("Missing '>' in " + name);
}
if(tmp[j] != '/' && tmp[j] != '>') {
// We have attribs...
j = child->loadAttribs(tmp, j);
}
if(tmp[j] == '>') {
// This is a real tag with data etc...
hasChildren = true;
j = child->fromXML(tmp, j+1, aa);
} else {
// A simple tag (<xxx/>
j++;
}
i = j;
if(isRoot) {
if(tmp.find('<', i) != string::npos) {
throw SimpleXMLException("Invalid XML file, multiple root tags");
}
return tmp.length();
}
}
}
void SimpleXML::addTag(const string& aName, const string& aData /* = "" */) throw(SimpleXMLException) {
if(aName.empty()) {
throw SimpleXMLException("Empty tag names not allowed");
}
if(current == root) {
if(current->children.empty()) {
current->children.push_back(new Tag(aName, aData, root, attribs));
currentChild = current->children.begin();
} else {
throw SimpleXMLException("Only one root tag allowed");
}
} else {
current->children.push_back(new Tag(aName, aData, current, attribs));
currentChild = current->children.end() - 1;
}
}
void SimpleXML::addAttrib(const string& aName, const string& aData) throw(SimpleXMLException) {
if(current==root)
throw SimpleXMLException("No tag is currently selected");
current->attribs.push_back(make_pair(aName, aData));
}
void SimpleXML::addChildAttrib(const string& aName, const string& aData) throw(SimpleXMLException) {
checkChildSelected();
(*currentChild)->attribs.push_back(make_pair(aName, aData));
}
void SimpleXML::fromXML(const string& aXML) throw(SimpleXMLException) {
if(root) {
delete root;
}
root = new Tag("BOGUSROOT", Util::emptyString, NULL, 0);
root->fromXML(aXML, 0, attribs, true);
if(root->children.size() != 1) {
throw SimpleXMLException("Invalid XML file, missing or multiple root tags");
}
current = root;
resetCurrentChild();
}
}

191
src/adchpp/SimpleXML.h Normal file
View File

@@ -0,0 +1,191 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_SIMPLEXML_H
#define ADCHPP_SIMPLEXML_H
#include "Exception.h"
#include "Util.h"
namespace adchpp {
STANDARD_EXCEPTION(SimpleXMLException);
/**
* A simple XML class that loads an XML-ish structure into an internal tree
* and allows easy access to each element through a "current location".
*/
class SimpleXML : private boost::noncopyable
{
public:
ADCHPP_DLL SimpleXML(int numAttribs = 0);
ADCHPP_DLL ~SimpleXML();
ADCHPP_DLL void addTag(const std::string& aName, const std::string& aData = Util::emptyString) throw(SimpleXMLException);
void addTag(const std::string& aName, int aData) throw(SimpleXMLException) {
addTag(aName, Util::toString(aData));
}
void addTag(const std::string& aName, int64_t aData) throw(SimpleXMLException) {
addTag(aName, Util::toString(aData));
}
template<typename T>
void addAttrib(const std::string& aName, const T& aData) throw(SimpleXMLException) {
addAttrib(aName, Util::toString(aData));
}
ADCHPP_DLL void addAttrib(const std::string& aName, const std::string& aData) throw(SimpleXMLException);
template <typename T>
void addChildAttrib(const std::string& aName, const T& aData) throw(SimpleXMLException) {
addChildAttrib(aName, Util::toString(aData));
}
ADCHPP_DLL void addChildAttrib(const std::string& aName, const std::string& aData) throw(SimpleXMLException);
const std::string& getData() const {
dcassert(current != NULL);
return current->data;
}
ADCHPP_DLL void stepIn() const throw(SimpleXMLException);
ADCHPP_DLL void stepOut() const throw(SimpleXMLException);
void resetCurrentChild() const throw() {
found = false;
dcassert(current != NULL);
currentChild = current->children.begin();
}
ADCHPP_DLL bool findChild(const std::string& aName) const throw();
const std::string& getChildName() const {
checkChildSelected();
return (*currentChild)->name;
}
const std::string& getChildData() const {
checkChildSelected();
return (*currentChild)->data;
}
const std::string& getChildAttrib(const std::string& aName, const std::string& aDefault = Util::emptyString) const {
checkChildSelected();
return (*currentChild)->getAttrib(aName, aDefault);
}
int getIntChildAttrib(const std::string& aName) const {
checkChildSelected();
return Util::toInt(getChildAttrib(aName));
}
int64_t getLongLongChildAttrib(const std::string& aName) const {
checkChildSelected();
return Util::toInt64(getChildAttrib(aName));
}
bool getBoolChildAttrib(const std::string& aName) const {
checkChildSelected();
const std::string& tmp = getChildAttrib(aName);
return (tmp.size() > 0) && tmp[0] == '1';
}
ADCHPP_DLL void fromXML(const std::string& aXML) throw(SimpleXMLException);
std::string toXML() { return (!root->children.empty()) ? root->children[0]->toXML(0) : Util::emptyString; }
ADCHPP_DLL static void escape(std::string& aString, bool aAttrib, bool aLoading = false);
/**
* This is a heurestic for whether escape needs to be called or not. The results are
* only guaranteed for false, i e sometimes true might be returned even though escape
* was not needed...
*/
static bool needsEscape(const std::string& aString, bool aAttrib, bool aLoading = false) {
return ((aLoading) ? aString.find('&') : aString.find_first_of(aAttrib ? "<&>'\"" : "<&>")) != std::string::npos;
}
private:
class Tag {
public:
typedef Tag* Ptr;
typedef std::vector<Ptr> List;
typedef List::iterator Iter;
typedef std::pair<std::string, std::string> StringPair;
typedef std::vector<StringPair> AttribMap;
typedef AttribMap::iterator AttribIter;
/**
* A simple list of children. To find a tag, one must search the entire list.
*/
List children;
/**
* Attributes of this tag. According to the XML standard the names
* must be unique (case-sensitive). (Assuming that we have few attributes here,
* we use a vector instead of a (hash)map to save a few bytes of memory and unnecessary
* calls to the memory allocator...)
*/
AttribMap attribs;
/** Tag name */
std::string name;
/** Tag data, may be empty. */
std::string data;
/** Parent tag, for easy traversal */
Ptr parent;
Tag(const std::string& aName, const std::string& aData, Ptr aParent, int numAttribs = 0) : name(aName), data(aData), parent(aParent) {
if(numAttribs > 0)
attribs.reserve(numAttribs);
}
const std::string& getAttrib(const std::string& aName, const std::string& aDefault = Util::emptyString) {
AttribIter i = find_if(attribs.begin(), attribs.end(), CompareFirst<std::string, std::string>(aName));
return (i == attribs.end()) ? aDefault : i->second;
}
ADCHPP_DLL std::string toXML(int indent);
std::string::size_type fromXML(const std::string& tmp, std::string::size_type start, int aa, bool isRoot = false) throw(SimpleXMLException);
std::string::size_type loadAttribs(const std::string& tmp, std::string::size_type start) throw(SimpleXMLException);
void appendAttribString(std::string& tmp);
/** Delete all children! */
~Tag() {
for(Iter i = children.begin(); i != children.end(); ++i) {
delete *i;
}
}
};
/** Bogus root tag, should be only one child! */
Tag::Ptr root;
/** Current position */
mutable Tag::Ptr current;
mutable Tag::Iter currentChild;
void checkChildSelected() const throw() {
dcassert(current != NULL);
dcassert(currentChild != current->children.end());
}
int attribs;
mutable bool found;
};
}
#endif // SIMPLEXML_H

View File

@@ -0,0 +1,385 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "SocketManager.h"
#include "LogManager.h"
#include "ManagedSocket.h"
#include "ServerInfo.h"
#include "SimpleXML.h"
#include "Core.h"
#ifdef HAVE_OPENSSL
#include <boost/asio/ssl.hpp>
#endif
#include <boost/date_time/posix_time/time_parsers.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ip/v6_only.hpp>
namespace adchpp {
using namespace std;
using namespace std::placeholders;
using namespace boost::asio;
using boost::system::error_code;
using boost::system::system_error;
SocketManager::SocketManager(Core &core) :
core(core),
bufferSize(1024),
maxBufferSize(16 * 1024),
overflowTimeout(60 * 1000),
disconnectTimeout(10 * 1000)
{
}
const string SocketManager::className = "SocketManager";
template<typename T>
class SocketStream : public AsyncStream {
public:
template<typename X>
SocketStream(X& x) : sock(x) { }
template<typename X, typename Y>
SocketStream(X& x, Y& y) : sock(x, y) { }
~SocketStream() { dcdebug("SocketStream deleted\n"); }
virtual size_t available() {
return sock.lowest_layer().available();
}
virtual void setOptions(size_t bufferSize) {
sock.lowest_layer().set_option(socket_base::receive_buffer_size(bufferSize));
sock.lowest_layer().set_option(socket_base::send_buffer_size(bufferSize));
}
virtual std::string getIp() {
try { return sock.lowest_layer().remote_endpoint().address().to_string(); }
catch(const system_error&) { return Util::emptyString; }
}
virtual void prepareRead(const BufferPtr& buf, const Handler& handler) {
if(buf) {
sock.async_read_some(buffer(buf->data(), buf->size()), handler);
} else {
sock.async_read_some(null_buffers(), handler);
}
}
virtual size_t read(const BufferPtr& buf) {
return sock.read_some(buffer(buf->data(), buf->size()));
}
virtual void write(const BufferList& bufs, const Handler& handler) {
if(bufs.size() == 1) {
sock.async_write_some(buffer(bufs[0]->data(), bufs[0]->size()), handler);
} else {
size_t n = std::min(bufs.size(), static_cast<size_t>(64));
std::vector<const_buffer> buffers;
buffers.reserve(n);
const size_t maxBytes = 1024;
for(size_t i = 0, total = 0; i < n && total < maxBytes; ++i) {
size_t left = maxBytes - total;
size_t bytes = min(bufs[i]->size(), left);
buffers.push_back(const_buffer(bufs[i]->data(), bytes));
total += bytes;
}
sock.async_write_some(buffers, handler);
}
}
T sock;
};
class SimpleSocketStream : public SocketStream<ip::tcp::socket> {
typedef SocketStream<ip::tcp::socket> Stream;
struct ShutdownHandler {
ShutdownHandler(const Handler& h) : h(h) { }
void operator()() { error_code ec; h(ec, 0); }
Handler h;
};
public:
SimpleSocketStream(boost::asio::io_service& x) : Stream(x) { }
virtual void init(const std::function<void ()>& postInit) {
postInit();
}
virtual void shutdown(const Handler& handler) {
sock.shutdown(ip::tcp::socket::shutdown_send);
sock.get_io_service().post(ShutdownHandler(handler));
}
virtual void close() {
// Abortive close, just go away...
if(sock.is_open()) {
error_code ec;
sock.close(ec); // Ignore errors
}
}
};
#ifdef HAVE_OPENSSL
class TLSSocketStream : public SocketStream<ssl::stream<ip::tcp::socket> > {
typedef SocketStream<ssl::stream<ip::tcp::socket> > Stream;
struct ShutdownHandler {
ShutdownHandler(const Handler& h) : h(h) { }
void operator()(const error_code &ec) { h(ec, 0); }
Handler h;
};
public:
TLSSocketStream(io_service& x, ssl::context& y) : Stream(x, y) { }
virtual void init(const std::function<void ()>& postInit) {
sock.async_handshake(ssl::stream_base::server, std::bind(&TLSSocketStream::handleHandshake,
this, std::placeholders::_1, postInit));
}
virtual void shutdown(const Handler& handler) {
sock.async_shutdown(ShutdownHandler(handler));
}
virtual void close() {
// Abortive close, just go away...
if(sock.lowest_layer().is_open()) {
error_code ec;
sock.lowest_layer().close(ec); // Ignore errors
}
}
private:
void handleHandshake(const error_code& ec, const std::function<void ()>& postInit) {
if(!ec) {
postInit();
}
}
};
#endif
static string formatEndpoint(const ip::tcp::endpoint& ep) {
return (ep.address().is_v4() ? ep.address().to_string() + ':' : '[' + ep.address().to_string() + "]:")
+ Util::toString(ep.port());
}
class SocketFactory : public enable_shared_from_this<SocketFactory>, boost::noncopyable {
public:
SocketFactory(SocketManager& sm, const SocketManager::IncomingHandler& handler_, const ServerInfo& info, const ip::tcp::endpoint& endpoint) :
sm(sm),
acceptor(sm.io),
handler(handler_)
{
acceptor.open(endpoint.protocol());
acceptor.set_option(socket_base::reuse_address(true));
if(endpoint.protocol() == ip::tcp::v6()) {
acceptor.set_option(ip::v6_only(true));
}
acceptor.bind(endpoint);
acceptor.listen(socket_base::max_connections);
LOGC(sm.getCore(), SocketManager::className,
"Listening on " + formatEndpoint(endpoint) +
" (Encrypted: " + (info.secure() ? "Yes)" : "No)"));
#ifdef HAVE_OPENSSL
if(info.secure()) {
context.reset(new ssl::context(sm.io, ssl::context::sslv23_server));
context->set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3 | ssl::context::single_dh_use);
//context->set_password_callback(boost::bind(&server::get_password, this));
context->use_certificate_chain_file(info.TLSParams.cert);
context->use_private_key_file(info.TLSParams.pkey, ssl::context::pem);
context->use_tmp_dh_file(info.TLSParams.dh);
}
#endif
}
void prepareAccept() {
if(!sm.work.get()) {
return;
}
#ifdef HAVE_OPENSSL
if(context) {
auto s = make_shared<TLSSocketStream>(sm.io, *context);
auto socket = make_shared<ManagedSocket>(sm, s);
acceptor.async_accept(s->sock.lowest_layer(), std::bind(&SocketFactory::handleAccept, shared_from_this(), std::placeholders::_1, socket));
} else {
#endif
auto s = make_shared<SimpleSocketStream>(sm.io);
auto socket = make_shared<ManagedSocket>(sm, s);
acceptor.async_accept(s->sock.lowest_layer(), std::bind(&SocketFactory::handleAccept, shared_from_this(), std::placeholders::_1, socket));
#ifdef HAVE_OPENSSL
}
#endif
}
void handleAccept(const error_code& ec, const ManagedSocketPtr& socket) {
if(!ec) {
socket->sock->setOptions(sm.getBufferSize());
socket->setIp(socket->sock->getIp());
}
completeAccept(ec, socket);
prepareAccept();
}
void completeAccept(const error_code& ec, const ManagedSocketPtr& socket) {
handler(socket);
socket->completeAccept(ec);
}
void close() { acceptor.close(); }
SocketManager &sm;
ip::tcp::acceptor acceptor;
SocketManager::IncomingHandler handler;
#ifdef HAVE_OPENSSL
unique_ptr<ssl::context> context;
#endif
};
int SocketManager::run() {
LOG(SocketManager::className, "Starting");
work.reset(new io_service::work(io));
for(auto i = servers.begin(), iend = servers.end(); i != iend; ++i) {
auto& si = *i;
try {
using ip::tcp;
tcp::resolver r(io);
auto local = r.resolve(tcp::resolver::query(si->ip, si->port,
tcp::resolver::query::address_configured | tcp::resolver::query::passive));
for(auto i = local; i != tcp::resolver::iterator(); ++i) {
SocketFactoryPtr factory = make_shared<SocketFactory>(*this, incomingHandler, *si, *i);
factory->prepareAccept();
factories.push_back(factory);
}
} catch(const std::exception& e) {
LOG(SocketManager::className, "Error while loading server on port " + si->port +": " + e.what());
}
}
io.run();
io.reset();
return 0;
}
void SocketManager::closeFactories() {
for(auto i = factories.begin(), iend = factories.end(); i != iend; ++i) {
(*i)->close();
}
factories.clear();
}
void SocketManager::addJob(const Callback& callback) throw() {
io.post(callback);
}
void SocketManager::addJob(const long msec, const Callback& callback) {
addJob(boost::posix_time::milliseconds(msec), callback);
}
void SocketManager::addJob(const std::string& time, const Callback& callback) {
addJob(boost::posix_time::duration_from_string(time), callback);
}
SocketManager::Callback SocketManager::addTimedJob(const long msec, const Callback& callback) {
return addTimedJob(boost::posix_time::milliseconds(msec), callback);
}
SocketManager::Callback SocketManager::addTimedJob(const std::string& time, const Callback& callback) {
return addTimedJob(boost::posix_time::duration_from_string(time), callback);
}
void SocketManager::addJob(const deadline_timer::duration_type& duration, const Callback& callback) {
setTimer(make_shared<timer_ptr::element_type>(io, duration), deadline_timer::duration_type(), new Callback(callback));
}
SocketManager::Callback SocketManager::addTimedJob(const deadline_timer::duration_type& duration, const Callback& callback) {
timer_ptr timer = make_shared<timer_ptr::element_type>(io, duration);
Callback* pCallback = new Callback(callback); // create a separate callback on the heap to avoid shutdown crashes
setTimer(timer, duration, pCallback);
return std::bind(&SocketManager::cancelTimer, this, timer, pCallback);
}
void SocketManager::setTimer(timer_ptr timer, const deadline_timer::duration_type& duration, Callback* callback) {
timer->async_wait(std::bind(&SocketManager::handleWait, this, timer, duration, std::placeholders::_1, callback));
}
void SocketManager::handleWait(timer_ptr timer, const deadline_timer::duration_type& duration, const error_code& error, Callback* callback) {
bool run_on = duration.ticks();
if(!error) {
if(run_on) {
// re-schedule the timer
timer->expires_at(timer->expires_at() + duration);
setTimer(timer, duration, callback);
}
addJob(*callback);
}
if(!run_on) {
// this timer was only running once, so it has no cancel function
delete callback;
}
}
void SocketManager::cancelTimer(timer_ptr timer, Callback* callback) {
if(timer.get()) {
error_code ec;
timer->cancel(ec);
}
delete callback;
}
void SocketManager::shutdown() {
closeFactories();
work.reset();
io.stop();
}
void SocketManager::onLoad(const SimpleXML& xml) throw() {
servers.clear();
}
}

133
src/adchpp/SocketManager.h Normal file
View File

@@ -0,0 +1,133 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_SOCKETMANAGER_H
#define ADCHPP_SOCKETMANAGER_H
#include "common.h"
#include "forward.h"
#include "ServerInfo.h"
#include <boost/asio/io_service.hpp>
#include <boost/asio/deadline_timer.hpp>
namespace adchpp {
struct SocketStats {
SocketStats() : queueCalls(0), queueBytes(0), sendCalls(0), sendBytes(0), recvCalls(0), recvBytes(0) { }
size_t queueCalls;
int64_t queueBytes;
size_t sendCalls;
int64_t sendBytes;
int64_t recvCalls;
int64_t recvBytes;
};
class SocketManager {
public:
typedef std::function<void()> Callback;
/** execute a function asynchronously */
ADCHPP_DLL void addJob(const Callback& callback) throw();
/** execute a function after the specified amount of time
* @param msec milliseconds
*/
ADCHPP_DLL void addJob(const long msec, const Callback& callback);
/** execute a function after the specified amount of time
* @param time a string that obeys to the "[-]h[h][:mm][:ss][.fff]" format
*/
ADCHPP_DLL void addJob(const std::string& time, const Callback& callback);
/** execute a function at regular intervals
* @param msec milliseconds
* @return function one must call to cancel the timer (its callback will still be executed)
*/
ADCHPP_DLL Callback addTimedJob(const long msec, const Callback& callback);
/** execute a function at regular intervals
* @param time a string that obeys to the "[-]h[h][:mm][:ss][.fff]" format
* @return function one must call to cancel the timer (its callback will still be executed)
*/
ADCHPP_DLL Callback addTimedJob(const std::string& time, const Callback& callback);
void shutdown();
void setServers(const ServerInfoList& servers_) { servers = servers_; }
typedef std::function<void (const ManagedSocketPtr&)> IncomingHandler;
void setIncomingHandler(const IncomingHandler& handler) { incomingHandler = handler; }
int run();
void setBufferSize(size_t newSize) { bufferSize = newSize; }
size_t getBufferSize() const { return bufferSize; }
void setMaxBufferSize(size_t newSize) { maxBufferSize = newSize; }
size_t getMaxBufferSize() const { return maxBufferSize; }
void setOverflowTimeout(size_t timeout) { overflowTimeout = timeout; }
size_t getOverflowTimeout() const { return overflowTimeout; }
void setDisconnectTimeout(size_t timeout) { disconnectTimeout = timeout; }
size_t getDisconnectTimeout() const { return disconnectTimeout; }
SocketStats &getStats() { return stats; }
Core &getCore() { return core; }
private:
friend class Core;
friend class ManagedSocket;
friend class SocketFactory;
void closeFactories();
Core &core;
boost::asio::io_service io;
std::unique_ptr<boost::asio::io_service::work> work;
SocketStats stats;
ServerInfoList servers;
std::vector<SocketFactoryPtr> factories;
IncomingHandler incomingHandler;
size_t bufferSize; /// Default buffer size used for SO_RCVBUF/SO_SNDBUF
size_t maxBufferSize; /// Max allowed write buffer size for each socket
size_t overflowTimeout;
size_t disconnectTimeout;
static const std::string className;
typedef shared_ptr<boost::asio::deadline_timer> timer_ptr;
void addJob(const boost::asio::deadline_timer::duration_type& duration, const Callback& callback);
Callback addTimedJob(const boost::asio::deadline_timer::duration_type& duration, const Callback& callback);
void setTimer(timer_ptr timer, const boost::asio::deadline_timer::duration_type& duration, Callback* callback);
void handleWait(timer_ptr timer, const boost::asio::deadline_timer::duration_type& duration, const boost::system::error_code& error,
Callback* callback);
void cancelTimer(timer_ptr timer, Callback* callback);
void onLoad(const SimpleXML& xml) throw();
SocketManager(Core &core);
};
}
#endif // SOCKETMANAGER_H

246
src/adchpp/Text.cpp Normal file
View File

@@ -0,0 +1,246 @@
/*
* Copyright (C) 2001-2014 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "Text.h"
#include "Util.h"
using namespace std;
namespace adchpp {
int Text::utf8ToWc(const char* str, wchar_t& c) {
const auto c0 = static_cast<uint8_t>(str[0]);
const auto bytes = 2 + !!(c0 & 0x20) + ((c0 & 0x30) == 0x30);
if((c0 & 0xc0) == 0xc0) { // 11xx xxxx
// # bytes of leading 1's; check for 0 next
const auto check_bit = 1 << (7 - bytes);
if (c0 & check_bit)
return -1;
c = (check_bit - 1) & c0;
// 2-4 total, or 1-3 additional, bytes
// Can't run off end of str so long as has sub-0x80-terminator
for (auto i = 1; i < bytes; ++i) {
const auto ci = static_cast<uint8_t>(str[i]);
if ((ci & 0xc0) != 0x80)
return -i;
c = (c << 6) | (ci & 0x3f);
}
// Invalid UTF-8 code points
if (c > 0x10ffff || (c >= 0xd800 && c <= 0xdfff)) {
// "REPLACEMENT CHARACTER": used to replace an incoming character
// whose value is unknown or unrepresentable in Unicode
c = 0xfffd;
return -bytes;
}
return bytes;
} else if ((c0 & 0x80) == 0) { // 0xxx xxxx
c = static_cast<unsigned char>(str[0]);
return 1;
} else { // 10xx xxxx
return -1;
}
dcassert(0);
}
void Text::wcToUtf8(wchar_t c, string& str) {
// https://tools.ietf.org/html/rfc3629#section-3
if(c > 0x10ffff || (c >= 0xd800 && c <= 0xdfff)) {
// Invalid UTF-8 code point
// REPLACEMENT CHARACTER: http://www.fileformat.info/info/unicode/char/0fffd/index.htm
wcToUtf8(0xfffd, str);
} else if(c >= 0x10000) {
str += (char)(0x80 | 0x40 | 0x20 | 0x10 | (c >> 18));
str += (char)(0x80 | ((c >> 12) & 0x3f));
str += (char)(0x80 | ((c >> 6) & 0x3f));
str += (char)(0x80 | (c & 0x3f));
} else if(c >= 0x0800) {
str += (char)(0x80 | 0x40 | 0x20 | (c >> 12));
str += (char)(0x80 | ((c >> 6) & 0x3f));
str += (char)(0x80 | (c & 0x3f));
} else if(c >= 0x0080) {
str += (char)(0x80 | 0x40 | (c >> 6));
str += (char)(0x80 | (c & 0x3f));
} else {
str += (char)c;
}
}
const string& Text::acpToUtf8(const string& str, string& tmp) throw() {
wstring wtmp;
return wideToUtf8(acpToWide(str, wtmp), tmp);
}
const wstring& Text::acpToWide(const string& str, wstring& tmp) throw() {
if(str.empty())
return Util::emptyStringW;
#ifdef _WIN32
int n = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.c_str(), (int)str.length(), NULL, 0);
if(n == 0) {
return Util::emptyStringW;
}
tmp.resize(n);
n = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.c_str(), (int)str.length(), &tmp[0], n);
if(n == 0) {
return Util::emptyStringW;
}
return tmp;
#else
size_t rv;
wchar_t wc;
const char *src = str.c_str();
size_t n = str.length() + 1;
tmp.clear();
tmp.reserve(n);
while(n > 0) {
rv = mbrtowc(&wc, src, n, NULL);
if(rv == 0 || rv == (size_t)-2) {
break;
} else if(rv == (size_t)-1) {
tmp.push_back(L'_');
++src;
--n;
} else {
tmp.push_back(wc);
src += rv;
n -= rv;
}
}
return tmp;
#endif
}
const string& Text::wideToUtf8(const wstring& str, string& tgt) throw() {
if(str.empty()) {
return Util::emptyString;
}
string::size_type n = str.length();
tgt.clear();
for(string::size_type i = 0; i < n; ++i) {
wcToUtf8(str[i], tgt);
}
return tgt;
}
const string& Text::wideToAcp(const wstring& str, string& tmp) throw() {
if(str.empty())
return Util::emptyString;
#ifdef _WIN32
int n = WideCharToMultiByte(CP_ACP, 0, str.c_str(), (int)str.length(), NULL, 0, NULL, NULL);
if(n == 0) {
return Util::emptyString;
}
tmp.resize(n);
n = WideCharToMultiByte(CP_ACP, 0, str.c_str(), (int)str.length(), &tmp[0], n, NULL, NULL);
if(n == 0) {
return Util::emptyString;
}
return tmp;
#else
const wchar_t* src = str.c_str();
int n = wcsrtombs(NULL, &src, 0, NULL);
if(n < 1) {
return Util::emptyString;
}
src = str.c_str();
tmp.resize(n);
n = wcsrtombs(&tmp[0], &src, n, NULL);
if(n < 1) {
return Util::emptyString;
}
return tmp;
#endif
}
bool Text::validateUtf8(const string& str) throw() {
string::size_type i = 0;
while(i < str.length()) {
wchar_t dummy = 0;
int j = utf8ToWc(&str[i], dummy);
if(j < 0)
return false;
i += j;
}
return true;
}
const string& Text::utf8ToAcp(const string& str, string& tmp) throw() {
wstring wtmp;
return wideToAcp(utf8ToWide(str, wtmp), tmp);
}
const wstring& Text::utf8ToWide(const string& str, wstring& tgt) throw() {
tgt.reserve(str.length());
string::size_type n = str.length();
for(string::size_type i = 0; i < n; ) {
wchar_t c = 0;
int x = utf8ToWc(str.c_str() + i, c);
if(x < 0) {
tgt += '_';
i += abs(x);
} else {
i += x;
tgt += c;
}
}
return tgt;
}
string Text::acpToUtf8(const string& str) throw() {
string tmp;
return acpToUtf8(str, tmp);
}
wstring Text::acpToWide(const string& str) throw() {
wstring tmp;
return acpToWide(str, tmp);
}
string Text::utf8ToAcp(const string& str) throw() {
string tmp;
return utf8ToAcp(str, tmp);
}
wstring Text::utf8ToWide(const string& str) throw() {
wstring tmp;
return utf8ToWide(str, tmp);
}
string Text::wideToAcp(const wstring& str) throw() {
string tmp;
return wideToAcp(str, tmp);
}
string Text::wideToUtf8(const wstring& str) throw() {
string tmp;
return wideToUtf8(str, tmp);
}
} // namespace adchpp

68
src/adchpp/Text.h Normal file
View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2001-2015 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_TEXT_H
#define ADCHPP_TEXT_H
namespace adchpp {
/**
* Text handling routines for ADCH++. ADCH++ internally uses UTF-8 for
* (almost) all string:s, hence all foreign text must be converted
* appropriately...
* acp - ANSI code page used by the system
* wide - wide unicode string
* utf8 - UTF-8 representation of the string
* string - UTF-8 string (most of the time)
* wstring - Wide string
*
* Taken from DC++.
*/
class Text {
typedef std::string string;
typedef std::wstring wstring;
public:
static const string& acpToUtf8(const string& str, string& tmp) throw();
ADCHPP_DLL static string acpToUtf8(const string& str) throw();
static const wstring& acpToWide(const string& str, wstring& tmp) throw();
ADCHPP_DLL static wstring acpToWide(const string& str) throw();
static const string& utf8ToAcp(const string& str, string& tmp) throw();
ADCHPP_DLL static string utf8ToAcp(const string& str) throw();
static const wstring& utf8ToWide(const string& str, wstring& tmp) throw();
ADCHPP_DLL static wstring utf8ToWide(const string& str) throw();
static const string& wideToAcp(const wstring& str, string& tmp) throw();
ADCHPP_DLL static string wideToAcp(const wstring& str) throw();
static const string& wideToUtf8(const wstring& str, string& tmp) throw();
ADCHPP_DLL static string wideToUtf8(const wstring& str) throw();
ADCHPP_DLL static bool validateUtf8(const string& str) throw();
private:
static int utf8ToWc(const char* str, wchar_t& c);
static void wcToUtf8(wchar_t c, string& str);
};
} // namespace dcpp
#endif

79
src/adchpp/Thread.cpp Normal file
View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "Thread.h"
#include "Util.h"
namespace adchpp {
#ifdef _WIN32
void Thread::start() throw(ThreadException) {
if(isRunning()) {
throw ThreadException(_T("Already running"));
}
DWORD threadId = 0;
if( (threadHandle = ::CreateThread(NULL, 0, &starter, this, 0, &threadId)) == NULL) {
throw ThreadException(Util::translateError(::GetLastError()));
}
}
void Thread::join() throw() {
if(!isRunning()) {
return;
}
::WaitForSingleObject(threadHandle, INFINITE);
::CloseHandle(threadHandle);
threadHandle = INVALID_HANDLE_VALUE;
}
#else // _WIN32
void Thread::start() throw(ThreadException) {
if(isRunning()) {
throw ThreadException(_T("Already running"));
}
// Not all implementations may create threads as joinable by default.
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int result = pthread_create(&t, &attr, &starter, this);
if(result != 0) {
throw ThreadException(Util::translateError(result));
}
pthread_attr_destroy(&attr);
}
void Thread::join() throw() {
if(t == 0)
return;
void* x;
pthread_join(t, &x);
t = 0;
}
#endif
}

107
src/adchpp/Thread.h Normal file
View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_THREAD_H
#define ADCHPP_THREAD_H
#ifndef _WIN32
# include <pthread.h>
# include <sched.h>
# include <sys/resource.h>
#include <unistd.h>
#endif
#include "Exception.h"
#include "nullptr.h"
namespace adchpp {
STANDARD_EXCEPTION(ThreadException);
class Thread : private boost::noncopyable
{
public:
ADCHPP_DLL void start() throw(ThreadException);
ADCHPP_DLL void join() throw();
#ifdef _WIN32
enum Priority {
LOW = THREAD_PRIORITY_BELOW_NORMAL,
NORMAL = THREAD_PRIORITY_NORMAL,
HIGH = THREAD_PRIORITY_ABOVE_NORMAL
};
Thread() throw() : threadHandle(INVALID_HANDLE_VALUE) { }
virtual ~Thread() {
if(threadHandle != INVALID_HANDLE_VALUE)
CloseHandle(threadHandle);
}
void setThreadPriority(Priority p) throw() { ::SetThreadPriority(threadHandle, p); }
bool isRunning() throw() { return (threadHandle != INVALID_HANDLE_VALUE); }
static void sleep(uint32_t millis) { ::Sleep(millis); }
static void yield() { ::Sleep(1); }
#elif defined(HAVE_PTHREAD)
enum Priority {
LOW = 1,
NORMAL = 0,
HIGH = -1
};
Thread() throw() : t(0) { }
virtual ~Thread() {
if(t != 0) {
pthread_detach(t);
}
}
void setThreadPriority(Priority p) { setpriority(PRIO_PROCESS, 0, p); }
bool isRunning() { return (t != 0); }
static void sleep(uint32_t millis) { ::usleep(millis*1000); }
static void yield() { ::sched_yield(); }
#else
#error No threading support found
#endif
protected:
virtual int run() = 0;
#ifdef _WIN32
HANDLE threadHandle;
static DWORD WINAPI starter(void* p) {
return static_cast<DWORD>(reinterpret_cast<Thread*>(p)->run());
}
#else
pthread_t t;
static void* starter(void* p) {
// ignore the return value.
reinterpret_cast<Thread*>(p)->run();
return nullptr;
}
#endif
};
}
#endif // THREAD_H

687
src/adchpp/TigerHash.cpp Normal file
View File

@@ -0,0 +1,687 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "TigerHash.h"
#include "common.h"
namespace adchpp {
using namespace std;
#define PASSES 3
#define t1 (table)
#define t2 (table+256)
#define t3 (table+256*2)
#define t4 (table+256*3)
#define save_abc \
aa = a; \
bb = b; \
cc = c;
#define round(a,b,c,x,mul) \
c ^= x; \
a -= t1[(uint8_t)(c)] ^ \
t2[(uint8_t)(((uint32_t)(c))>>(2*8))] ^ \
t3[(uint8_t)((c)>>(4*8))] ^ \
t4[(uint8_t)(((uint32_t)((c)>>(4*8)))>>(2*8))] ; \
b += t4[(uint8_t)(((uint32_t)(c))>>(1*8))] ^ \
t3[(uint8_t)(((uint32_t)(c))>>(3*8))] ^ \
t2[(uint8_t)(((uint32_t)((c)>>(4*8)))>>(1*8))] ^ \
t1[(uint8_t)(((uint32_t)((c)>>(4*8)))>>(3*8))]; \
b *= mul;
#define pass(a,b,c,mul) \
round(a,b,c,x0,mul) \
round(b,c,a,x1,mul) \
round(c,a,b,x2,mul) \
round(a,b,c,x3,mul) \
round(b,c,a,x4,mul) \
round(c,a,b,x5,mul) \
round(a,b,c,x6,mul) \
round(b,c,a,x7,mul)
#define key_schedule \
x0 -= x7 ^ _ULL(0xA5A5A5A5A5A5A5A5); \
x1 ^= x0; \
x2 += x1; \
x3 -= x2 ^ ((~x1)<<19); \
x4 ^= x3; \
x5 += x4; \
x6 -= x5 ^ ((~x4)>>23); \
x7 ^= x6; \
x0 += x7; \
x1 -= x0 ^ ((~x7)<<19); \
x2 ^= x1; \
x3 += x2; \
x4 -= x3 ^ ((~x2)>>23); \
x5 ^= x4; \
x6 += x5; \
x7 -= x6 ^ _ULL(0x0123456789ABCDEF);
#define feedforward \
a ^= aa; \
b -= bb; \
c += cc;
#define compress \
save_abc \
for(pass_no=0; pass_no<PASSES; pass_no++) { \
if(pass_no != 0) {key_schedule} \
pass(a,b,c,(pass_no==0?5:pass_no==1?7:9)); \
tmpa=a; a=c; c=b; b=tmpa;} \
feedforward
#define tiger_compress_macro(str, state) \
{ \
register uint64_t a, b, c, tmpa; \
uint64_t aa, bb, cc; \
register uint64_t x0, x1, x2, x3, x4, x5, x6, x7; \
int pass_no; \
\
a = state[0]; \
b = state[1]; \
c = state[2]; \
\
x0=str[0]; x1=str[1]; x2=str[2]; x3=str[3]; \
x4=str[4]; x5=str[5]; x6=str[6]; x7=str[7]; \
\
compress; \
\
state[0] = a; \
state[1] = b; \
state[2] = c; \
}
/* The compress function is a function. Requires smaller cache? */
void TigerHash::tigerCompress(const uint64_t *str, uint64_t state[3]) {
tiger_compress_macro(((const uint64_t*)str), ((uint64_t*)state));
}
void TigerHash::update(const void* data, size_t length) {
size_t tmppos = (uint32_t)(pos & (BLOCK_SIZE-1));
const uint8_t* str = (const uint8_t*)data;
// First empty tmp buffer if possible
if(tmppos > 0) {
size_t n = min(length, BLOCK_SIZE-tmppos);
memcpy(tmp + tmppos, str, n);
str += n;
pos += n;
length -= n;
if((tmppos + n) == BLOCK_SIZE) {
tigerCompress((uint64_t*)tmp, res);
tmppos = 0;
}
}
// So, now either tmp is empty or all data has been consumed...
dcassert(length == 0 || tmppos == 0);
// Process the bulk of data
while(length>=BLOCK_SIZE) {
tigerCompress((uint64_t*)str, res);
str += BLOCK_SIZE;
pos += BLOCK_SIZE;
length -= BLOCK_SIZE;
}
// Copy the rest to the tmp buffer
memcpy(tmp, str, length);
pos += length;
}
uint8_t* TigerHash::finalize() {
size_t tmppos = (size_t)(pos & (BLOCK_SIZE-1));
// Tmp buffer always has at least one pos, otherwise it would have
// been processed in update()
tmp[tmppos++] = 0x01;
if(tmppos > (BLOCK_SIZE - sizeof(uint64_t))) {
memset(tmp + tmppos, 0, BLOCK_SIZE - tmppos);
tigerCompress(((uint64_t*)tmp), res);
memset(tmp, 0, BLOCK_SIZE);
} else {
memset(tmp + tmppos, 0, BLOCK_SIZE - tmppos - sizeof(uint64_t));
}
((uint64_t*)(&(tmp[56])))[0] = pos<<3;
tigerCompress((uint64_t*)tmp, res);
return getResult();
}
uint64_t TigerHash::table[4*256] = {
_ULL(0x02AAB17CF7E90C5E) /* 0 */, _ULL(0xAC424B03E243A8EC) /* 1 */,
_ULL(0x72CD5BE30DD5FCD3) /* 2 */, _ULL(0x6D019B93F6F97F3A) /* 3 */,
_ULL(0xCD9978FFD21F9193) /* 4 */, _ULL(0x7573A1C9708029E2) /* 5 */,
_ULL(0xB164326B922A83C3) /* 6 */, _ULL(0x46883EEE04915870) /* 7 */,
_ULL(0xEAACE3057103ECE6) /* 8 */, _ULL(0xC54169B808A3535C) /* 9 */,
_ULL(0x4CE754918DDEC47C) /* 10 */, _ULL(0x0AA2F4DFDC0DF40C) /* 11 */,
_ULL(0x10B76F18A74DBEFA) /* 12 */, _ULL(0xC6CCB6235AD1AB6A) /* 13 */,
_ULL(0x13726121572FE2FF) /* 14 */, _ULL(0x1A488C6F199D921E) /* 15 */,
_ULL(0x4BC9F9F4DA0007CA) /* 16 */, _ULL(0x26F5E6F6E85241C7) /* 17 */,
_ULL(0x859079DBEA5947B6) /* 18 */, _ULL(0x4F1885C5C99E8C92) /* 19 */,
_ULL(0xD78E761EA96F864B) /* 20 */, _ULL(0x8E36428C52B5C17D) /* 21 */,
_ULL(0x69CF6827373063C1) /* 22 */, _ULL(0xB607C93D9BB4C56E) /* 23 */,
_ULL(0x7D820E760E76B5EA) /* 24 */, _ULL(0x645C9CC6F07FDC42) /* 25 */,
_ULL(0xBF38A078243342E0) /* 26 */, _ULL(0x5F6B343C9D2E7D04) /* 27 */,
_ULL(0xF2C28AEB600B0EC6) /* 28 */, _ULL(0x6C0ED85F7254BCAC) /* 29 */,
_ULL(0x71592281A4DB4FE5) /* 30 */, _ULL(0x1967FA69CE0FED9F) /* 31 */,
_ULL(0xFD5293F8B96545DB) /* 32 */, _ULL(0xC879E9D7F2A7600B) /* 33 */,
_ULL(0x860248920193194E) /* 34 */, _ULL(0xA4F9533B2D9CC0B3) /* 35 */,
_ULL(0x9053836C15957613) /* 36 */, _ULL(0xDB6DCF8AFC357BF1) /* 37 */,
_ULL(0x18BEEA7A7A370F57) /* 38 */, _ULL(0x037117CA50B99066) /* 39 */,
_ULL(0x6AB30A9774424A35) /* 40 */, _ULL(0xF4E92F02E325249B) /* 41 */,
_ULL(0x7739DB07061CCAE1) /* 42 */, _ULL(0xD8F3B49CECA42A05) /* 43 */,
_ULL(0xBD56BE3F51382F73) /* 44 */, _ULL(0x45FAED5843B0BB28) /* 45 */,
_ULL(0x1C813D5C11BF1F83) /* 46 */, _ULL(0x8AF0E4B6D75FA169) /* 47 */,
_ULL(0x33EE18A487AD9999) /* 48 */, _ULL(0x3C26E8EAB1C94410) /* 49 */,
_ULL(0xB510102BC0A822F9) /* 50 */, _ULL(0x141EEF310CE6123B) /* 51 */,
_ULL(0xFC65B90059DDB154) /* 52 */, _ULL(0xE0158640C5E0E607) /* 53 */,
_ULL(0x884E079826C3A3CF) /* 54 */, _ULL(0x930D0D9523C535FD) /* 55 */,
_ULL(0x35638D754E9A2B00) /* 56 */, _ULL(0x4085FCCF40469DD5) /* 57 */,
_ULL(0xC4B17AD28BE23A4C) /* 58 */, _ULL(0xCAB2F0FC6A3E6A2E) /* 59 */,
_ULL(0x2860971A6B943FCD) /* 60 */, _ULL(0x3DDE6EE212E30446) /* 61 */,
_ULL(0x6222F32AE01765AE) /* 62 */, _ULL(0x5D550BB5478308FE) /* 63 */,
_ULL(0xA9EFA98DA0EDA22A) /* 64 */, _ULL(0xC351A71686C40DA7) /* 65 */,
_ULL(0x1105586D9C867C84) /* 66 */, _ULL(0xDCFFEE85FDA22853) /* 67 */,
_ULL(0xCCFBD0262C5EEF76) /* 68 */, _ULL(0xBAF294CB8990D201) /* 69 */,
_ULL(0xE69464F52AFAD975) /* 70 */, _ULL(0x94B013AFDF133E14) /* 71 */,
_ULL(0x06A7D1A32823C958) /* 72 */, _ULL(0x6F95FE5130F61119) /* 73 */,
_ULL(0xD92AB34E462C06C0) /* 74 */, _ULL(0xED7BDE33887C71D2) /* 75 */,
_ULL(0x79746D6E6518393E) /* 76 */, _ULL(0x5BA419385D713329) /* 77 */,
_ULL(0x7C1BA6B948A97564) /* 78 */, _ULL(0x31987C197BFDAC67) /* 79 */,
_ULL(0xDE6C23C44B053D02) /* 80 */, _ULL(0x581C49FED002D64D) /* 81 */,
_ULL(0xDD474D6338261571) /* 82 */, _ULL(0xAA4546C3E473D062) /* 83 */,
_ULL(0x928FCE349455F860) /* 84 */, _ULL(0x48161BBACAAB94D9) /* 85 */,
_ULL(0x63912430770E6F68) /* 86 */, _ULL(0x6EC8A5E602C6641C) /* 87 */,
_ULL(0x87282515337DDD2B) /* 88 */, _ULL(0x2CDA6B42034B701B) /* 89 */,
_ULL(0xB03D37C181CB096D) /* 90 */, _ULL(0xE108438266C71C6F) /* 91 */,
_ULL(0x2B3180C7EB51B255) /* 92 */, _ULL(0xDF92B82F96C08BBC) /* 93 */,
_ULL(0x5C68C8C0A632F3BA) /* 94 */, _ULL(0x5504CC861C3D0556) /* 95 */,
_ULL(0xABBFA4E55FB26B8F) /* 96 */, _ULL(0x41848B0AB3BACEB4) /* 97 */,
_ULL(0xB334A273AA445D32) /* 98 */, _ULL(0xBCA696F0A85AD881) /* 99 */,
_ULL(0x24F6EC65B528D56C) /* 100 */, _ULL(0x0CE1512E90F4524A) /* 101 */,
_ULL(0x4E9DD79D5506D35A) /* 102 */, _ULL(0x258905FAC6CE9779) /* 103 */,
_ULL(0x2019295B3E109B33) /* 104 */, _ULL(0xF8A9478B73A054CC) /* 105 */,
_ULL(0x2924F2F934417EB0) /* 106 */, _ULL(0x3993357D536D1BC4) /* 107 */,
_ULL(0x38A81AC21DB6FF8B) /* 108 */, _ULL(0x47C4FBF17D6016BF) /* 109 */,
_ULL(0x1E0FAADD7667E3F5) /* 110 */, _ULL(0x7ABCFF62938BEB96) /* 111 */,
_ULL(0xA78DAD948FC179C9) /* 112 */, _ULL(0x8F1F98B72911E50D) /* 113 */,
_ULL(0x61E48EAE27121A91) /* 114 */, _ULL(0x4D62F7AD31859808) /* 115 */,
_ULL(0xECEBA345EF5CEAEB) /* 116 */, _ULL(0xF5CEB25EBC9684CE) /* 117 */,
_ULL(0xF633E20CB7F76221) /* 118 */, _ULL(0xA32CDF06AB8293E4) /* 119 */,
_ULL(0x985A202CA5EE2CA4) /* 120 */, _ULL(0xCF0B8447CC8A8FB1) /* 121 */,
_ULL(0x9F765244979859A3) /* 122 */, _ULL(0xA8D516B1A1240017) /* 123 */,
_ULL(0x0BD7BA3EBB5DC726) /* 124 */, _ULL(0xE54BCA55B86ADB39) /* 125 */,
_ULL(0x1D7A3AFD6C478063) /* 126 */, _ULL(0x519EC608E7669EDD) /* 127 */,
_ULL(0x0E5715A2D149AA23) /* 128 */, _ULL(0x177D4571848FF194) /* 129 */,
_ULL(0xEEB55F3241014C22) /* 130 */, _ULL(0x0F5E5CA13A6E2EC2) /* 131 */,
_ULL(0x8029927B75F5C361) /* 132 */, _ULL(0xAD139FABC3D6E436) /* 133 */,
_ULL(0x0D5DF1A94CCF402F) /* 134 */, _ULL(0x3E8BD948BEA5DFC8) /* 135 */,
_ULL(0xA5A0D357BD3FF77E) /* 136 */, _ULL(0xA2D12E251F74F645) /* 137 */,
_ULL(0x66FD9E525E81A082) /* 138 */, _ULL(0x2E0C90CE7F687A49) /* 139 */,
_ULL(0xC2E8BCBEBA973BC5) /* 140 */, _ULL(0x000001BCE509745F) /* 141 */,
_ULL(0x423777BBE6DAB3D6) /* 142 */, _ULL(0xD1661C7EAEF06EB5) /* 143 */,
_ULL(0xA1781F354DAACFD8) /* 144 */, _ULL(0x2D11284A2B16AFFC) /* 145 */,
_ULL(0xF1FC4F67FA891D1F) /* 146 */, _ULL(0x73ECC25DCB920ADA) /* 147 */,
_ULL(0xAE610C22C2A12651) /* 148 */, _ULL(0x96E0A810D356B78A) /* 149 */,
_ULL(0x5A9A381F2FE7870F) /* 150 */, _ULL(0xD5AD62EDE94E5530) /* 151 */,
_ULL(0xD225E5E8368D1427) /* 152 */, _ULL(0x65977B70C7AF4631) /* 153 */,
_ULL(0x99F889B2DE39D74F) /* 154 */, _ULL(0x233F30BF54E1D143) /* 155 */,
_ULL(0x9A9675D3D9A63C97) /* 156 */, _ULL(0x5470554FF334F9A8) /* 157 */,
_ULL(0x166ACB744A4F5688) /* 158 */, _ULL(0x70C74CAAB2E4AEAD) /* 159 */,
_ULL(0xF0D091646F294D12) /* 160 */, _ULL(0x57B82A89684031D1) /* 161 */,
_ULL(0xEFD95A5A61BE0B6B) /* 162 */, _ULL(0x2FBD12E969F2F29A) /* 163 */,
_ULL(0x9BD37013FEFF9FE8) /* 164 */, _ULL(0x3F9B0404D6085A06) /* 165 */,
_ULL(0x4940C1F3166CFE15) /* 166 */, _ULL(0x09542C4DCDF3DEFB) /* 167 */,
_ULL(0xB4C5218385CD5CE3) /* 168 */, _ULL(0xC935B7DC4462A641) /* 169 */,
_ULL(0x3417F8A68ED3B63F) /* 170 */, _ULL(0xB80959295B215B40) /* 171 */,
_ULL(0xF99CDAEF3B8C8572) /* 172 */, _ULL(0x018C0614F8FCB95D) /* 173 */,
_ULL(0x1B14ACCD1A3ACDF3) /* 174 */, _ULL(0x84D471F200BB732D) /* 175 */,
_ULL(0xC1A3110E95E8DA16) /* 176 */, _ULL(0x430A7220BF1A82B8) /* 177 */,
_ULL(0xB77E090D39DF210E) /* 178 */, _ULL(0x5EF4BD9F3CD05E9D) /* 179 */,
_ULL(0x9D4FF6DA7E57A444) /* 180 */, _ULL(0xDA1D60E183D4A5F8) /* 181 */,
_ULL(0xB287C38417998E47) /* 182 */, _ULL(0xFE3EDC121BB31886) /* 183 */,
_ULL(0xC7FE3CCC980CCBEF) /* 184 */, _ULL(0xE46FB590189BFD03) /* 185 */,
_ULL(0x3732FD469A4C57DC) /* 186 */, _ULL(0x7EF700A07CF1AD65) /* 187 */,
_ULL(0x59C64468A31D8859) /* 188 */, _ULL(0x762FB0B4D45B61F6) /* 189 */,
_ULL(0x155BAED099047718) /* 190 */, _ULL(0x68755E4C3D50BAA6) /* 191 */,
_ULL(0xE9214E7F22D8B4DF) /* 192 */, _ULL(0x2ADDBF532EAC95F4) /* 193 */,
_ULL(0x32AE3909B4BD0109) /* 194 */, _ULL(0x834DF537B08E3450) /* 195 */,
_ULL(0xFA209DA84220728D) /* 196 */, _ULL(0x9E691D9B9EFE23F7) /* 197 */,
_ULL(0x0446D288C4AE8D7F) /* 198 */, _ULL(0x7B4CC524E169785B) /* 199 */,
_ULL(0x21D87F0135CA1385) /* 200 */, _ULL(0xCEBB400F137B8AA5) /* 201 */,
_ULL(0x272E2B66580796BE) /* 202 */, _ULL(0x3612264125C2B0DE) /* 203 */,
_ULL(0x057702BDAD1EFBB2) /* 204 */, _ULL(0xD4BABB8EACF84BE9) /* 205 */,
_ULL(0x91583139641BC67B) /* 206 */, _ULL(0x8BDC2DE08036E024) /* 207 */,
_ULL(0x603C8156F49F68ED) /* 208 */, _ULL(0xF7D236F7DBEF5111) /* 209 */,
_ULL(0x9727C4598AD21E80) /* 210 */, _ULL(0xA08A0896670A5FD7) /* 211 */,
_ULL(0xCB4A8F4309EBA9CB) /* 212 */, _ULL(0x81AF564B0F7036A1) /* 213 */,
_ULL(0xC0B99AA778199ABD) /* 214 */, _ULL(0x959F1EC83FC8E952) /* 215 */,
_ULL(0x8C505077794A81B9) /* 216 */, _ULL(0x3ACAAF8F056338F0) /* 217 */,
_ULL(0x07B43F50627A6778) /* 218 */, _ULL(0x4A44AB49F5ECCC77) /* 219 */,
_ULL(0x3BC3D6E4B679EE98) /* 220 */, _ULL(0x9CC0D4D1CF14108C) /* 221 */,
_ULL(0x4406C00B206BC8A0) /* 222 */, _ULL(0x82A18854C8D72D89) /* 223 */,
_ULL(0x67E366B35C3C432C) /* 224 */, _ULL(0xB923DD61102B37F2) /* 225 */,
_ULL(0x56AB2779D884271D) /* 226 */, _ULL(0xBE83E1B0FF1525AF) /* 227 */,
_ULL(0xFB7C65D4217E49A9) /* 228 */, _ULL(0x6BDBE0E76D48E7D4) /* 229 */,
_ULL(0x08DF828745D9179E) /* 230 */, _ULL(0x22EA6A9ADD53BD34) /* 231 */,
_ULL(0xE36E141C5622200A) /* 232 */, _ULL(0x7F805D1B8CB750EE) /* 233 */,
_ULL(0xAFE5C7A59F58E837) /* 234 */, _ULL(0xE27F996A4FB1C23C) /* 235 */,
_ULL(0xD3867DFB0775F0D0) /* 236 */, _ULL(0xD0E673DE6E88891A) /* 237 */,
_ULL(0x123AEB9EAFB86C25) /* 238 */, _ULL(0x30F1D5D5C145B895) /* 239 */,
_ULL(0xBB434A2DEE7269E7) /* 240 */, _ULL(0x78CB67ECF931FA38) /* 241 */,
_ULL(0xF33B0372323BBF9C) /* 242 */, _ULL(0x52D66336FB279C74) /* 243 */,
_ULL(0x505F33AC0AFB4EAA) /* 244 */, _ULL(0xE8A5CD99A2CCE187) /* 245 */,
_ULL(0x534974801E2D30BB) /* 246 */, _ULL(0x8D2D5711D5876D90) /* 247 */,
_ULL(0x1F1A412891BC038E) /* 248 */, _ULL(0xD6E2E71D82E56648) /* 249 */,
_ULL(0x74036C3A497732B7) /* 250 */, _ULL(0x89B67ED96361F5AB) /* 251 */,
_ULL(0xFFED95D8F1EA02A2) /* 252 */, _ULL(0xE72B3BD61464D43D) /* 253 */,
_ULL(0xA6300F170BDC4820) /* 254 */, _ULL(0xEBC18760ED78A77A) /* 255 */,
_ULL(0xE6A6BE5A05A12138) /* 256 */, _ULL(0xB5A122A5B4F87C98) /* 257 */,
_ULL(0x563C6089140B6990) /* 258 */, _ULL(0x4C46CB2E391F5DD5) /* 259 */,
_ULL(0xD932ADDBC9B79434) /* 260 */, _ULL(0x08EA70E42015AFF5) /* 261 */,
_ULL(0xD765A6673E478CF1) /* 262 */, _ULL(0xC4FB757EAB278D99) /* 263 */,
_ULL(0xDF11C6862D6E0692) /* 264 */, _ULL(0xDDEB84F10D7F3B16) /* 265 */,
_ULL(0x6F2EF604A665EA04) /* 266 */, _ULL(0x4A8E0F0FF0E0DFB3) /* 267 */,
_ULL(0xA5EDEEF83DBCBA51) /* 268 */, _ULL(0xFC4F0A2A0EA4371E) /* 269 */,
_ULL(0xE83E1DA85CB38429) /* 270 */, _ULL(0xDC8FF882BA1B1CE2) /* 271 */,
_ULL(0xCD45505E8353E80D) /* 272 */, _ULL(0x18D19A00D4DB0717) /* 273 */,
_ULL(0x34A0CFEDA5F38101) /* 274 */, _ULL(0x0BE77E518887CAF2) /* 275 */,
_ULL(0x1E341438B3C45136) /* 276 */, _ULL(0xE05797F49089CCF9) /* 277 */,
_ULL(0xFFD23F9DF2591D14) /* 278 */, _ULL(0x543DDA228595C5CD) /* 279 */,
_ULL(0x661F81FD99052A33) /* 280 */, _ULL(0x8736E641DB0F7B76) /* 281 */,
_ULL(0x15227725418E5307) /* 282 */, _ULL(0xE25F7F46162EB2FA) /* 283 */,
_ULL(0x48A8B2126C13D9FE) /* 284 */, _ULL(0xAFDC541792E76EEA) /* 285 */,
_ULL(0x03D912BFC6D1898F) /* 286 */, _ULL(0x31B1AAFA1B83F51B) /* 287 */,
_ULL(0xF1AC2796E42AB7D9) /* 288 */, _ULL(0x40A3A7D7FCD2EBAC) /* 289 */,
_ULL(0x1056136D0AFBBCC5) /* 290 */, _ULL(0x7889E1DD9A6D0C85) /* 291 */,
_ULL(0xD33525782A7974AA) /* 292 */, _ULL(0xA7E25D09078AC09B) /* 293 */,
_ULL(0xBD4138B3EAC6EDD0) /* 294 */, _ULL(0x920ABFBE71EB9E70) /* 295 */,
_ULL(0xA2A5D0F54FC2625C) /* 296 */, _ULL(0xC054E36B0B1290A3) /* 297 */,
_ULL(0xF6DD59FF62FE932B) /* 298 */, _ULL(0x3537354511A8AC7D) /* 299 */,
_ULL(0xCA845E9172FADCD4) /* 300 */, _ULL(0x84F82B60329D20DC) /* 301 */,
_ULL(0x79C62CE1CD672F18) /* 302 */, _ULL(0x8B09A2ADD124642C) /* 303 */,
_ULL(0xD0C1E96A19D9E726) /* 304 */, _ULL(0x5A786A9B4BA9500C) /* 305 */,
_ULL(0x0E020336634C43F3) /* 306 */, _ULL(0xC17B474AEB66D822) /* 307 */,
_ULL(0x6A731AE3EC9BAAC2) /* 308 */, _ULL(0x8226667AE0840258) /* 309 */,
_ULL(0x67D4567691CAECA5) /* 310 */, _ULL(0x1D94155C4875ADB5) /* 311 */,
_ULL(0x6D00FD985B813FDF) /* 312 */, _ULL(0x51286EFCB774CD06) /* 313 */,
_ULL(0x5E8834471FA744AF) /* 314 */, _ULL(0xF72CA0AEE761AE2E) /* 315 */,
_ULL(0xBE40E4CDAEE8E09A) /* 316 */, _ULL(0xE9970BBB5118F665) /* 317 */,
_ULL(0x726E4BEB33DF1964) /* 318 */, _ULL(0x703B000729199762) /* 319 */,
_ULL(0x4631D816F5EF30A7) /* 320 */, _ULL(0xB880B5B51504A6BE) /* 321 */,
_ULL(0x641793C37ED84B6C) /* 322 */, _ULL(0x7B21ED77F6E97D96) /* 323 */,
_ULL(0x776306312EF96B73) /* 324 */, _ULL(0xAE528948E86FF3F4) /* 325 */,
_ULL(0x53DBD7F286A3F8F8) /* 326 */, _ULL(0x16CADCE74CFC1063) /* 327 */,
_ULL(0x005C19BDFA52C6DD) /* 328 */, _ULL(0x68868F5D64D46AD3) /* 329 */,
_ULL(0x3A9D512CCF1E186A) /* 330 */, _ULL(0x367E62C2385660AE) /* 331 */,
_ULL(0xE359E7EA77DCB1D7) /* 332 */, _ULL(0x526C0773749ABE6E) /* 333 */,
_ULL(0x735AE5F9D09F734B) /* 334 */, _ULL(0x493FC7CC8A558BA8) /* 335 */,
_ULL(0xB0B9C1533041AB45) /* 336 */, _ULL(0x321958BA470A59BD) /* 337 */,
_ULL(0x852DB00B5F46C393) /* 338 */, _ULL(0x91209B2BD336B0E5) /* 339 */,
_ULL(0x6E604F7D659EF19F) /* 340 */, _ULL(0xB99A8AE2782CCB24) /* 341 */,
_ULL(0xCCF52AB6C814C4C7) /* 342 */, _ULL(0x4727D9AFBE11727B) /* 343 */,
_ULL(0x7E950D0C0121B34D) /* 344 */, _ULL(0x756F435670AD471F) /* 345 */,
_ULL(0xF5ADD442615A6849) /* 346 */, _ULL(0x4E87E09980B9957A) /* 347 */,
_ULL(0x2ACFA1DF50AEE355) /* 348 */, _ULL(0xD898263AFD2FD556) /* 349 */,
_ULL(0xC8F4924DD80C8FD6) /* 350 */, _ULL(0xCF99CA3D754A173A) /* 351 */,
_ULL(0xFE477BACAF91BF3C) /* 352 */, _ULL(0xED5371F6D690C12D) /* 353 */,
_ULL(0x831A5C285E687094) /* 354 */, _ULL(0xC5D3C90A3708A0A4) /* 355 */,
_ULL(0x0F7F903717D06580) /* 356 */, _ULL(0x19F9BB13B8FDF27F) /* 357 */,
_ULL(0xB1BD6F1B4D502843) /* 358 */, _ULL(0x1C761BA38FFF4012) /* 359 */,
_ULL(0x0D1530C4E2E21F3B) /* 360 */, _ULL(0x8943CE69A7372C8A) /* 361 */,
_ULL(0xE5184E11FEB5CE66) /* 362 */, _ULL(0x618BDB80BD736621) /* 363 */,
_ULL(0x7D29BAD68B574D0B) /* 364 */, _ULL(0x81BB613E25E6FE5B) /* 365 */,
_ULL(0x071C9C10BC07913F) /* 366 */, _ULL(0xC7BEEB7909AC2D97) /* 367 */,
_ULL(0xC3E58D353BC5D757) /* 368 */, _ULL(0xEB017892F38F61E8) /* 369 */,
_ULL(0xD4EFFB9C9B1CC21A) /* 370 */, _ULL(0x99727D26F494F7AB) /* 371 */,
_ULL(0xA3E063A2956B3E03) /* 372 */, _ULL(0x9D4A8B9A4AA09C30) /* 373 */,
_ULL(0x3F6AB7D500090FB4) /* 374 */, _ULL(0x9CC0F2A057268AC0) /* 375 */,
_ULL(0x3DEE9D2DEDBF42D1) /* 376 */, _ULL(0x330F49C87960A972) /* 377 */,
_ULL(0xC6B2720287421B41) /* 378 */, _ULL(0x0AC59EC07C00369C) /* 379 */,
_ULL(0xEF4EAC49CB353425) /* 380 */, _ULL(0xF450244EEF0129D8) /* 381 */,
_ULL(0x8ACC46E5CAF4DEB6) /* 382 */, _ULL(0x2FFEAB63989263F7) /* 383 */,
_ULL(0x8F7CB9FE5D7A4578) /* 384 */, _ULL(0x5BD8F7644E634635) /* 385 */,
_ULL(0x427A7315BF2DC900) /* 386 */, _ULL(0x17D0C4AA2125261C) /* 387 */,
_ULL(0x3992486C93518E50) /* 388 */, _ULL(0xB4CBFEE0A2D7D4C3) /* 389 */,
_ULL(0x7C75D6202C5DDD8D) /* 390 */, _ULL(0xDBC295D8E35B6C61) /* 391 */,
_ULL(0x60B369D302032B19) /* 392 */, _ULL(0xCE42685FDCE44132) /* 393 */,
_ULL(0x06F3DDB9DDF65610) /* 394 */, _ULL(0x8EA4D21DB5E148F0) /* 395 */,
_ULL(0x20B0FCE62FCD496F) /* 396 */, _ULL(0x2C1B912358B0EE31) /* 397 */,
_ULL(0xB28317B818F5A308) /* 398 */, _ULL(0xA89C1E189CA6D2CF) /* 399 */,
_ULL(0x0C6B18576AAADBC8) /* 400 */, _ULL(0xB65DEAA91299FAE3) /* 401 */,
_ULL(0xFB2B794B7F1027E7) /* 402 */, _ULL(0x04E4317F443B5BEB) /* 403 */,
_ULL(0x4B852D325939D0A6) /* 404 */, _ULL(0xD5AE6BEEFB207FFC) /* 405 */,
_ULL(0x309682B281C7D374) /* 406 */, _ULL(0xBAE309A194C3B475) /* 407 */,
_ULL(0x8CC3F97B13B49F05) /* 408 */, _ULL(0x98A9422FF8293967) /* 409 */,
_ULL(0x244B16B01076FF7C) /* 410 */, _ULL(0xF8BF571C663D67EE) /* 411 */,
_ULL(0x1F0D6758EEE30DA1) /* 412 */, _ULL(0xC9B611D97ADEB9B7) /* 413 */,
_ULL(0xB7AFD5887B6C57A2) /* 414 */, _ULL(0x6290AE846B984FE1) /* 415 */,
_ULL(0x94DF4CDEACC1A5FD) /* 416 */, _ULL(0x058A5BD1C5483AFF) /* 417 */,
_ULL(0x63166CC142BA3C37) /* 418 */, _ULL(0x8DB8526EB2F76F40) /* 419 */,
_ULL(0xE10880036F0D6D4E) /* 420 */, _ULL(0x9E0523C9971D311D) /* 421 */,
_ULL(0x45EC2824CC7CD691) /* 422 */, _ULL(0x575B8359E62382C9) /* 423 */,
_ULL(0xFA9E400DC4889995) /* 424 */, _ULL(0xD1823ECB45721568) /* 425 */,
_ULL(0xDAFD983B8206082F) /* 426 */, _ULL(0xAA7D29082386A8CB) /* 427 */,
_ULL(0x269FCD4403B87588) /* 428 */, _ULL(0x1B91F5F728BDD1E0) /* 429 */,
_ULL(0xE4669F39040201F6) /* 430 */, _ULL(0x7A1D7C218CF04ADE) /* 431 */,
_ULL(0x65623C29D79CE5CE) /* 432 */, _ULL(0x2368449096C00BB1) /* 433 */,
_ULL(0xAB9BF1879DA503BA) /* 434 */, _ULL(0xBC23ECB1A458058E) /* 435 */,
_ULL(0x9A58DF01BB401ECC) /* 436 */, _ULL(0xA070E868A85F143D) /* 437 */,
_ULL(0x4FF188307DF2239E) /* 438 */, _ULL(0x14D565B41A641183) /* 439 */,
_ULL(0xEE13337452701602) /* 440 */, _ULL(0x950E3DCF3F285E09) /* 441 */,
_ULL(0x59930254B9C80953) /* 442 */, _ULL(0x3BF299408930DA6D) /* 443 */,
_ULL(0xA955943F53691387) /* 444 */, _ULL(0xA15EDECAA9CB8784) /* 445 */,
_ULL(0x29142127352BE9A0) /* 446 */, _ULL(0x76F0371FFF4E7AFB) /* 447 */,
_ULL(0x0239F450274F2228) /* 448 */, _ULL(0xBB073AF01D5E868B) /* 449 */,
_ULL(0xBFC80571C10E96C1) /* 450 */, _ULL(0xD267088568222E23) /* 451 */,
_ULL(0x9671A3D48E80B5B0) /* 452 */, _ULL(0x55B5D38AE193BB81) /* 453 */,
_ULL(0x693AE2D0A18B04B8) /* 454 */, _ULL(0x5C48B4ECADD5335F) /* 455 */,
_ULL(0xFD743B194916A1CA) /* 456 */, _ULL(0x2577018134BE98C4) /* 457 */,
_ULL(0xE77987E83C54A4AD) /* 458 */, _ULL(0x28E11014DA33E1B9) /* 459 */,
_ULL(0x270CC59E226AA213) /* 460 */, _ULL(0x71495F756D1A5F60) /* 461 */,
_ULL(0x9BE853FB60AFEF77) /* 462 */, _ULL(0xADC786A7F7443DBF) /* 463 */,
_ULL(0x0904456173B29A82) /* 464 */, _ULL(0x58BC7A66C232BD5E) /* 465 */,
_ULL(0xF306558C673AC8B2) /* 466 */, _ULL(0x41F639C6B6C9772A) /* 467 */,
_ULL(0x216DEFE99FDA35DA) /* 468 */, _ULL(0x11640CC71C7BE615) /* 469 */,
_ULL(0x93C43694565C5527) /* 470 */, _ULL(0xEA038E6246777839) /* 471 */,
_ULL(0xF9ABF3CE5A3E2469) /* 472 */, _ULL(0x741E768D0FD312D2) /* 473 */,
_ULL(0x0144B883CED652C6) /* 474 */, _ULL(0xC20B5A5BA33F8552) /* 475 */,
_ULL(0x1AE69633C3435A9D) /* 476 */, _ULL(0x97A28CA4088CFDEC) /* 477 */,
_ULL(0x8824A43C1E96F420) /* 478 */, _ULL(0x37612FA66EEEA746) /* 479 */,
_ULL(0x6B4CB165F9CF0E5A) /* 480 */, _ULL(0x43AA1C06A0ABFB4A) /* 481 */,
_ULL(0x7F4DC26FF162796B) /* 482 */, _ULL(0x6CBACC8E54ED9B0F) /* 483 */,
_ULL(0xA6B7FFEFD2BB253E) /* 484 */, _ULL(0x2E25BC95B0A29D4F) /* 485 */,
_ULL(0x86D6A58BDEF1388C) /* 486 */, _ULL(0xDED74AC576B6F054) /* 487 */,
_ULL(0x8030BDBC2B45805D) /* 488 */, _ULL(0x3C81AF70E94D9289) /* 489 */,
_ULL(0x3EFF6DDA9E3100DB) /* 490 */, _ULL(0xB38DC39FDFCC8847) /* 491 */,
_ULL(0x123885528D17B87E) /* 492 */, _ULL(0xF2DA0ED240B1B642) /* 493 */,
_ULL(0x44CEFADCD54BF9A9) /* 494 */, _ULL(0x1312200E433C7EE6) /* 495 */,
_ULL(0x9FFCC84F3A78C748) /* 496 */, _ULL(0xF0CD1F72248576BB) /* 497 */,
_ULL(0xEC6974053638CFE4) /* 498 */, _ULL(0x2BA7B67C0CEC4E4C) /* 499 */,
_ULL(0xAC2F4DF3E5CE32ED) /* 500 */, _ULL(0xCB33D14326EA4C11) /* 501 */,
_ULL(0xA4E9044CC77E58BC) /* 502 */, _ULL(0x5F513293D934FCEF) /* 503 */,
_ULL(0x5DC9645506E55444) /* 504 */, _ULL(0x50DE418F317DE40A) /* 505 */,
_ULL(0x388CB31A69DDE259) /* 506 */, _ULL(0x2DB4A83455820A86) /* 507 */,
_ULL(0x9010A91E84711AE9) /* 508 */, _ULL(0x4DF7F0B7B1498371) /* 509 */,
_ULL(0xD62A2EABC0977179) /* 510 */, _ULL(0x22FAC097AA8D5C0E) /* 511 */,
_ULL(0xF49FCC2FF1DAF39B) /* 512 */, _ULL(0x487FD5C66FF29281) /* 513 */,
_ULL(0xE8A30667FCDCA83F) /* 514 */, _ULL(0x2C9B4BE3D2FCCE63) /* 515 */,
_ULL(0xDA3FF74B93FBBBC2) /* 516 */, _ULL(0x2FA165D2FE70BA66) /* 517 */,
_ULL(0xA103E279970E93D4) /* 518 */, _ULL(0xBECDEC77B0E45E71) /* 519 */,
_ULL(0xCFB41E723985E497) /* 520 */, _ULL(0xB70AAA025EF75017) /* 521 */,
_ULL(0xD42309F03840B8E0) /* 522 */, _ULL(0x8EFC1AD035898579) /* 523 */,
_ULL(0x96C6920BE2B2ABC5) /* 524 */, _ULL(0x66AF4163375A9172) /* 525 */,
_ULL(0x2174ABDCCA7127FB) /* 526 */, _ULL(0xB33CCEA64A72FF41) /* 527 */,
_ULL(0xF04A4933083066A5) /* 528 */, _ULL(0x8D970ACDD7289AF5) /* 529 */,
_ULL(0x8F96E8E031C8C25E) /* 530 */, _ULL(0xF3FEC02276875D47) /* 531 */,
_ULL(0xEC7BF310056190DD) /* 532 */, _ULL(0xF5ADB0AEBB0F1491) /* 533 */,
_ULL(0x9B50F8850FD58892) /* 534 */, _ULL(0x4975488358B74DE8) /* 535 */,
_ULL(0xA3354FF691531C61) /* 536 */, _ULL(0x0702BBE481D2C6EE) /* 537 */,
_ULL(0x89FB24057DEDED98) /* 538 */, _ULL(0xAC3075138596E902) /* 539 */,
_ULL(0x1D2D3580172772ED) /* 540 */, _ULL(0xEB738FC28E6BC30D) /* 541 */,
_ULL(0x5854EF8F63044326) /* 542 */, _ULL(0x9E5C52325ADD3BBE) /* 543 */,
_ULL(0x90AA53CF325C4623) /* 544 */, _ULL(0xC1D24D51349DD067) /* 545 */,
_ULL(0x2051CFEEA69EA624) /* 546 */, _ULL(0x13220F0A862E7E4F) /* 547 */,
_ULL(0xCE39399404E04864) /* 548 */, _ULL(0xD9C42CA47086FCB7) /* 549 */,
_ULL(0x685AD2238A03E7CC) /* 550 */, _ULL(0x066484B2AB2FF1DB) /* 551 */,
_ULL(0xFE9D5D70EFBF79EC) /* 552 */, _ULL(0x5B13B9DD9C481854) /* 553 */,
_ULL(0x15F0D475ED1509AD) /* 554 */, _ULL(0x0BEBCD060EC79851) /* 555 */,
_ULL(0xD58C6791183AB7F8) /* 556 */, _ULL(0xD1187C5052F3EEE4) /* 557 */,
_ULL(0xC95D1192E54E82FF) /* 558 */, _ULL(0x86EEA14CB9AC6CA2) /* 559 */,
_ULL(0x3485BEB153677D5D) /* 560 */, _ULL(0xDD191D781F8C492A) /* 561 */,
_ULL(0xF60866BAA784EBF9) /* 562 */, _ULL(0x518F643BA2D08C74) /* 563 */,
_ULL(0x8852E956E1087C22) /* 564 */, _ULL(0xA768CB8DC410AE8D) /* 565 */,
_ULL(0x38047726BFEC8E1A) /* 566 */, _ULL(0xA67738B4CD3B45AA) /* 567 */,
_ULL(0xAD16691CEC0DDE19) /* 568 */, _ULL(0xC6D4319380462E07) /* 569 */,
_ULL(0xC5A5876D0BA61938) /* 570 */, _ULL(0x16B9FA1FA58FD840) /* 571 */,
_ULL(0x188AB1173CA74F18) /* 572 */, _ULL(0xABDA2F98C99C021F) /* 573 */,
_ULL(0x3E0580AB134AE816) /* 574 */, _ULL(0x5F3B05B773645ABB) /* 575 */,
_ULL(0x2501A2BE5575F2F6) /* 576 */, _ULL(0x1B2F74004E7E8BA9) /* 577 */,
_ULL(0x1CD7580371E8D953) /* 578 */, _ULL(0x7F6ED89562764E30) /* 579 */,
_ULL(0xB15926FF596F003D) /* 580 */, _ULL(0x9F65293DA8C5D6B9) /* 581 */,
_ULL(0x6ECEF04DD690F84C) /* 582 */, _ULL(0x4782275FFF33AF88) /* 583 */,
_ULL(0xE41433083F820801) /* 584 */, _ULL(0xFD0DFE409A1AF9B5) /* 585 */,
_ULL(0x4325A3342CDB396B) /* 586 */, _ULL(0x8AE77E62B301B252) /* 587 */,
_ULL(0xC36F9E9F6655615A) /* 588 */, _ULL(0x85455A2D92D32C09) /* 589 */,
_ULL(0xF2C7DEA949477485) /* 590 */, _ULL(0x63CFB4C133A39EBA) /* 591 */,
_ULL(0x83B040CC6EBC5462) /* 592 */, _ULL(0x3B9454C8FDB326B0) /* 593 */,
_ULL(0x56F56A9E87FFD78C) /* 594 */, _ULL(0x2DC2940D99F42BC6) /* 595 */,
_ULL(0x98F7DF096B096E2D) /* 596 */, _ULL(0x19A6E01E3AD852BF) /* 597 */,
_ULL(0x42A99CCBDBD4B40B) /* 598 */, _ULL(0xA59998AF45E9C559) /* 599 */,
_ULL(0x366295E807D93186) /* 600 */, _ULL(0x6B48181BFAA1F773) /* 601 */,
_ULL(0x1FEC57E2157A0A1D) /* 602 */, _ULL(0x4667446AF6201AD5) /* 603 */,
_ULL(0xE615EBCACFB0F075) /* 604 */, _ULL(0xB8F31F4F68290778) /* 605 */,
_ULL(0x22713ED6CE22D11E) /* 606 */, _ULL(0x3057C1A72EC3C93B) /* 607 */,
_ULL(0xCB46ACC37C3F1F2F) /* 608 */, _ULL(0xDBB893FD02AAF50E) /* 609 */,
_ULL(0x331FD92E600B9FCF) /* 610 */, _ULL(0xA498F96148EA3AD6) /* 611 */,
_ULL(0xA8D8426E8B6A83EA) /* 612 */, _ULL(0xA089B274B7735CDC) /* 613 */,
_ULL(0x87F6B3731E524A11) /* 614 */, _ULL(0x118808E5CBC96749) /* 615 */,
_ULL(0x9906E4C7B19BD394) /* 616 */, _ULL(0xAFED7F7E9B24A20C) /* 617 */,
_ULL(0x6509EADEEB3644A7) /* 618 */, _ULL(0x6C1EF1D3E8EF0EDE) /* 619 */,
_ULL(0xB9C97D43E9798FB4) /* 620 */, _ULL(0xA2F2D784740C28A3) /* 621 */,
_ULL(0x7B8496476197566F) /* 622 */, _ULL(0x7A5BE3E6B65F069D) /* 623 */,
_ULL(0xF96330ED78BE6F10) /* 624 */, _ULL(0xEEE60DE77A076A15) /* 625 */,
_ULL(0x2B4BEE4AA08B9BD0) /* 626 */, _ULL(0x6A56A63EC7B8894E) /* 627 */,
_ULL(0x02121359BA34FEF4) /* 628 */, _ULL(0x4CBF99F8283703FC) /* 629 */,
_ULL(0x398071350CAF30C8) /* 630 */, _ULL(0xD0A77A89F017687A) /* 631 */,
_ULL(0xF1C1A9EB9E423569) /* 632 */, _ULL(0x8C7976282DEE8199) /* 633 */,
_ULL(0x5D1737A5DD1F7ABD) /* 634 */, _ULL(0x4F53433C09A9FA80) /* 635 */,
_ULL(0xFA8B0C53DF7CA1D9) /* 636 */, _ULL(0x3FD9DCBC886CCB77) /* 637 */,
_ULL(0xC040917CA91B4720) /* 638 */, _ULL(0x7DD00142F9D1DCDF) /* 639 */,
_ULL(0x8476FC1D4F387B58) /* 640 */, _ULL(0x23F8E7C5F3316503) /* 641 */,
_ULL(0x032A2244E7E37339) /* 642 */, _ULL(0x5C87A5D750F5A74B) /* 643 */,
_ULL(0x082B4CC43698992E) /* 644 */, _ULL(0xDF917BECB858F63C) /* 645 */,
_ULL(0x3270B8FC5BF86DDA) /* 646 */, _ULL(0x10AE72BB29B5DD76) /* 647 */,
_ULL(0x576AC94E7700362B) /* 648 */, _ULL(0x1AD112DAC61EFB8F) /* 649 */,
_ULL(0x691BC30EC5FAA427) /* 650 */, _ULL(0xFF246311CC327143) /* 651 */,
_ULL(0x3142368E30E53206) /* 652 */, _ULL(0x71380E31E02CA396) /* 653 */,
_ULL(0x958D5C960AAD76F1) /* 654 */, _ULL(0xF8D6F430C16DA536) /* 655 */,
_ULL(0xC8FFD13F1BE7E1D2) /* 656 */, _ULL(0x7578AE66004DDBE1) /* 657 */,
_ULL(0x05833F01067BE646) /* 658 */, _ULL(0xBB34B5AD3BFE586D) /* 659 */,
_ULL(0x095F34C9A12B97F0) /* 660 */, _ULL(0x247AB64525D60CA8) /* 661 */,
_ULL(0xDCDBC6F3017477D1) /* 662 */, _ULL(0x4A2E14D4DECAD24D) /* 663 */,
_ULL(0xBDB5E6D9BE0A1EEB) /* 664 */, _ULL(0x2A7E70F7794301AB) /* 665 */,
_ULL(0xDEF42D8A270540FD) /* 666 */, _ULL(0x01078EC0A34C22C1) /* 667 */,
_ULL(0xE5DE511AF4C16387) /* 668 */, _ULL(0x7EBB3A52BD9A330A) /* 669 */,
_ULL(0x77697857AA7D6435) /* 670 */, _ULL(0x004E831603AE4C32) /* 671 */,
_ULL(0xE7A21020AD78E312) /* 672 */, _ULL(0x9D41A70C6AB420F2) /* 673 */,
_ULL(0x28E06C18EA1141E6) /* 674 */, _ULL(0xD2B28CBD984F6B28) /* 675 */,
_ULL(0x26B75F6C446E9D83) /* 676 */, _ULL(0xBA47568C4D418D7F) /* 677 */,
_ULL(0xD80BADBFE6183D8E) /* 678 */, _ULL(0x0E206D7F5F166044) /* 679 */,
_ULL(0xE258A43911CBCA3E) /* 680 */, _ULL(0x723A1746B21DC0BC) /* 681 */,
_ULL(0xC7CAA854F5D7CDD3) /* 682 */, _ULL(0x7CAC32883D261D9C) /* 683 */,
_ULL(0x7690C26423BA942C) /* 684 */, _ULL(0x17E55524478042B8) /* 685 */,
_ULL(0xE0BE477656A2389F) /* 686 */, _ULL(0x4D289B5E67AB2DA0) /* 687 */,
_ULL(0x44862B9C8FBBFD31) /* 688 */, _ULL(0xB47CC8049D141365) /* 689 */,
_ULL(0x822C1B362B91C793) /* 690 */, _ULL(0x4EB14655FB13DFD8) /* 691 */,
_ULL(0x1ECBBA0714E2A97B) /* 692 */, _ULL(0x6143459D5CDE5F14) /* 693 */,
_ULL(0x53A8FBF1D5F0AC89) /* 694 */, _ULL(0x97EA04D81C5E5B00) /* 695 */,
_ULL(0x622181A8D4FDB3F3) /* 696 */, _ULL(0xE9BCD341572A1208) /* 697 */,
_ULL(0x1411258643CCE58A) /* 698 */, _ULL(0x9144C5FEA4C6E0A4) /* 699 */,
_ULL(0x0D33D06565CF620F) /* 700 */, _ULL(0x54A48D489F219CA1) /* 701 */,
_ULL(0xC43E5EAC6D63C821) /* 702 */, _ULL(0xA9728B3A72770DAF) /* 703 */,
_ULL(0xD7934E7B20DF87EF) /* 704 */, _ULL(0xE35503B61A3E86E5) /* 705 */,
_ULL(0xCAE321FBC819D504) /* 706 */, _ULL(0x129A50B3AC60BFA6) /* 707 */,
_ULL(0xCD5E68EA7E9FB6C3) /* 708 */, _ULL(0xB01C90199483B1C7) /* 709 */,
_ULL(0x3DE93CD5C295376C) /* 710 */, _ULL(0xAED52EDF2AB9AD13) /* 711 */,
_ULL(0x2E60F512C0A07884) /* 712 */, _ULL(0xBC3D86A3E36210C9) /* 713 */,
_ULL(0x35269D9B163951CE) /* 714 */, _ULL(0x0C7D6E2AD0CDB5FA) /* 715 */,
_ULL(0x59E86297D87F5733) /* 716 */, _ULL(0x298EF221898DB0E7) /* 717 */,
_ULL(0x55000029D1A5AA7E) /* 718 */, _ULL(0x8BC08AE1B5061B45) /* 719 */,
_ULL(0xC2C31C2B6C92703A) /* 720 */, _ULL(0x94CC596BAF25EF42) /* 721 */,
_ULL(0x0A1D73DB22540456) /* 722 */, _ULL(0x04B6A0F9D9C4179A) /* 723 */,
_ULL(0xEFFDAFA2AE3D3C60) /* 724 */, _ULL(0xF7C8075BB49496C4) /* 725 */,
_ULL(0x9CC5C7141D1CD4E3) /* 726 */, _ULL(0x78BD1638218E5534) /* 727 */,
_ULL(0xB2F11568F850246A) /* 728 */, _ULL(0xEDFABCFA9502BC29) /* 729 */,
_ULL(0x796CE5F2DA23051B) /* 730 */, _ULL(0xAAE128B0DC93537C) /* 731 */,
_ULL(0x3A493DA0EE4B29AE) /* 732 */, _ULL(0xB5DF6B2C416895D7) /* 733 */,
_ULL(0xFCABBD25122D7F37) /* 734 */, _ULL(0x70810B58105DC4B1) /* 735 */,
_ULL(0xE10FDD37F7882A90) /* 736 */, _ULL(0x524DCAB5518A3F5C) /* 737 */,
_ULL(0x3C9E85878451255B) /* 738 */, _ULL(0x4029828119BD34E2) /* 739 */,
_ULL(0x74A05B6F5D3CECCB) /* 740 */, _ULL(0xB610021542E13ECA) /* 741 */,
_ULL(0x0FF979D12F59E2AC) /* 742 */, _ULL(0x6037DA27E4F9CC50) /* 743 */,
_ULL(0x5E92975A0DF1847D) /* 744 */, _ULL(0xD66DE190D3E623FE) /* 745 */,
_ULL(0x5032D6B87B568048) /* 746 */, _ULL(0x9A36B7CE8235216E) /* 747 */,
_ULL(0x80272A7A24F64B4A) /* 748 */, _ULL(0x93EFED8B8C6916F7) /* 749 */,
_ULL(0x37DDBFF44CCE1555) /* 750 */, _ULL(0x4B95DB5D4B99BD25) /* 751 */,
_ULL(0x92D3FDA169812FC0) /* 752 */, _ULL(0xFB1A4A9A90660BB6) /* 753 */,
_ULL(0x730C196946A4B9B2) /* 754 */, _ULL(0x81E289AA7F49DA68) /* 755 */,
_ULL(0x64669A0F83B1A05F) /* 756 */, _ULL(0x27B3FF7D9644F48B) /* 757 */,
_ULL(0xCC6B615C8DB675B3) /* 758 */, _ULL(0x674F20B9BCEBBE95) /* 759 */,
_ULL(0x6F31238275655982) /* 760 */, _ULL(0x5AE488713E45CF05) /* 761 */,
_ULL(0xBF619F9954C21157) /* 762 */, _ULL(0xEABAC46040A8EAE9) /* 763 */,
_ULL(0x454C6FE9F2C0C1CD) /* 764 */, _ULL(0x419CF6496412691C) /* 765 */,
_ULL(0xD3DC3BEF265B0F70) /* 766 */, _ULL(0x6D0E60F5C3578A9E) /* 767 */,
_ULL(0x5B0E608526323C55) /* 768 */, _ULL(0x1A46C1A9FA1B59F5) /* 769 */,
_ULL(0xA9E245A17C4C8FFA) /* 770 */, _ULL(0x65CA5159DB2955D7) /* 771 */,
_ULL(0x05DB0A76CE35AFC2) /* 772 */, _ULL(0x81EAC77EA9113D45) /* 773 */,
_ULL(0x528EF88AB6AC0A0D) /* 774 */, _ULL(0xA09EA253597BE3FF) /* 775 */,
_ULL(0x430DDFB3AC48CD56) /* 776 */, _ULL(0xC4B3A67AF45CE46F) /* 777 */,
_ULL(0x4ECECFD8FBE2D05E) /* 778 */, _ULL(0x3EF56F10B39935F0) /* 779 */,
_ULL(0x0B22D6829CD619C6) /* 780 */, _ULL(0x17FD460A74DF2069) /* 781 */,
_ULL(0x6CF8CC8E8510ED40) /* 782 */, _ULL(0xD6C824BF3A6ECAA7) /* 783 */,
_ULL(0x61243D581A817049) /* 784 */, _ULL(0x048BACB6BBC163A2) /* 785 */,
_ULL(0xD9A38AC27D44CC32) /* 786 */, _ULL(0x7FDDFF5BAAF410AB) /* 787 */,
_ULL(0xAD6D495AA804824B) /* 788 */, _ULL(0xE1A6A74F2D8C9F94) /* 789 */,
_ULL(0xD4F7851235DEE8E3) /* 790 */, _ULL(0xFD4B7F886540D893) /* 791 */,
_ULL(0x247C20042AA4BFDA) /* 792 */, _ULL(0x096EA1C517D1327C) /* 793 */,
_ULL(0xD56966B4361A6685) /* 794 */, _ULL(0x277DA5C31221057D) /* 795 */,
_ULL(0x94D59893A43ACFF7) /* 796 */, _ULL(0x64F0C51CCDC02281) /* 797 */,
_ULL(0x3D33BCC4FF6189DB) /* 798 */, _ULL(0xE005CB184CE66AF1) /* 799 */,
_ULL(0xFF5CCD1D1DB99BEA) /* 800 */, _ULL(0xB0B854A7FE42980F) /* 801 */,
_ULL(0x7BD46A6A718D4B9F) /* 802 */, _ULL(0xD10FA8CC22A5FD8C) /* 803 */,
_ULL(0xD31484952BE4BD31) /* 804 */, _ULL(0xC7FA975FCB243847) /* 805 */,
_ULL(0x4886ED1E5846C407) /* 806 */, _ULL(0x28CDDB791EB70B04) /* 807 */,
_ULL(0xC2B00BE2F573417F) /* 808 */, _ULL(0x5C9590452180F877) /* 809 */,
_ULL(0x7A6BDDFFF370EB00) /* 810 */, _ULL(0xCE509E38D6D9D6A4) /* 811 */,
_ULL(0xEBEB0F00647FA702) /* 812 */, _ULL(0x1DCC06CF76606F06) /* 813 */,
_ULL(0xE4D9F28BA286FF0A) /* 814 */, _ULL(0xD85A305DC918C262) /* 815 */,
_ULL(0x475B1D8732225F54) /* 816 */, _ULL(0x2D4FB51668CCB5FE) /* 817 */,
_ULL(0xA679B9D9D72BBA20) /* 818 */, _ULL(0x53841C0D912D43A5) /* 819 */,
_ULL(0x3B7EAA48BF12A4E8) /* 820 */, _ULL(0x781E0E47F22F1DDF) /* 821 */,
_ULL(0xEFF20CE60AB50973) /* 822 */, _ULL(0x20D261D19DFFB742) /* 823 */,
_ULL(0x16A12B03062A2E39) /* 824 */, _ULL(0x1960EB2239650495) /* 825 */,
_ULL(0x251C16FED50EB8B8) /* 826 */, _ULL(0x9AC0C330F826016E) /* 827 */,
_ULL(0xED152665953E7671) /* 828 */, _ULL(0x02D63194A6369570) /* 829 */,
_ULL(0x5074F08394B1C987) /* 830 */, _ULL(0x70BA598C90B25CE1) /* 831 */,
_ULL(0x794A15810B9742F6) /* 832 */, _ULL(0x0D5925E9FCAF8C6C) /* 833 */,
_ULL(0x3067716CD868744E) /* 834 */, _ULL(0x910AB077E8D7731B) /* 835 */,
_ULL(0x6A61BBDB5AC42F61) /* 836 */, _ULL(0x93513EFBF0851567) /* 837 */,
_ULL(0xF494724B9E83E9D5) /* 838 */, _ULL(0xE887E1985C09648D) /* 839 */,
_ULL(0x34B1D3C675370CFD) /* 840 */, _ULL(0xDC35E433BC0D255D) /* 841 */,
_ULL(0xD0AAB84234131BE0) /* 842 */, _ULL(0x08042A50B48B7EAF) /* 843 */,
_ULL(0x9997C4EE44A3AB35) /* 844 */, _ULL(0x829A7B49201799D0) /* 845 */,
_ULL(0x263B8307B7C54441) /* 846 */, _ULL(0x752F95F4FD6A6CA6) /* 847 */,
_ULL(0x927217402C08C6E5) /* 848 */, _ULL(0x2A8AB754A795D9EE) /* 849 */,
_ULL(0xA442F7552F72943D) /* 850 */, _ULL(0x2C31334E19781208) /* 851 */,
_ULL(0x4FA98D7CEAEE6291) /* 852 */, _ULL(0x55C3862F665DB309) /* 853 */,
_ULL(0xBD0610175D53B1F3) /* 854 */, _ULL(0x46FE6CB840413F27) /* 855 */,
_ULL(0x3FE03792DF0CFA59) /* 856 */, _ULL(0xCFE700372EB85E8F) /* 857 */,
_ULL(0xA7BE29E7ADBCE118) /* 858 */, _ULL(0xE544EE5CDE8431DD) /* 859 */,
_ULL(0x8A781B1B41F1873E) /* 860 */, _ULL(0xA5C94C78A0D2F0E7) /* 861 */,
_ULL(0x39412E2877B60728) /* 862 */, _ULL(0xA1265EF3AFC9A62C) /* 863 */,
_ULL(0xBCC2770C6A2506C5) /* 864 */, _ULL(0x3AB66DD5DCE1CE12) /* 865 */,
_ULL(0xE65499D04A675B37) /* 866 */, _ULL(0x7D8F523481BFD216) /* 867 */,
_ULL(0x0F6F64FCEC15F389) /* 868 */, _ULL(0x74EFBE618B5B13C8) /* 869 */,
_ULL(0xACDC82B714273E1D) /* 870 */, _ULL(0xDD40BFE003199D17) /* 871 */,
_ULL(0x37E99257E7E061F8) /* 872 */, _ULL(0xFA52626904775AAA) /* 873 */,
_ULL(0x8BBBF63A463D56F9) /* 874 */, _ULL(0xF0013F1543A26E64) /* 875 */,
_ULL(0xA8307E9F879EC898) /* 876 */, _ULL(0xCC4C27A4150177CC) /* 877 */,
_ULL(0x1B432F2CCA1D3348) /* 878 */, _ULL(0xDE1D1F8F9F6FA013) /* 879 */,
_ULL(0x606602A047A7DDD6) /* 880 */, _ULL(0xD237AB64CC1CB2C7) /* 881 */,
_ULL(0x9B938E7225FCD1D3) /* 882 */, _ULL(0xEC4E03708E0FF476) /* 883 */,
_ULL(0xFEB2FBDA3D03C12D) /* 884 */, _ULL(0xAE0BCED2EE43889A) /* 885 */,
_ULL(0x22CB8923EBFB4F43) /* 886 */, _ULL(0x69360D013CF7396D) /* 887 */,
_ULL(0x855E3602D2D4E022) /* 888 */, _ULL(0x073805BAD01F784C) /* 889 */,
_ULL(0x33E17A133852F546) /* 890 */, _ULL(0xDF4874058AC7B638) /* 891 */,
_ULL(0xBA92B29C678AA14A) /* 892 */, _ULL(0x0CE89FC76CFAADCD) /* 893 */,
_ULL(0x5F9D4E0908339E34) /* 894 */, _ULL(0xF1AFE9291F5923B9) /* 895 */,
_ULL(0x6E3480F60F4A265F) /* 896 */, _ULL(0xEEBF3A2AB29B841C) /* 897 */,
_ULL(0xE21938A88F91B4AD) /* 898 */, _ULL(0x57DFEFF845C6D3C3) /* 899 */,
_ULL(0x2F006B0BF62CAAF2) /* 900 */, _ULL(0x62F479EF6F75EE78) /* 901 */,
_ULL(0x11A55AD41C8916A9) /* 902 */, _ULL(0xF229D29084FED453) /* 903 */,
_ULL(0x42F1C27B16B000E6) /* 904 */, _ULL(0x2B1F76749823C074) /* 905 */,
_ULL(0x4B76ECA3C2745360) /* 906 */, _ULL(0x8C98F463B91691BD) /* 907 */,
_ULL(0x14BCC93CF1ADE66A) /* 908 */, _ULL(0x8885213E6D458397) /* 909 */,
_ULL(0x8E177DF0274D4711) /* 910 */, _ULL(0xB49B73B5503F2951) /* 911 */,
_ULL(0x10168168C3F96B6B) /* 912 */, _ULL(0x0E3D963B63CAB0AE) /* 913 */,
_ULL(0x8DFC4B5655A1DB14) /* 914 */, _ULL(0xF789F1356E14DE5C) /* 915 */,
_ULL(0x683E68AF4E51DAC1) /* 916 */, _ULL(0xC9A84F9D8D4B0FD9) /* 917 */,
_ULL(0x3691E03F52A0F9D1) /* 918 */, _ULL(0x5ED86E46E1878E80) /* 919 */,
_ULL(0x3C711A0E99D07150) /* 920 */, _ULL(0x5A0865B20C4E9310) /* 921 */,
_ULL(0x56FBFC1FE4F0682E) /* 922 */, _ULL(0xEA8D5DE3105EDF9B) /* 923 */,
_ULL(0x71ABFDB12379187A) /* 924 */, _ULL(0x2EB99DE1BEE77B9C) /* 925 */,
_ULL(0x21ECC0EA33CF4523) /* 926 */, _ULL(0x59A4D7521805C7A1) /* 927 */,
_ULL(0x3896F5EB56AE7C72) /* 928 */, _ULL(0xAA638F3DB18F75DC) /* 929 */,
_ULL(0x9F39358DABE9808E) /* 930 */, _ULL(0xB7DEFA91C00B72AC) /* 931 */,
_ULL(0x6B5541FD62492D92) /* 932 */, _ULL(0x6DC6DEE8F92E4D5B) /* 933 */,
_ULL(0x353F57ABC4BEEA7E) /* 934 */, _ULL(0x735769D6DA5690CE) /* 935 */,
_ULL(0x0A234AA642391484) /* 936 */, _ULL(0xF6F9508028F80D9D) /* 937 */,
_ULL(0xB8E319A27AB3F215) /* 938 */, _ULL(0x31AD9C1151341A4D) /* 939 */,
_ULL(0x773C22A57BEF5805) /* 940 */, _ULL(0x45C7561A07968633) /* 941 */,
_ULL(0xF913DA9E249DBE36) /* 942 */, _ULL(0xDA652D9B78A64C68) /* 943 */,
_ULL(0x4C27A97F3BC334EF) /* 944 */, _ULL(0x76621220E66B17F4) /* 945 */,
_ULL(0x967743899ACD7D0B) /* 946 */, _ULL(0xF3EE5BCAE0ED6782) /* 947 */,
_ULL(0x409F753600C879FC) /* 948 */, _ULL(0x06D09A39B5926DB6) /* 949 */,
_ULL(0x6F83AEB0317AC588) /* 950 */, _ULL(0x01E6CA4A86381F21) /* 951 */,
_ULL(0x66FF3462D19F3025) /* 952 */, _ULL(0x72207C24DDFD3BFB) /* 953 */,
_ULL(0x4AF6B6D3E2ECE2EB) /* 954 */, _ULL(0x9C994DBEC7EA08DE) /* 955 */,
_ULL(0x49ACE597B09A8BC4) /* 956 */, _ULL(0xB38C4766CF0797BA) /* 957 */,
_ULL(0x131B9373C57C2A75) /* 958 */, _ULL(0xB1822CCE61931E58) /* 959 */,
_ULL(0x9D7555B909BA1C0C) /* 960 */, _ULL(0x127FAFDD937D11D2) /* 961 */,
_ULL(0x29DA3BADC66D92E4) /* 962 */, _ULL(0xA2C1D57154C2ECBC) /* 963 */,
_ULL(0x58C5134D82F6FE24) /* 964 */, _ULL(0x1C3AE3515B62274F) /* 965 */,
_ULL(0xE907C82E01CB8126) /* 966 */, _ULL(0xF8ED091913E37FCB) /* 967 */,
_ULL(0x3249D8F9C80046C9) /* 968 */, _ULL(0x80CF9BEDE388FB63) /* 969 */,
_ULL(0x1881539A116CF19E) /* 970 */, _ULL(0x5103F3F76BD52457) /* 971 */,
_ULL(0x15B7E6F5AE47F7A8) /* 972 */, _ULL(0xDBD7C6DED47E9CCF) /* 973 */,
_ULL(0x44E55C410228BB1A) /* 974 */, _ULL(0xB647D4255EDB4E99) /* 975 */,
_ULL(0x5D11882BB8AAFC30) /* 976 */, _ULL(0xF5098BBB29D3212A) /* 977 */,
_ULL(0x8FB5EA14E90296B3) /* 978 */, _ULL(0x677B942157DD025A) /* 979 */,
_ULL(0xFB58E7C0A390ACB5) /* 980 */, _ULL(0x89D3674C83BD4A01) /* 981 */,
_ULL(0x9E2DA4DF4BF3B93B) /* 982 */, _ULL(0xFCC41E328CAB4829) /* 983 */,
_ULL(0x03F38C96BA582C52) /* 984 */, _ULL(0xCAD1BDBD7FD85DB2) /* 985 */,
_ULL(0xBBB442C16082AE83) /* 986 */, _ULL(0xB95FE86BA5DA9AB0) /* 987 */,
_ULL(0xB22E04673771A93F) /* 988 */, _ULL(0x845358C9493152D8) /* 989 */,
_ULL(0xBE2A488697B4541E) /* 990 */, _ULL(0x95A2DC2DD38E6966) /* 991 */,
_ULL(0xC02C11AC923C852B) /* 992 */, _ULL(0x2388B1990DF2A87B) /* 993 */,
_ULL(0x7C8008FA1B4F37BE) /* 994 */, _ULL(0x1F70D0C84D54E503) /* 995 */,
_ULL(0x5490ADEC7ECE57D4) /* 996 */, _ULL(0x002B3C27D9063A3A) /* 997 */,
_ULL(0x7EAEA3848030A2BF) /* 998 */, _ULL(0xC602326DED2003C0) /* 999 */,
_ULL(0x83A7287D69A94086) /* 1000 */, _ULL(0xC57A5FCB30F57A8A) /* 1001 */,
_ULL(0xB56844E479EBE779) /* 1002 */, _ULL(0xA373B40F05DCBCE9) /* 1003 */,
_ULL(0xD71A786E88570EE2) /* 1004 */, _ULL(0x879CBACDBDE8F6A0) /* 1005 */,
_ULL(0x976AD1BCC164A32F) /* 1006 */, _ULL(0xAB21E25E9666D78B) /* 1007 */,
_ULL(0x901063AAE5E5C33C) /* 1008 */, _ULL(0x9818B34448698D90) /* 1009 */,
_ULL(0xE36487AE3E1E8ABB) /* 1010 */, _ULL(0xAFBDF931893BDCB4) /* 1011 */,
_ULL(0x6345A0DC5FBBD519) /* 1012 */, _ULL(0x8628FE269B9465CA) /* 1013 */,
_ULL(0x1E5D01603F9C51EC) /* 1014 */, _ULL(0x4DE44006A15049B7) /* 1015 */,
_ULL(0xBF6C70E5F776CBB1) /* 1016 */, _ULL(0x411218F2EF552BED) /* 1017 */,
_ULL(0xCB0C0708705A36A3) /* 1018 */, _ULL(0xE74D14754F986044) /* 1019 */,
_ULL(0xCD56D9430EA8280E) /* 1020 */, _ULL(0xC12591D7535F5065) /* 1021 */,
_ULL(0xC83223F1720AEF96) /* 1022 */, _ULL(0xC3A0396F7363A51F) /* 1023 */
};
}

66
src/adchpp/TigerHash.h Normal file
View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_TIGER_HASH_H
#define ADCHPP_TIGER_HASH_H
namespace adchpp {
class TigerHash : private boost::noncopyable {
public:
/** Hash size */
static const size_t BITS = 192;
static const size_t BYTES = BITS / 8;
TigerHash() : pos(0) {
res[0]=_ULL(0x0123456789ABCDEF);
res[1]=_ULL(0xFEDCBA9876543210);
res[2]=_ULL(0xF096A5B4C3B2E187);
}
TigerHash(uint64_t pos, uint64_t initial_res[3]) : pos(pos) {
res[0] = initial_res[0];
res[1] = initial_res[1];
res[2] = initial_res[2];
}
~TigerHash() { }
/** Calculates the Tiger hash of the data. */
ADCHPP_DLL void update(const void* data, size_t len);
/** Call once all data has been processed. */
ADCHPP_DLL uint8_t* finalize();
uint8_t* getResult() { return (uint8_t*) res; }
private:
enum { BLOCK_SIZE = 512/8 };
/** 512 bit blocks for the compress function */
uint8_t tmp[512/8];
/** State / final hash value */
uint64_t res[3];
/** Total number of bytes compressed */
uint64_t pos;
/** S boxes */
static uint64_t table[];
void tigerCompress(const uint64_t* data, uint64_t state[3]);
};
}
#endif // _TIGER_HASH

14
src/adchpp/TimeUtil.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef ADCHPP_ADCHPP_TIME_H_
#define ADCHPP_ADCHPP_TIME_H_
#include <boost/date_time/posix_time/posix_time.hpp>
namespace adchpp {
namespace time {
using namespace boost::posix_time;
inline ptime now() { return microsec_clock::local_time(); }
}
}
#endif /* TIME_H_ */

365
src/adchpp/Util.cpp Normal file
View File

@@ -0,0 +1,365 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include <random>
#include "Util.h"
#include "FastAlloc.h"
#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/utsname.h>
#include <ctype.h>
#endif
#include "TimeUtil.h"
namespace adchpp {
using namespace std;
#ifdef NDEBUG
FastMutex FastAllocBase::mtx;
#endif
#ifndef _WIN32
string Util::appName;
string Util::appPath;
#endif
string Util::emptyString;
wstring Util::emptyStringW;
/**
* Decodes a URL the best it can...
* Default ports:
* http:// -> port 80
* dchub:// -> port 411
*/
void Util::decodeUrl(const string& url, string& aServer, short& aPort, string& aFile) {
// First, check for a protocol: xxxx://
string::size_type i = 0, j, k;
aServer.clear();
aFile.clear();
if( (j=url.find("://", i)) != string::npos) {
// Protocol found
string protocol = url.substr(0, j);
i = j + 3;
if(protocol == "http") {
aPort = 80;
} else if(protocol == "dchub") {
aPort = 411;
}
}
if( (j=url.find('/', i)) != string::npos) {
// We have a filename...
aFile = url.substr(j);
}
if( (k=url.find(':', i)) != string::npos) {
// Port
if(k < j)
aPort = (short)Util::toInt(url.substr(k+1, j-k-1));
} else {
k = j;
}
// Only the server should be left now...
aServer = url.substr(i, k-i);
}
void Util::tokenize(StringList& lst, const string& str, char sep, string::size_type j) {
string::size_type i = 0;
while( (i=str.find_first_of(sep, j)) != string::npos ) {
lst.push_back(str.substr(j, i-j));
j = i + 1;
}
if(j <= str.size())
lst.push_back(str.substr(j, str.size()-j));
}
#ifdef _WIN32
string Util::getAppPath() {
string tmp = getAppName();
string::size_type i = tmp.rfind('\\');
if(i != string::npos)
tmp.erase(i+1);
return tmp;
}
string Util::getAppName() {
string tmp(MAX_PATH + 1, '\0');
tmp.resize(::GetModuleFileNameA(NULL, &tmp[0], MAX_PATH));
return tmp;
}
#else // WIN32
void Util::setApp(const string& app) {
string::size_type i = app.rfind('/');
if(i != string::npos) {
appPath = app.substr(0, i+1);
appName = app;
}
}
string Util::getAppPath() {
return appPath;
}
string Util::getAppName() {
return appName;
}
#endif // WIN32
string Util::getLocalIp() {
string tmp;
char buf[256];
gethostname(buf, 255);
hostent* he = gethostbyname(buf);
if(he == NULL || he->h_addr_list[0] == 0)
return Util::emptyString;
sockaddr_in dest;
int i = 0;
// We take the first ip as default, but if we can find a better one, use it instead...
memcpy(&(dest.sin_addr), he->h_addr_list[i++], he->h_length);
tmp = inet_ntoa(dest.sin_addr);
if( strncmp(tmp.c_str(), "192", 3) == 0 ||
strncmp(tmp.c_str(), "169", 3) == 0 ||
strncmp(tmp.c_str(), "127", 3) == 0 ||
strncmp(tmp.c_str(), "10", 2) == 0 ) {
while(he->h_addr_list[i]) {
memcpy(&(dest.sin_addr), he->h_addr_list[i], he->h_length);
string tmp2 = inet_ntoa(dest.sin_addr);
if( strncmp(tmp2.c_str(), "192", 3) != 0 &&
strncmp(tmp2.c_str(), "169", 3) != 0 &&
strncmp(tmp2.c_str(), "127", 3) != 0 &&
strncmp(tmp2.c_str(), "10", 2) != 0) {
tmp = tmp2;
}
i++;
}
}
return tmp;
}
string Util::formatBytes(int64_t aBytes) {
char buf[64];
if(aBytes < 1024) {
sprintf(buf, "%d B", (int)(aBytes&0xffffffff));
} else if(aBytes < 1024*1024) {
sprintf(buf, "%.02f KiB", (double)aBytes/(1024.0));
} else if(aBytes < 1024*1024*1024) {
sprintf(buf, "%.02f MiB", (double)aBytes/(1024.0*1024.0));
} else if(aBytes < (int64_t)1024*1024*1024*1024) {
sprintf(buf, "%.02f GiB", (double)aBytes/(1024.0*1024.0*1024.0));
} else {
sprintf(buf, "%.02f TiB", (double)aBytes/(1024.0*1024.0*1024.0*1024.0));
}
return buf;
}
string Util::getShortTimeString() {
char buf[8];
time_t _tt;
std::time(&_tt);
tm* _tm = localtime(&_tt);
strftime(buf, 8, "%H:%M", _tm);
return buf;
}
string Util::getTimeString() {
char buf[64];
time_t _tt;
std::time(&_tt);
tm* _tm = localtime(&_tt);
if(_tm == NULL) {
strcpy(buf, "xx:xx:xx");
} else {
strftime(buf, 64, "%X", _tm);
}
return buf;
}
string Util::formatTime(const string& msg, time_t t /* = time(NULL) */) {
size_t bufsize = msg.size() + 64;
char* buf = new char[bufsize];
while(!strftime(buf, bufsize-1, msg.c_str(), localtime(&t))) {
delete buf;
bufsize+=64;
buf = new char[bufsize];
}
string result = buf;
delete[] buf;
return result;
}
string Util::translateError(int aError) {
#ifdef _WIN32
LPVOID lpMsgBuf;
::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
aError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
#ifdef _UNICODE
string tmp = Util::toAcp((LPCTSTR)lpMsgBuf);
#else
string tmp = (LPCTSTR)lpMsgBuf;
#endif
// Free the buffer.
LocalFree( lpMsgBuf );
#else // WIN32
string tmp = strerror(aError);
#endif // WIN32
string::size_type i = 0;
while( (i = tmp.find_first_of("\r\n", i)) != string::npos) {
tmp.erase(i, 1);
}
return tmp;
}
string Util::getOsVersion() {
#ifdef _WIN32
string os;
OSVERSIONINFOEX ver;
memset(&ver, 0, sizeof(OSVERSIONINFOEX));
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if(!GetVersionEx((OSVERSIONINFO*)&ver)) {
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(!GetVersionEx((OSVERSIONINFO*)&ver)) {
os = "Windows (version unknown)";
}
}
if(os.empty()) {
if(ver.dwPlatformId != VER_PLATFORM_WIN32_NT) {
os = "Win9x/ME/Junk";
} else if(ver.dwMajorVersion == 4) {
os = "WinNT4";
} else if(ver.dwMajorVersion == 5) {
if(ver.dwMinorVersion == 0) {
os = "Win2000";
} else if(ver.dwMinorVersion == 1) {
os = "WinXP";
} else if(ver.dwMinorVersion == 2) {
os = "Win2003";
} else {
os = "WinUnknown";
}
if(ver.wProductType == VER_NT_WORKSTATION)
os += " Pro";
else if(ver.wProductType == VER_NT_SERVER)
os += " Server";
else if(ver.wProductType == VER_NT_DOMAIN_CONTROLLER)
os += " DC";
}
if(ver.wServicePackMajor > 0) {
os += " SP" + Util::toString(ver.wServicePackMajor);
}
}
return os;
#else // WIN32
utsname n;
if(uname(&n) != 0) {
return "unix (unknown version)";
}
return string(n.sysname) + " " + string(n.release) + " (" + string(n.machine) + ")";
#endif // WIN32
}
#ifdef __MINGW32__
// creating a random_device throws an exception in MinGW with GCC 4.6; simpler alternative...
uint32_t Util::rand() {
static bool init = false;
if(!init) {
::srand(::time(0));
init = true;
}
return ::rand();
}
#else
uint32_t Util::rand() {
static std::random_device rd;
static std::default_random_engine dre(rd());
return dre();
}
#endif
bool Util::isPrivateIp(std::string const& ip) {
struct in_addr addr;
addr.s_addr = inet_addr(ip.c_str());
if (addr.s_addr != INADDR_NONE) {
unsigned long haddr = ntohl(addr.s_addr);
return ((haddr & 0xff000000) == 0x0a000000 || // 10.0.0.0/8
(haddr & 0xff000000) == 0x7f000000 || // 127.0.0.0/8
(haddr & 0xfff00000) == 0xac100000 || // 172.16.0.0/12
(haddr & 0xffff0000) == 0xc0a80000); // 192.168.0.0/16
}
return false;
}
bool Util::validateCharset(std::string const& field, int p) {
for(string::size_type i = 0; i < field.length(); ++i) {
if((uint8_t) field[i] < p) {
return false;
}
}
return true;
}
}

237
src/adchpp/Util.h Normal file
View File

@@ -0,0 +1,237 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_UTIL_H
#define ADCHPP_UTIL_H
#include "common.h"
namespace adchpp {
/** Evaluates op(pair<T1, T2>.first, compareTo) */
template<class T1, class T2, class op = std::equal_to<T1> >
class CompareFirst {
public:
CompareFirst(const T1& compareTo) : a(compareTo) { }
bool operator()(const std::pair<T1, T2>& p) { return op()(p.first, a); }
private:
CompareFirst& operator=(const CompareFirst&);
const T1& a;
};
/** Evaluates op(pair<T1, T2>.second, compareTo) */
template<class T1, class T2, class op = std::equal_to<T2> >
class CompareSecond {
public:
CompareSecond(const T2& compareTo) : a(compareTo) { }
bool operator()(const std::pair<T1, T2>& p) { return op()(p.second, a); }
private:
CompareSecond& operator=(const CompareSecond&);
const T2& a;
};
struct DeleteFunction {
template<typename T>
void operator()(T* ptr) { delete ptr; }
};
/**
* Compares two values
* @return -1 if v1 < v2, 0 if v1 == v2 and 1 if v1 > v2
*/
template<typename T1>
inline int compare(const T1& v1, const T1& v2) { return (v1 < v2) ? -1 : ((v1 == v2) ? 0 : 1); }
class Flags {
public:
typedef size_t MaskType;
Flags() : flags(0) { }
Flags(const Flags& rhs) : flags(rhs.flags) { }
Flags(MaskType f) : flags(f) { }
MaskType getFlags() const { return flags; }
bool isSet(MaskType aFlag) const { return (flags & aFlag) == aFlag; }
bool isAnySet(MaskType aFlag) const { return (flags & aFlag) != 0; }
void setFlag(MaskType aFlag) { flags |= aFlag; }
void unsetFlag(MaskType aFlag) { flags &= ~aFlag; }
Flags& operator=(const Flags& rhs) { flags = rhs.flags; return *this; }
private:
MaskType flags;
};
class Util
{
public:
enum Reason {
REASON_BAD_STATE,
REASON_CID_CHANGE,
REASON_CID_TAKEN,
REASON_FLOODING,
REASON_HUB_FULL,
REASON_INVALID_COMMAND_TYPE,
REASON_INVALID_IP,
REASON_INVALID_SID,
REASON_LOGIN_TIMEOUT,
REASON_MAX_COMMAND_SIZE,
REASON_NICK_INVALID,
REASON_NICK_TAKEN,
REASON_NO_BASE_SUPPORT,
REASON_NO_TIGR_SUPPORT,
REASON_PID_MISSING,
REASON_PID_CID_LENGTH,
REASON_PID_CID_MISMATCH,
REASON_PID_WITHOUT_CID,
REASON_PLUGIN,
REASON_WRITE_OVERFLOW,
REASON_NO_BANDWIDTH,
REASON_INVALID_DESCRIPTION,
REASON_WRITE_TIMEOUT,
REASON_SOCKET_ERROR,
REASON_LAST,
};
ADCHPP_DLL static std::string emptyString;
static std::wstring emptyStringW;
ADCHPP_DLL static std::string getOsVersion();
ADCHPP_DLL static void decodeUrl(const std::string& aUrl, std::string& aServer, short& aPort, std::string& aFile);
ADCHPP_DLL static std::string formatTime(const std::string& msg, time_t t = std::time(NULL));
ADCHPP_DLL static std::string getAppPath();
ADCHPP_DLL static std::string getAppName();
#ifndef _WIN32
ADCHPP_DLL static void setApp(const std::string& app);
static std::string appPath;
static std::string appName;
#endif
ADCHPP_DLL static std::string translateError(int aError);
static std::string formatBytes(const std::string& aString) { return formatBytes(toInt64(aString)); }
ADCHPP_DLL static std::string getShortTimeString();
ADCHPP_DLL static std::string getTimeString();
ADCHPP_DLL static std::string formatBytes(int64_t aBytes);
ADCHPP_DLL static void tokenize(StringList& lst, const std::string& str, char sep, std::string::size_type j = 0);
static std::string formatSeconds(int64_t aSec) {
char buf[64];
sprintf(buf, "%01d:%02d:%02d:%02d", (int)(aSec / (24*60*60)), (int)((aSec / (60*60)) % 24), (int)((aSec / 60) % 60), (int)(aSec % 60));
return buf;
}
static bool toBool(const std::string& aString) { return toBool(aString.c_str()); }
static int toInt(const std::string& aString) { return toInt(aString.c_str()); }
static double toDouble(const std::string& aString) { return toDouble(aString.c_str()); }
static float toFloat(const std::string& aString) { return toFloat(aString.c_str()); }
static int64_t toInt64(const std::string& aString) { return toInt64(aString.c_str()); }
static bool toBool(const char* aString) { return toInt(aString) > 0; }
static int toInt(const char* aString) { return ::atoi(aString); }
static double toDouble(const char* aString) { return ::atof(aString); }
static float toFloat(const char* aString) { return (float)::atof(aString); }
static int64_t toInt64(const char* aString) {
#ifdef _MSC_VER
return _atoi64(aString);
#else
return atoll(aString);
#endif
}
static std::string toString(bool val) {
return val ? "1" : "0";
}
static std::string toString(short val) {
char buf[8];
sprintf(buf, "%d", (int)val);
return buf;
}
static std::string toString(unsigned short val) {
char buf[8];
sprintf(buf, "%u", (unsigned int)val);
return buf;
}
static std::string toString(int val) {
char buf[16];
sprintf(buf, "%d", val);
return buf;
}
static std::string toString(unsigned int val) {
char buf[16];
sprintf(buf, "%u", val);
return buf;
}
static std::string toString(long val) {
char buf[32];
sprintf(buf, "%ld", val);
return buf;
}
static std::string toString(unsigned long val) {
char buf[32];
sprintf(buf, "%lu", val);
return buf;
}
static std::string toString(long long val) {
char buf[32];
#if defined(_MSC_VER) || defined(__MINGW32__)
sprintf(buf, "%I64d", val);
#else
sprintf(buf, "%lld", val);
#endif
return buf;
}
static std::string toString(unsigned long long val) {
char buf[32];
#if defined(_MSC_VER) || defined(__MINGW32__)
sprintf(buf, "%I64u", val);
#else
sprintf(buf, "%llu", val);
#endif
return buf;
}
static std::string toString(double val, int maxDec = 2) {
char buf[32];
sprintf(buf, "%.*f", maxDec, val);
return buf;
}
static const std::string& toString(const std::string& aString) {
return aString;
}
/** Avoid this! Use the one of a connected socket instead... */
ADCHPP_DLL static std::string getLocalIp();
ADCHPP_DLL static uint32_t rand();
static uint32_t rand(uint32_t high) { return rand() % high; }
static uint32_t rand(uint32_t low, uint32_t high) { return rand(high-low) + low; }
static double randd() { return ((double)rand()) / ((double)0xffffffff); }
ADCHPP_DLL static bool isPrivateIp(std::string const& ip);
ADCHPP_DLL static bool validateCharset(std::string const& field, int p);
};
}
#endif // UTIL_H

19
src/adchpp/adchpp.cpp Normal file
View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"

75
src/adchpp/adchpp.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_ADCHPP_H
#define ADCHPP_ADCHPP_H
#include "compiler.h"
#include "config.h"
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#include <tchar.h>
#else
#include <sys/time.h>
#endif
#include <cerrno>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <ctime>
#include <string>
#include <vector>
#include <list>
#include <functional>
#include <memory>
#include <algorithm>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include "shared_ptr.h"
#include "nullptr.h"
#include <boost/noncopyable.hpp>
#ifdef _UNICODE
# ifndef _T
# define _T(s) L##s
# endif
#else
# ifndef _T
# define _T(s) s
# endif
#endif
#if defined(max) || defined(min)
#error min/max defined
#endif
#endif // STDINC_H

42
src/adchpp/common.cpp Normal file
View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "File.h"
namespace adchpp {
using namespace std;
const char compileTime[] = __DATE__ " " __TIME__;
//#ifdef _DEBUG
void logAssert(const char* file, int line, const char* exp) {
try {
//File f(Util::getCfgPath() + _T("exceptioninfo.txt"), File::WRITE, File::OPEN | File::CREATE);
//f.setEndPos(0);
//f.write(string(file) + "(" + Util::toString(line) + "): " + string(exp) + "\r\n");
} catch (const FileException& e) {
dcdebug("logAssert: %s\n", e.getError().c_str());
}
}
//#endif // _DEBUG
}

91
src/adchpp/common.h Normal file
View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**
* @mainpage
*
* ADCH++ is a server application meant to be used in the Direct Connect network,
* released under the GPL-2 license.
*
* There's a plugin API about which you can find some general
* information on the @ref PluginAPI page.
*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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.
*
* Please see License.txt for full details regarding licensing.
*/
#ifndef ADCHPP_COMMON_H
#define ADCHPP_COMMON_H
namespace adchpp {
extern ADCHPP_DLL const char compileTime[];
extern ADCHPP_DLL void logAssert(const char* file, int line, const char* exp);
#ifndef NDEBUG
inline void debugTrace(const char* format, ...)
{
va_list args;
va_start(args, format);
#ifdef _MSC_VER
char buf[512];
_vsnprintf(buf, sizeof(buf), format, args);
OutputDebugStringA(buf);
fputs(buf, stderr);
#else // _MSC_VER
vfprintf(stdout, format, args);
#endif // _MSC_VER
va_end(args);
}
#define dcdebug debugTrace
#define dcassert(exp) do { if(!(exp)) logAssert(__FILE__, __LINE__, #exp); } while(false)
//#define dcassert(exp) do { if(!(exp)) __asm { int 3}; } while(0)
#define dcasserta(exp) dcassert(exp)
#define dcdrun(exp) exp
#else //NDEBUG
#define dcdebug if(false) printf
//#define dcassert(exp) do { if(!(exp)) logAssert(__FILE__, __LINE__, #exp); } while(0)
#define dcassert(exp)
#ifdef _MSC_VER
#define dcasserta(exp) __assume(exp)
#else
#define dcasserta(exp)
#endif // WIN32
#define dcdrun(exp)
#endif //NDEBUG
typedef std::vector<std::string> StringList;
typedef StringList::iterator StringIter;
typedef StringList::const_iterator StringIterC;
typedef std::vector<uint8_t> ByteVector;
typedef ByteVector::iterator ByteIter;
}
#endif // COMMON_H

37
src/adchpp/compiler.h Normal file
View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#if defined(__GNUC__)
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)
#error GCC 4.4 is required
#endif
#if __GNUC_MINOR__ == 4
// GCC 4.4 is missing this type
#define default_random_engine minstd_rand0
#endif
#elif defined(_MSC_VER)
#if _MSC_VER < 1600
#error MSVC 10 (2010) is required
#endif
#else
#error No supported compiler found
#endif

91
src/adchpp/config.h Normal file
View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_ADCHPP_CONFIG_H_
#define ADCHPP_ADCHPP_CONFIG_H_
#ifndef _REENTRANT
# define _REENTRANT 1
#endif
#ifdef _MSC_VER
//disable the deprecated warnings for the CRT functions.
# define _CRT_SECURE_NO_DEPRECATE 1
# define _ATL_SECURE_NO_DEPRECATE 1
# define _CRT_NON_CONFORMING_SWPRINTFS 1
#endif
#if defined(_MSC_VER) || defined(__MINGW32__)
# define _LL(x) x##ll
# define _ULL(x) x##ull
# define I64_FMT "%I64d"
#elif defined(SIZEOF_LONG) && SIZEOF_LONG == 8
# define _LL(x) x##l
# define _ULL(x) x##ul
# define I64_FMT "%ld"
#else
# define _LL(x) x##ll
# define _ULL(x) x##ull
# define I64_FMT "%lld"
#endif
#ifdef _WIN32
#define PATH_SEPARATOR '\\'
#define PATH_SEPARATOR_STR "\\"
#else
#define PATH_SEPARATOR '/'
#define PATH_SEPARATOR_STR "/"
#endif
#ifdef _WIN32
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0501
# endif
# ifndef _WIN32_IE
# define _WIN32_IE 0x0501
# endif
# ifndef WINVER
# define WINVER 0x0501
# endif
# ifndef STRICT
# define STRICT 1
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN 1
# endif
# ifndef NOMINMAX
# define NOMINMAX
# endif
# define ADCHPP_VISIBLE
# ifdef BUILDING_ADCHPP
# define ADCHPP_DLL __declspec(dllexport)
# else
# define ADCHPP_DLL __declspec(dllimport)
# endif // DLLEXPORT
#else
# define ADCHPP_DLL __attribute__ ((visibility("default")))
# define ADCHPP_VISIBLE __attribute__ ((visibility("default")))
#endif
#endif /* CONFIG_H_ */

56
src/adchpp/forward.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_ADCHPP_FORWARD_H_
#define ADCHPP_ADCHPP_FORWARD_H_
#include <vector>
#include "shared_ptr.h"
namespace adchpp {
class Client;
class ClientManager;
class Core;
class Entity;
class LogManager;
class ManagedSocket;
typedef shared_ptr<ManagedSocket> ManagedSocketPtr;
class PluginManager;
struct ServerInfo;
typedef shared_ptr<ServerInfo> ServerInfoPtr;
typedef std::vector<ServerInfoPtr> ServerInfoList;
class SimpleXML;
class SocketFactory;
typedef shared_ptr<SocketFactory> SocketFactoryPtr;
class SocketManager;
}
#endif /*FORWARD_H_*/

27
src/adchpp/nullptr.h Normal file
View File

@@ -0,0 +1,27 @@
// for compilers that don't support nullptr, use the workaround in section 1.1 of the proposal.
#ifndef ADCHPP_NULLPTR_H
#define ADCHPP_NULLPTR_H
#ifdef __GNUC__
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) // GCC 4.6 is the first GCC to implement nullptr.
#define FAKE_NULLPTR
const // this is a const object...
class {
public:
template<class T> // convertible to any type
operator T*() const // of null non-member
{ return 0; } // pointer...
template<class C, class T> // or any type of null
operator T C::*() const // member pointer...
{ return 0; }
private:
void operator&() const; // whose address can't be taken
} nullptr = {}; // and whose name is nullptr
#endif
#endif
#endif // ADCHPP_NULLPTR_H

58
src/adchpp/shared_ptr.h Normal file
View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_ADCHPP_SHARED_PTR_H_
#define ADCHPP_ADCHPP_SHARED_PTR_H_
#ifdef __MINGW32__
/* the shared_ptr implementation provided by MinGW / GCC 4.5's libstdc++ consumes too many
semaphores, so we prefer boost's one. see <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46455>. */
// enabling this on newer GCC versions as well as handle leaks still appear when running scripts.
/// @todo hopefully remove this someday...
#define BOOST_ASIO_DISABLE_STD_SHARED_PTR 1
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
#define SHARED_PTR_NS boost
#else
#include <memory>
#define SHARED_PTR_NS std
#endif
namespace adchpp {
using SHARED_PTR_NS::shared_ptr;
using SHARED_PTR_NS::make_shared;
using SHARED_PTR_NS::enable_shared_from_this;
using SHARED_PTR_NS::static_pointer_cast;
using SHARED_PTR_NS::dynamic_pointer_cast;
}
#undef SHARED_PTR_NS
#endif /* SHARED_PTR_H_ */

50
src/adchpp/version.cpp Normal file
View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include "version.h"
#ifndef ADCHPP_REVISION
#define ADCHPP_REVISION 0
#endif
#define xstrver(s) strver(s)
#define strver(s) #s
// don't forget to also update the .rc file of adchppd!
#define APPNAME "ADCH++"
#define VERSIONSTRING "2.12.1 (r\"" xstrver(ADCHPP_REVISION) "\")"
#define VERSIONFLOAT 2.96
#ifndef NDEBUG
#define BUILDSTRING "Debug"
#else
#define BUILDSTRING "Release"
#endif
#define FULLVERSIONSTRING VERSIONSTRING " " BUILDSTRING
namespace adchpp {
using namespace std;
string appName = APPNAME;
string versionString = FULLVERSIONSTRING;
float versionFloat = VERSIONFLOAT;
}

31
src/adchpp/version.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ADCHPP_VERSION_H
#define ADCHPP_VERSION_H
namespace adchpp {
ADCHPP_DLL extern std::string appName;
ADCHPP_DLL extern std::string versionString;
ADCHPP_DLL extern float versionFloat;
}
// This should be updated whenever the plugin API changes
#define PLUGINVERSION 1
#endif // VERSION_H