Implement #243, separate core/client (PCH support dropped for now)

This commit is contained in:
EinMByte 2015-08-21 22:22:34 +02:00
parent bdaf2c16aa
commit 8ac9520dfd
153 changed files with 360 additions and 20020 deletions

83
core/util/I2PEndian.cpp Normal file
View file

@ -0,0 +1,83 @@
#include "I2PEndian.h"
// http://habrahabr.ru/post/121811/
// http://codepad.org/2ycmkz2y
#include "LittleBigEndian.h"
#ifdef NEEDS_LOCAL_ENDIAN
uint16_t htobe16(uint16_t int16)
{
BigEndian<uint16_t> u16(int16);
return u16.raw_value;
}
uint32_t htobe32(uint32_t int32)
{
BigEndian<uint32_t> u32(int32);
return u32.raw_value;
}
uint64_t htobe64(uint64_t int64)
{
BigEndian<uint64_t> u64(int64);
return u64.raw_value;
}
uint16_t be16toh(uint16_t big16)
{
LittleEndian<uint16_t> u16(big16);
return u16.raw_value;
}
uint32_t be32toh(uint32_t big32)
{
LittleEndian<uint32_t> u32(big32);
return u32.raw_value;
}
uint64_t be64toh(uint64_t big64)
{
LittleEndian<uint64_t> u64(big64);
return u64.raw_value;
}
#endif
/* it can be used in Windows 8
#include <Winsock2.h>
uint16_t htobe16(uint16_t int16)
{
return htons(int16);
}
uint32_t htobe32(uint32_t int32)
{
return htonl(int32);
}
uint64_t htobe64(uint64_t int64)
{
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
//return htonll(int64);
return 0;
}
uint16_t be16toh(uint16_t big16)
{
return ntohs(big16);
}
uint32_t be32toh(uint32_t big32)
{
return ntohl(big32);
}
uint64_t be64toh(uint64_t big64)
{
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
//return ntohll(big64);
return 0;
}
*/

119
core/util/I2PEndian.h Normal file
View file

@ -0,0 +1,119 @@
#ifndef I2PENDIAN_H__
#define I2PENDIAN_H__
#include <inttypes.h>
#include <string.h>
#if defined(__linux__) || defined(__FreeBSD_kernel__)
#include <endian.h>
#elif __FreeBSD__
#include <sys/endian.h>
#elif defined(__APPLE__) && defined(__MACH__)
#include <libkern/OSByteOrder.h>
#define htobe16(x) OSSwapHostToBigInt16(x)
#define htole16(x) OSSwapHostToLittleInt16(x)
#define be16toh(x) OSSwapBigToHostInt16(x)
#define le16toh(x) OSSwapLittleToHostInt16(x)
#define htobe32(x) OSSwapHostToBigInt32(x)
#define htole32(x) OSSwapHostToLittleInt32(x)
#define be32toh(x) OSSwapBigToHostInt32(x)
#define le32toh(x) OSSwapLittleToHostInt32(x)
#define htobe64(x) OSSwapHostToBigInt64(x)
#define htole64(x) OSSwapHostToLittleInt64(x)
#define be64toh(x) OSSwapBigToHostInt64(x)
#define le64toh(x) OSSwapLittleToHostInt64(x)
#else
#define NEEDS_LOCAL_ENDIAN
#include <cstdint>
uint16_t htobe16(uint16_t int16);
uint32_t htobe32(uint32_t int32);
uint64_t htobe64(uint64_t int64);
uint16_t be16toh(uint16_t big16);
uint32_t be32toh(uint32_t big32);
uint64_t be64toh(uint64_t big64);
// assume LittleEndine
#define htole16
#define htole32
#define htole64
#define le16toh
#define le32toh
#define le64toh
#endif
inline uint16_t buf16toh(const void *buf)
{
uint16_t b16;
memcpy(&b16, buf, sizeof(uint16_t));
return b16;
}
inline uint32_t buf32toh(const void *buf)
{
uint32_t b32;
memcpy(&b32, buf, sizeof(uint32_t));
return b32;
}
inline uint64_t buf64toh(const void *buf)
{
uint64_t b64;
memcpy(&b64, buf, sizeof(uint64_t));
return b64;
}
inline uint16_t bufbe16toh(const void *buf)
{
return be16toh(buf16toh(buf));
}
inline uint32_t bufbe32toh(const void *buf)
{
return be32toh(buf32toh(buf));
}
inline uint64_t bufbe64toh(const void *buf)
{
return be64toh(buf64toh(buf));
}
inline void htobuf16(void *buf, uint16_t b16)
{
memcpy(buf, &b16, sizeof(uint16_t));
}
inline void htobuf32(void *buf, uint32_t b32)
{
memcpy(buf, &b32, sizeof(uint32_t));
}
inline void htobuf64(void *buf, uint64_t b64)
{
memcpy(buf, &b64, sizeof(uint64_t));
}
inline void htobe16buf(void *buf, uint16_t big16)
{
htobuf16(buf, htobe16(big16));
}
inline void htobe32buf(void *buf, uint32_t big32)
{
htobuf32(buf, htobe32(big32));
}
inline void htobe64buf(void *buf, uint64_t big64)
{
htobuf64(buf, htobe64(big64));
}
#endif // I2PENDIAN_H__

242
core/util/LittleBigEndian.h Normal file
View file

@ -0,0 +1,242 @@
// LittleBigEndian.h fixed for 64-bits added union
//
#ifndef LITTLEBIGENDIAN_H
#define LITTLEBIGENDIAN_H
// Determine Little-Endian or Big-Endian
#define CURRENT_BYTE_ORDER (*(int *)"\x01\x02\x03\x04")
#define LITTLE_ENDIAN_BYTE_ORDER 0x04030201
#define BIG_ENDIAN_BYTE_ORDER 0x01020304
#define PDP_ENDIAN_BYTE_ORDER 0x02010403
#define IS_LITTLE_ENDIAN (CURRENT_BYTE_ORDER == LITTLE_ENDIAN_BYTE_ORDER)
#define IS_BIG_ENDIAN (CURRENT_BYTE_ORDER == BIG_ENDIAN_BYTE_ORDER)
#define IS_PDP_ENDIAN (CURRENT_BYTE_ORDER == PDP_ENDIAN_BYTE_ORDER)
// Forward declaration
template<typename T>
struct LittleEndian;
template<typename T>
struct BigEndian;
// Little-Endian template
#pragma pack(push,1)
template<typename T>
struct LittleEndian
{
union
{
unsigned char bytes[sizeof(T)];
T raw_value;
};
LittleEndian(T t = T())
{
operator =(t);
}
LittleEndian(const LittleEndian<T> & t)
{
raw_value = t.raw_value;
}
LittleEndian(const BigEndian<T> & t)
{
for (unsigned i = 0; i < sizeof(T); i++)
bytes[i] = t.bytes[sizeof(T)-1-i];
}
operator const T() const
{
T t = T();
for (unsigned i = 0; i < sizeof(T); i++)
t |= T(bytes[i]) << (i << 3);
return t;
}
const T operator = (const T t)
{
for (unsigned i = 0; i < sizeof(T); i++)
bytes[sizeof(T)-1 - i] = static_cast<unsigned char>(t >> (i << 3));
return t;
}
// operators
const T operator += (const T t)
{
return (*this = *this + t);
}
const T operator -= (const T t)
{
return (*this = *this - t);
}
const T operator *= (const T t)
{
return (*this = *this * t);
}
const T operator /= (const T t)
{
return (*this = *this / t);
}
const T operator %= (const T t)
{
return (*this = *this % t);
}
LittleEndian<T> operator ++ (int)
{
LittleEndian<T> tmp(*this);
operator ++ ();
return tmp;
}
LittleEndian<T> & operator ++ ()
{
for (unsigned i = 0; i < sizeof(T); i++)
{
++bytes[i];
if (bytes[i] != 0)
break;
}
return (*this);
}
LittleEndian<T> operator -- (int)
{
LittleEndian<T> tmp(*this);
operator -- ();
return tmp;
}
LittleEndian<T> & operator -- ()
{
for (unsigned i = 0; i < sizeof(T); i++)
{
--bytes[i];
if (bytes[i] != (T)(-1))
break;
}
return (*this);
}
};
#pragma pack(pop)
// Big-Endian template
#pragma pack(push,1)
template<typename T>
struct BigEndian
{
union
{
unsigned char bytes[sizeof(T)];
T raw_value;
};
BigEndian(T t = T())
{
operator =(t);
}
BigEndian(const BigEndian<T> & t)
{
raw_value = t.raw_value;
}
BigEndian(const LittleEndian<T> & t)
{
for (unsigned i = 0; i < sizeof(T); i++)
bytes[i] = t.bytes[sizeof(T)-1-i];
}
operator const T() const
{
T t = T();
for (unsigned i = 0; i < sizeof(T); i++)
t |= T(bytes[sizeof(T) - 1 - i]) << (i << 3);
return t;
}
const T operator = (const T t)
{
for (unsigned i = 0; i < sizeof(T); i++)
bytes[sizeof(T) - 1 - i] = t >> (i << 3);
return t;
}
// operators
const T operator += (const T t)
{
return (*this = *this + t);
}
const T operator -= (const T t)
{
return (*this = *this - t);
}
const T operator *= (const T t)
{
return (*this = *this * t);
}
const T operator /= (const T t)
{
return (*this = *this / t);
}
const T operator %= (const T t)
{
return (*this = *this % t);
}
BigEndian<T> operator ++ (int)
{
BigEndian<T> tmp(*this);
operator ++ ();
return tmp;
}
BigEndian<T> & operator ++ ()
{
for (unsigned i = 0; i < sizeof(T); i++)
{
++bytes[sizeof(T) - 1 - i];
if (bytes[sizeof(T) - 1 - i] != 0)
break;
}
return (*this);
}
BigEndian<T> operator -- (int)
{
BigEndian<T> tmp(*this);
operator -- ();
return tmp;
}
BigEndian<T> & operator -- ()
{
for (unsigned i = 0; i < sizeof(T); i++)
{
--bytes[sizeof(T) - 1 - i];
if (bytes[sizeof(T) - 1 - i] != (T)(-1))
break;
}
return (*this);
}
};
#pragma pack(pop)
#endif // LITTLEBIGENDIAN_H

62
core/util/Log.cpp Normal file
View file

@ -0,0 +1,62 @@
#include <boost/date_time/posix_time/posix_time.hpp>
#include "Log.h"
Log * g_Log = nullptr;
static const char * g_LogLevelStr[eNumLogLevels] =
{
"error", // eLogError
"warn", // eLogWarning
"info", // eLogInfo
"debug" // eLogDebug
};
void LogMsg::Process()
{
auto& output = (log && log->GetLogStream ()) ? *log->GetLogStream () : std::cerr;
if (log)
output << log->GetTimestamp ();
else
output << boost::posix_time::second_clock::local_time().time_of_day ();
output << "/" << g_LogLevelStr[level] << " - ";
output << s.str();
}
const std::string& Log::GetTimestamp ()
{
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__)
auto ts = std::chrono::monotonic_clock::now ();
#else
auto ts = std::chrono::steady_clock::now ();
#endif
if (ts > m_LastTimestampUpdate + std::chrono::milliseconds (500)) // 0.5 second
{
m_LastTimestampUpdate = ts;
m_Timestamp = boost::posix_time::to_simple_string (boost::posix_time::second_clock::local_time().time_of_day ());
}
return m_Timestamp;
}
void Log::Flush ()
{
if (m_LogStream)
m_LogStream->flush();
}
void Log::SetLogFile (const std::string& fullFilePath)
{
auto logFile = new std::ofstream (fullFilePath, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
if (logFile->is_open ())
{
SetLogStream (logFile);
LogPrint("Logging to file ", fullFilePath, " enabled.");
}
else
delete logFile;
}
void Log::SetLogStream (std::ostream * logStream)
{
if (m_LogStream) delete m_LogStream;
m_LogStream = logStream;
}

129
core/util/Log.h Normal file
View file

@ -0,0 +1,129 @@
#ifndef LOG_H__
#define LOG_H__
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <functional>
#include <chrono>
#include "Queue.h"
enum LogLevel
{
eLogError = 0,
eLogWarning,
eLogInfo,
eLogDebug,
eNumLogLevels
};
class Log;
struct LogMsg
{
std::stringstream s;
Log * log;
LogLevel level;
LogMsg (Log * l = nullptr, LogLevel lv = eLogInfo): log (l), level (lv) {};
void Process();
};
class Log: public i2p::util::MsgQueue<LogMsg>
{
public:
Log (): m_LogStream (nullptr) { SetOnEmpty (std::bind (&Log::Flush, this)); };
~Log () { delete m_LogStream; };
void SetLogFile (const std::string& fullFilePath);
void SetLogStream (std::ostream * logStream);
std::ostream * GetLogStream () const { return m_LogStream; };
const std::string& GetTimestamp ();
private:
void Flush ();
private:
std::ostream * m_LogStream;
std::string m_Timestamp;
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__)
std::chrono::monotonic_clock::time_point m_LastTimestampUpdate;
#else
std::chrono::steady_clock::time_point m_LastTimestampUpdate;
#endif
};
extern Log * g_Log;
inline void StartLog (const std::string& fullFilePath)
{
if (!g_Log)
{
auto log = new Log ();
if (fullFilePath.length () > 0)
log->SetLogFile (fullFilePath);
g_Log = log;
}
}
inline void StartLog (std::ostream * s)
{
if (!g_Log)
{
auto log = new Log ();
if (s)
log->SetLogStream (s);
g_Log = log;
}
}
inline void StopLog ()
{
if (g_Log)
{
auto log = g_Log;
g_Log = nullptr;
log->Stop ();
delete log;
}
}
template<typename TValue>
void LogPrint (std::stringstream& s, TValue arg)
{
s << arg;
}
template<typename TValue, typename... TArgs>
void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
{
LogPrint (s, arg);
LogPrint (s, args...);
}
template<typename... TArgs>
void LogPrint (LogLevel level, TArgs... args)
{
LogMsg * msg = new LogMsg (g_Log, level);
LogPrint (msg->s, args...);
msg->s << std::endl;
if (g_Log)
g_Log->Put (msg);
else
{
msg->Process ();
delete msg;
}
}
template<typename... TArgs>
void LogPrint (TArgs... args)
{
LogPrint (eLogInfo, args...);
}
#endif

169
core/util/Queue.h Normal file
View file

@ -0,0 +1,169 @@
#ifndef QUEUE_H__
#define QUEUE_H__
#include <queue>
#include <vector>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <functional>
namespace i2p
{
namespace util
{
template<typename Element>
class Queue
{
public:
void Put (Element e)
{
std::unique_lock<std::mutex> l(m_QueueMutex);
m_Queue.push (e);
m_NonEmpty.notify_one ();
}
void Put (const std::vector<Element>& vec)
{
if (!vec.empty ())
{
std::unique_lock<std::mutex> l(m_QueueMutex);
for (auto it: vec)
m_Queue.push (it);
m_NonEmpty.notify_one ();
}
}
Element GetNext ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
auto el = GetNonThreadSafe ();
if (!el)
{
m_NonEmpty.wait (l);
el = GetNonThreadSafe ();
}
return el;
}
Element GetNextWithTimeout (int usec)
{
std::unique_lock<std::mutex> l(m_QueueMutex);
auto el = GetNonThreadSafe ();
if (!el)
{
m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec));
el = GetNonThreadSafe ();
}
return el;
}
void Wait ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
m_NonEmpty.wait (l);
}
bool Wait (int sec, int usec)
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return m_NonEmpty.wait_for (l, std::chrono::seconds (sec) + std::chrono::milliseconds (usec)) != std::cv_status::timeout;
}
bool IsEmpty ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return m_Queue.empty ();
}
int GetSize ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return m_Queue.size ();
}
void WakeUp () { m_NonEmpty.notify_all (); };
Element Get ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return GetNonThreadSafe ();
}
Element Peek ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return GetNonThreadSafe (true);
}
private:
Element GetNonThreadSafe (bool peek = false)
{
if (!m_Queue.empty ())
{
auto el = m_Queue.front ();
if (!peek)
m_Queue.pop ();
return el;
}
return nullptr;
}
private:
std::queue<Element> m_Queue;
std::mutex m_QueueMutex;
std::condition_variable m_NonEmpty;
};
template<class Msg>
class MsgQueue: public Queue<Msg *>
{
public:
typedef std::function<void()> OnEmpty;
MsgQueue (): m_IsRunning (true), m_Thread (std::bind (&MsgQueue<Msg>::Run, this)) {};
~MsgQueue () { Stop (); };
void Stop()
{
if (m_IsRunning)
{
m_IsRunning = false;
Queue<Msg *>::WakeUp ();
m_Thread.join();
}
}
void SetOnEmpty (OnEmpty const & e) { m_OnEmpty = e; };
private:
void Run ()
{
while (m_IsRunning)
{
while (auto msg = Queue<Msg *>::Get ())
{
msg->Process ();
delete msg;
}
if (m_OnEmpty != nullptr)
m_OnEmpty ();
if (m_IsRunning)
Queue<Msg *>::Wait ();
}
}
private:
volatile bool m_IsRunning;
OnEmpty m_OnEmpty;
std::thread m_Thread;
};
}
}
#endif

32
core/util/Timestamp.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef TIMESTAMP_H__
#define TIMESTAMP_H__
#include <inttypes.h>
#include <chrono>
namespace i2p
{
namespace util
{
inline uint64_t GetMillisecondsSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count ();
}
inline uint32_t GetHoursSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::hours>(
std::chrono::system_clock::now().time_since_epoch()).count ();
}
inline uint64_t GetSecondsSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch()).count ();
}
}
}
#endif

239
core/util/base64.cpp Normal file
View file

@ -0,0 +1,239 @@
#include <stdlib.h>
#include "base64.h"
namespace i2p
{
namespace util
{
static void iT64Build(void);
/*
*
* BASE64 Substitution Table
* -------------------------
*
* Direct Substitution Table
*/
static char T64[64] = {
'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', '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', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '-', '~'
};
const char * GetBase64SubstitutionTable ()
{
return T64;
}
/*
* Reverse Substitution Table (built in run time)
*/
static char iT64[256];
static int isFirstTime = 1;
/*
* Padding
*/
static char P64 = '=';
size_t ByteStreamToBase64(const uint8_t* InBuffer, size_t InCount, char* OutBuffer, size_t len)
{
unsigned char * ps;
unsigned char * pd;
unsigned char acc_1;
unsigned char acc_2;
int i;
int n;
int m;
size_t outCount;
ps = (unsigned char *)InBuffer;
n = InCount/3;
m = InCount%3;
if (!m)
outCount = 4*n;
else
outCount = 4*(n+1);
if (outCount > len) return 0;
pd = (unsigned char *)OutBuffer;
for ( i = 0; i<n; i++ ){
acc_1 = *ps++;
acc_2 = (acc_1<<4)&0x30;
acc_1 >>= 2; /* base64 digit #1 */
*pd++ = T64[acc_1];
acc_1 = *ps++;
acc_2 |= acc_1 >> 4; /* base64 digit #2 */
*pd++ = T64[acc_2];
acc_1 &= 0x0f;
acc_1 <<=2;
acc_2 = *ps++;
acc_1 |= acc_2>>6; /* base64 digit #3 */
*pd++ = T64[acc_1];
acc_2 &= 0x3f; /* base64 digit #4 */
*pd++ = T64[acc_2];
}
if ( m == 1 ){
acc_1 = *ps++;
acc_2 = (acc_1<<4)&0x3f; /* base64 digit #2 */
acc_1 >>= 2; /* base64 digit #1 */
*pd++ = T64[acc_1];
*pd++ = T64[acc_2];
*pd++ = P64;
*pd++ = P64;
}
else if ( m == 2 ){
acc_1 = *ps++;
acc_2 = (acc_1<<4)&0x3f;
acc_1 >>= 2; /* base64 digit #1 */
*pd++ = T64[acc_1];
acc_1 = *ps++;
acc_2 |= acc_1 >> 4; /* base64 digit #2 */
*pd++ = T64[acc_2];
acc_1 &= 0x0f;
acc_1 <<=2; /* base64 digit #3 */
*pd++ = T64[acc_1];
*pd++ = P64;
}
return outCount;
}
size_t Base64ToByteStream(const char * InBuffer, size_t InCount, uint8_t* OutBuffer, size_t len)
{
unsigned char * ps;
unsigned char * pd;
unsigned char acc_1;
unsigned char acc_2;
int i;
int n;
int m;
size_t outCount;
if (isFirstTime) iT64Build();
n = InCount/4;
m = InCount%4;
if(InCount && !m)
outCount = 3*n;
else {
outCount = 0;
return 0;
}
ps = (unsigned char *)(InBuffer + InCount - 1);
while ( *ps-- == P64 ) outCount--;
ps = (unsigned char *)InBuffer;
if (outCount > len) return 0;
pd = OutBuffer;
auto endOfOutBuffer = OutBuffer + outCount;
for ( i = 0; i < n; i++ ){
acc_1 = iT64[*ps++];
acc_2 = iT64[*ps++];
acc_1 <<= 2;
acc_1 |= acc_2>>4;
*pd++ = acc_1;
if (pd >= endOfOutBuffer) break;
acc_2 <<= 4;
acc_1 = iT64[*ps++];
acc_2 |= acc_1 >> 2;
*pd++ = acc_2;
if (pd >= endOfOutBuffer) break;
acc_2 = iT64[*ps++];
acc_2 |= acc_1 << 6;
*pd++ = acc_2;
}
return outCount;
}
/*
*
* iT64
* ----
* Reverse table builder. P64 character is replaced with 0
*
*
*/
static void iT64Build()
{
int i;
isFirstTime = 0;
for ( i=0; i<256; i++ ) iT64[i] = -1;
for ( i=0; i<64; i++ ) iT64[(int)T64[i]] = i;
iT64[(int)P64] = 0;
}
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen)
{
int tmp = 0, bits = 0;
size_t ret = 0;
for (size_t i = 0; i < len; i++)
{
char ch = inBuf[i];
if (ch >= '2' && ch <= '7') // digit
ch = (ch - '2') + 26; // 26 means a-z
else if (ch >= 'a' && ch <= 'z')
ch = ch - 'a'; // a = 0
else
return 0; // unexpected character
tmp |= ch;
bits += 5;
if (bits >= 8)
{
if (ret >= outLen) return ret;
outBuf[ret] = tmp >> (bits - 8);
bits -= 8;
ret++;
}
tmp <<= 5;
}
return ret;
}
size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen)
{
if(!len)
return 0; // No data given
size_t ret = 0, pos = 1;
int bits = 8, tmp = inBuf[0];
while (ret < outLen && (bits > 0 || pos < len))
{
if (bits < 5)
{
if (pos < len)
{
tmp <<= 8;
tmp |= inBuf[pos] & 0xFF;
pos++;
bits += 8;
}
else // last byte
{
tmp <<= (5 - bits);
bits = 5;
}
}
bits -= 5;
int ind = (tmp >> bits) & 0x1F;
outBuf[ret] = (ind < 26) ? (ind + 'a') : ((ind - 26) + '2');
ret++;
}
return ret;
}
}
}

63
core/util/base64.h Normal file
View file

@ -0,0 +1,63 @@
#ifndef BASE64_H
#define BASE64_H
#include <inttypes.h>
#include <string.h>
namespace i2p
{
namespace util
{
/*
* Base64 encodes an array of bytes.
* @return the number of characters written to the output buffer
* @param InBuffer array of input bytes to be encoded
* @param InCount length of the input array
* @param OutBuffer array to store output characters
* @param len length of the output buffer
* @note zero is returned when the output buffer is too small
*/
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
/**
* Decodes base 64 encoded data to an array of bytes.
* @return the number of bytes written to the output buffer
* @param InBuffer array of input characters to be decoded
* @param InCount length of the input array
* @param OutBuffer array to store output bytes
* @param len length of the output buffer
* @todo Do not return a negative value on failure, size_t could be unsigned.
* @note zero is returned when the output buffer is too small
*/
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
const char * GetBase64SubstitutionTable ();
/**
* Decodes base 32 encoded data to an array of bytes.
* @return the number of bytes written to the output buffer
* @param inBuf array of input characters to be decoded
* @param len length of the input buffer
* @param outBuf array to store output bytes
* @param outLen length of the output array
* @note zero is returned when the output buffer is too small
*/
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
/**
* Base 32 encodes an array of bytes.
* @return the number of bytes written to the output buffer
* @param inBuf array of input bytes to be encoded
* @param len length of the input buffer
* @param outBuf array to store output characters
* @param outLen length of the output array
* @note zero is returned when the output buffer is too small
*/
size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen);
}
}
#endif

676
core/util/util.cpp Normal file
View file

@ -0,0 +1,676 @@
#include <cstdlib>
#include <string>
#include <algorithm>
#include <cctype>
#include <functional>
#include <fstream>
#include <set>
#include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/algorithm/string.hpp>
#include "util.h"
#include "Log.h"
#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
#include <sys/types.h>
#include <ifaddrs.h>
#elif defined(WIN32)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <shlobj.h>
#pragma comment(lib, "IPHLPAPI.lib")
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
int inet_pton(int af, const char *src, void *dst)
{ /* This function was written by Petar Korponai?. See
http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found */
struct sockaddr_storage ss;
int size = sizeof (ss);
char src_copy[INET6_ADDRSTRLEN + 1];
ZeroMemory (&ss, sizeof (ss));
strncpy_s (src_copy, src, INET6_ADDRSTRLEN + 1);
src_copy[INET6_ADDRSTRLEN] = 0;
if (WSAStringToAddress (src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0)
{
switch (af)
{
case AF_INET:
*(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
return 1;
case AF_INET6:
*(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
return 1;
}
}
return 0;
}
#endif
namespace i2p {
namespace util {
namespace config {
std::map<std::string, std::string> mapArgs;
std::map<std::string, std::vector<std::string> > mapMultiArgs;
void OptionParser(int argc, const char* const argv[])
{
mapArgs.clear();
mapMultiArgs.clear();
for(int i = 1; i < argc; ++i) {
std::string strKey (argv[i]);
std::string strValue;
size_t has_data = strKey.find('=');
if(has_data != std::string::npos) {
strValue = strKey.substr(has_data+1);
strKey = strKey.substr(0, has_data);
}
#ifdef WIN32
boost::to_lower(strKey);
if(boost::algorithm::starts_with(strKey, "/"))
strKey = "-" + strKey.substr(1);
#endif
if(strKey[0] != '-')
break;
mapArgs[strKey] = strValue;
mapMultiArgs[strKey].push_back(strValue);
}
for(auto& entry : mapArgs) {
std::string name = entry.first;
// interpret --foo as -foo (as long as both are not set)
if (name.find("--") == 0) {
std::string singleDash(name.begin()+1, name.end());
if (mapArgs.count(singleDash) == 0)
mapArgs[singleDash] = entry.second;
name = singleDash;
}
}
}
const char* GetCharArg(const std::string& strArg, const std::string& nDefault)
{
if(mapArgs.count(strArg))
return mapArgs[strArg].c_str();
return nDefault.c_str();
}
std::string GetArg(const std::string& strArg, const std::string& strDefault)
{
if(mapArgs.count(strArg))
return mapArgs[strArg];
return strDefault;
}
int GetArg(const std::string& strArg, int nDefault)
{
if(mapArgs.count(strArg))
return stoi(mapArgs[strArg]);
return nDefault;
}
}
namespace filesystem
{
std::string appName("i2pd");
void SetAppName(const std::string& name)
{
appName = name;
}
std::string GetAppName()
{
return appName;
}
const boost::filesystem::path& GetDataDir()
{
static boost::filesystem::path path;
// TODO: datadir parameter is useless because GetDataDir is called before OptionParser
// and mapArgs is not initialized yet
/*if (i2p::util::config::mapArgs.count("-datadir"))
path = boost::filesystem::system_complete(i2p::util::config::mapArgs["-datadir"]);
else */
path = GetDefaultDataDir();
if(!boost::filesystem::exists(path)) {
// Create data directory
if(!boost::filesystem::create_directory(path)) {
LogPrint("Failed to create data directory!");
path = "";
return path;
}
}
if(!boost::filesystem::is_directory(path))
path = GetDefaultDataDir();
return path;
}
std::string GetFullPath(const std::string& filename)
{
std::string fullPath = GetDataDir().string();
#ifndef _WIN32
fullPath.append("/");
#else
fullPath.append("\\");
#endif
fullPath.append(filename);
return fullPath;
}
boost::filesystem::path GetConfigFile()
{
boost::filesystem::path pathConfigFile(i2p::util::config::GetArg("-conf", "i2p.conf"));
if(!pathConfigFile.is_complete())
pathConfigFile = GetDataDir() / pathConfigFile;
return pathConfigFile;
}
boost::filesystem::path GetTunnelsConfigFile()
{
boost::filesystem::path pathTunnelsConfigFile(i2p::util::config::GetArg("-tunnelscfg", "tunnels.cfg"));
if(!pathTunnelsConfigFile.is_complete())
pathTunnelsConfigFile = GetDataDir() / pathTunnelsConfigFile;
return pathTunnelsConfigFile;
}
boost::filesystem::path GetDefaultDataDir()
{
// Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd
// Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd
// Mac: ~/Library/Application Support/i2pd
// Unix: ~/.i2pd or /var/lib/i2pd is system=1
#ifdef WIN32
// Windows
char localAppData[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData);
return boost::filesystem::path(std::string(localAppData) + "\\" + appName);
#else
if(i2p::util::config::GetArg("-service", 0)) // use system folder
return boost::filesystem::path(std::string ("/var/lib/") + appName);
boost::filesystem::path pathRet;
char* pszHome = getenv("HOME");
if(pszHome == NULL || strlen(pszHome) == 0)
pathRet = boost::filesystem::path("/");
else
pathRet = boost::filesystem::path(pszHome);
#ifdef MAC_OSX
// Mac
pathRet /= "Library/Application Support";
boost::filesystem::create_directory(pathRet);
return pathRet / appName;
#else
// Unix
return pathRet / (std::string (".") + appName);
#endif
#endif
}
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet,
std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet)
{
boost::filesystem::ifstream streamConfig(GetConfigFile());
if(!streamConfig.good())
return; // No i2pd.conf file is OK
std::set<std::string> setOptions;
setOptions.insert("*");
for(boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end;
it != end; ++it) {
// Don't overwrite existing settings so command line settings override i2pd.conf
std::string strKey = std::string("-") + it->string_key;
if(mapSettingsRet.count(strKey) == 0) {
mapSettingsRet[strKey] = it->value[0];
}
mapMultiSettingsRet[strKey].push_back(it->value[0]);
}
}
boost::filesystem::path GetCertificatesDir()
{
return GetDataDir () / "certificates";
}
}
namespace http
{
std::string httpRequest(const std::string& address)
{
try {
i2p::util::http::url u(address);
boost::asio::ip::tcp::iostream site;
// please don't uncomment following line because it's not compatible with boost 1.46
// 1.46 is default boost for Ubuntu 12.04 LTS
//site.expires_from_now (boost::posix_time::seconds(30));
if(u.port_ == 80)
site.connect(u.host_, "http");
else {
std::stringstream ss; ss << u.port_;
site.connect(u.host_, ss.str());
}
if(site) {
// User-Agent is needed to get the server list routerInfo files.
site << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_
<< "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n"
<< "Connection: close\r\n\r\n";
// read response and extract content
return GetHttpContent(site);
} else {
LogPrint("Can't connect to ", address);
return "";
}
} catch(const std::exception& ex) {
LogPrint("Failed to download ", address, " : ", ex.what());
return "";
}
}
std::string GetHttpContent (std::istream& response)
{
std::string version, statusMessage;
response >> version; // HTTP version
int status;
response >> status; // status
std::getline (response, statusMessage);
if(status == 200) { // OK
bool isChunked = false;
std::string header;
while(!response.eof() && header != "\r") {
std::getline(response, header);
auto colon = header.find (':');
if(colon != std::string::npos) {
std::string field = header.substr (0, colon);
if(field == i2p::util::http::TRANSFER_ENCODING)
isChunked = (header.find("chunked", colon + 1) != std::string::npos);
}
}
std::stringstream ss;
if(isChunked)
MergeChunkedResponse(response, ss);
else
ss << response.rdbuf();
return ss.str();
} else {
LogPrint("HTTP response ", status);
return "";
}
}
void MergeChunkedResponse(std::istream& response, std::ostream& merged)
{
while(!response.eof()) {
std::string hexLen;
int len;
std::getline(response, hexLen);
std::istringstream iss(hexLen);
iss >> std::hex >> len;
if(!len)
break;
char* buf = new char[len];
response.read(buf, len);
merged.write(buf, len);
delete[] buf;
std::getline(response, hexLen); // read \r\n after chunk
}
}
int httpRequestViaI2pProxy(const std::string& address, std::string &content)
{
content = "";
try {
boost::asio::ip::tcp::iostream site;
// please don't uncomment following line because it's not compatible with boost 1.46
// 1.46 is default boost for Ubuntu 12.04 LTS
//site.expires_from_now (boost::posix_time::seconds(30));
{
std::stringstream ss; ss << i2p::util::config::GetArg("-httpproxyport", 4446);
site.connect("127.0.0.1", ss.str());
}
if(site) {
i2p::util::http::url u(address);
std::stringstream ss;
ss << "GET " << address << " HTTP/1.0" << std::endl;
ss << "Host: " << u.host_ << std::endl;
ss << "Accept: */*" << std::endl;
ss << "User - Agent: Wget / 1.11.4" << std::endl;
ss << "Connection: close" << std::endl;
ss << std::endl;
site << ss.str();
// read response
std::string version, statusMessage;
site >> version; // HTTP version
int status;
site >> status; // status
std::getline(site, statusMessage);
if(status == 200) { // OK
std::string header;
while(std::getline(site, header) && header != "\r"){}
std::stringstream ss;
ss << site.rdbuf();
content = ss.str();
return status;
} else {
LogPrint("HTTP response ", status);
return status;
}
} else {
LogPrint("Can't connect to proxy");
return 408;
}
} catch (std::exception& ex) {
LogPrint("Failed to download ", address, " : ", ex.what());
return 408;
}
}
url::url(const std::string& url_s)
{
portstr_ = "80";
port_ = 80;
user_ = "";
pass_ = "";
parse(url_s);
}
void url::parse(const std::string& url_s)
{
const std::string prot_end("://");
std::string::const_iterator prot_i = search(
url_s.begin(), url_s.end(), prot_end.begin(), prot_end.end()
);
protocol_.reserve(distance(url_s.begin(), prot_i));
// Make portocol lowercase
transform(
url_s.begin(), prot_i, back_inserter(protocol_), std::ptr_fun<int, int>(std::tolower)
);
if(prot_i == url_s.end())
return;
advance(prot_i, prot_end.length());
std::string::const_iterator path_i = find(prot_i, url_s.end(), '/');
host_.reserve(distance(prot_i, path_i));
// Make host lowerase
transform(prot_i, path_i, back_inserter(host_), std::ptr_fun<int, int>(std::tolower));
// parse user/password
auto user_pass_i = find(host_.begin(), host_.end(), '@');
if(user_pass_i != host_.end()) {
std::string user_pass = std::string(host_.begin(), user_pass_i);
auto pass_i = find(user_pass.begin(), user_pass.end(), ':');
if (pass_i != user_pass.end()) {
user_ = std::string(user_pass.begin(), pass_i);
pass_ = std::string(pass_i + 1, user_pass.end());
} else
user_ = user_pass;
host_.assign(user_pass_i + 1, host_.end());
}
// parse port
auto port_i = find(host_.begin(), host_.end(), ':');
if(port_i != host_.end()) {
portstr_ = std::string(port_i + 1, host_.end());
host_.assign(host_.begin(), port_i);
try {
port_ = boost::lexical_cast<decltype(port_)>(portstr_);
} catch(const std::exception& e) {
port_ = 80;
}
}
std::string::const_iterator query_i = find(path_i, url_s.end(), '?');
path_.assign(path_i, query_i);
if( query_i != url_s.end() )
++query_i;
query_.assign(query_i, url_s.end());
}
std::string urlDecode(const std::string& data)
{
std::string res(data);
for(size_t pos = res.find('%'); pos != std::string::npos; pos = res.find('%', pos + 1)) {
const char c = strtol(res.substr(pos + 1, 2).c_str(), NULL, 16);
res.replace(pos, 3, 1, c);
}
return res;
}
}
namespace net {
#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
int GetMTUUnix(const boost::asio::ip::address& localAddress, int fallback)
{
ifaddrs* ifaddr, *ifa = nullptr;
if(getifaddrs(&ifaddr) == -1) {
LogPrint(eLogError, "Can't excute getifaddrs");
return fallback;
}
int family = 0;
// look for interface matching local address
for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
if(!ifa->ifa_addr)
continue;
family = ifa->ifa_addr->sa_family;
if(family == AF_INET && localAddress.is_v4()) {
sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr;
if(!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4))
break; // address matches
} else if(family == AF_INET6 && localAddress.is_v6()) {
sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr;
if(!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16))
break; // address matches
}
}
int mtu = fallback;
if(ifa && family) { // interface found?
int fd = socket(family, SOCK_DGRAM, 0);
if(fd > 0) {
ifreq ifr;
strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); // set interface for query
if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0)
mtu = ifr.ifr_mtu; // MTU
else
LogPrint (eLogError, "Failed to run ioctl");
close(fd);
} else
LogPrint(eLogError, "Failed to create datagram socket");
} else {
LogPrint(
eLogWarning, "Interface for local address",
localAddress.to_string(), " not found"
);
}
freeifaddrs(ifaddr);
return mtu;
}
#elif defined(WIN32)
int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback)
{
ULONG outBufLen = 0;
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
if(GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
== ERROR_BUFFER_OVERFLOW) {
FREE(pAddresses);
pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen);
}
DWORD dwRetVal = GetAdaptersAddresses(
AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
);
if(dwRetVal != NO_ERROR) {
LogPrint(
eLogError, "GetMTU() has failed: enclosed GetAdaptersAddresses() call has failed"
);
FREE(pAddresses);
return fallback;
}
pCurrAddresses = pAddresses;
while(pCurrAddresses) {
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress;
if(pUnicast == nullptr) {
LogPrint(
eLogError, "GetMTU() has failed: not a unicast ipv4 address, this is not supported"
);
}
for(int i = 0; pUnicast != nullptr; ++i) {
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr) {
result = pAddresses->Mtu;
FREE(pAddresses);
return result;
}
pUnicast = pUnicast->Next;
}
pCurrAddresses = pCurrAddresses->Next;
}
LogPrint(eLogError, "GetMTU() error: no usable unicast ipv4 addresses found");
FREE(pAddresses);
return fallback;
}
int GetMTUWindowsIpv6(sockaddr_in6 inputAddress, int fallback)
{
ULONG outBufLen = 0;
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
== ERROR_BUFFER_OVERFLOW) {
FREE(pAddresses);
pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen);
}
DWORD dwRetVal = GetAdaptersAddresses(
AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
);
if(dwRetVal != NO_ERROR) {
LogPrint(
eLogError,
"GetMTU() has failed: enclosed GetAdaptersAddresses() call has failed"
);
FREE(pAddresses);
return fallback;
}
bool found_address = false;
pCurrAddresses = pAddresses;
while(pCurrAddresses) {
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress;
if(pUnicast == nullptr) {
LogPrint(
eLogError,
"GetMTU() has failed: not a unicast ipv6 address, this is not supported"
);
}
for(int i = 0; pUnicast != nullptr; ++i) {
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
for (int j = 0; j != 8; ++j) {
if (localInterfaceAddress->sin6_addr.u.Word[j] != inputAddress.sin6_addr.u.Word[j]) {
break;
} else {
found_address = true;
}
} if (found_address) {
result = pAddresses->Mtu;
FREE(pAddresses);
pAddresses = nullptr;
return result;
}
pUnicast = pUnicast->Next;
}
pCurrAddresses = pCurrAddresses->Next;
}
LogPrint(eLogError, "GetMTU() error: no usable unicast ipv6 addresses found");
FREE(pAddresses);
return fallback;
}
int GetMTUWindows(const boost::asio::ip::address& localAddress, int fallback)
{
#ifdef UNICODE
string localAddress_temporary = localAddress.to_string();
wstring localAddressUniversal(localAddress_temporary.begin(), localAddress_temporary.end());
#else
std::string localAddressUniversal = localAddress.to_string();
#endif
if(localAddress.is_v4()) {
sockaddr_in inputAddress;
inet_pton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
return GetMTUWindowsIpv4(inputAddress, fallback);
} else if(localAddress.is_v6()) {
sockaddr_in6 inputAddress;
inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
return GetMTUWindowsIpv6(inputAddress, fallback);
} else {
LogPrint(eLogError, "GetMTU() has failed: address family is not supported");
return fallback;
}
}
#endif // WIN32
int GetMTU(const boost::asio::ip::address& localAddress)
{
const int fallback = 576; // fallback MTU
#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
return GetMTUUnix(localAddress, fallback);
#elif defined(WIN32)
return GetMTUWindows(localAddress, fallback);
#endif
return fallback;
}
}
} // util
} // i2p

162
core/util/util.h Normal file
View file

@ -0,0 +1,162 @@
#ifndef UTIL_H
#define UTIL_H
#include <map>
#include <string>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#define PAIRTYPE(t1, t2) std::pair<t1, t2>
namespace i2p
{
namespace util
{
namespace config
{
extern std::map<std::string, std::string> mapArgs;
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
/**
* Parses command line arguments, i.e. stores them in config::mapArgs.
*/
void OptionParser(int argc, const char* const argv[]);
/**
* @return a command line argument from config::mapArgs as an int
* @param nDefault the default value to be returned
*/
int GetArg(const std::string& strArg, int nDefault);
/**
* @return a command line argument from config::mapArgs as a std::string
* @param strDefault the default value to be returned
*/
std::string GetArg(const std::string& strArg, const std::string& strDefault);
/**
* @return a command line argument from config::mapArgs as a C-style string
* @param nDefault the default value to be returned
*/
const char* GetCharArg(const std::string& strArg, const std::string& nDefault);
}
namespace filesystem
{
/**
* Change the application name.
*/
void SetAppName(const std::string& name);
/**
* @return the application name.
*/
std::string GetAppName();
/**
* @return the path of the i2pd directory
*/
const boost::filesystem::path& GetDataDir();
/**
* @return the full path of a file within the i2pd directory
*/
std::string GetFullPath(const std::string& filename);
/**
* @return the path of the configuration file
*/
boost::filesystem::path GetConfigFile();
/**
* @return the path of the tunnels configuration file
*/
boost::filesystem::path GetTunnelsConfigFile();
/**
* @return the default directory for i2pd data
*/
boost::filesystem::path GetDefaultDataDir();
/**
* Read a configuration file and store its contents in the given maps.
*/
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet,
std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
/**
* @return the path of the certificates directory
*/
boost::filesystem::path GetCertificatesDir();
}
namespace http
{
const char ETAG[] = "ETag";
const char IF_NONE_MATCH[] = "If-None-Match";
const char IF_MODIFIED_SINCE[] = "If-Modified-Since";
const char LAST_MODIFIED[] = "Last-Modified";
const char TRANSFER_ENCODING[] = "Transfer-Encoding";
/**
* Perform an HTTP request.
* @return the result of the request, or an empty string if it fails
*/
std::string httpRequest(const std::string& address);
/**
* @return the content of the given HTTP stream without headers
*/
std::string GetHttpContent(std::istream& response);
/**
* Merge chunks of a HTTP response into the gien std:ostream object.
*/
void MergeChunkedResponse(std::istream& response, std::ostream& merged);
/**
* Send an HTTP request through the i2p proxy.
* @return the HTTP status code
*/
int httpRequestViaI2pProxy(const std::string& address, std::string &content);
/**
* @return the decoded url
*/
std::string urlDecode(const std::string& data);
/**
* Provides functionality for parsing URLs.
*/
struct url {
/**
* Parse a url given as a string.
*/
url(const std::string& url_s);
private:
void parse(const std::string& url_s);
public:
std::string protocol_, host_, path_, query_;
std::string portstr_;
unsigned int port_;
std::string user_;
std::string pass_;
};
}
namespace net
{
/**
* @return the maximum transmission unit, or 576 on failure
*/
int GetMTU(const boost::asio::ip::address& localAddress);
}
}
}
#endif