update dis shit mang
This commit is contained in:
parent
cc089b3401
commit
d31ca5b6a7
@ -1,2 +1,4 @@
|
||||
*.o
|
||||
nntpchan
|
||||
nntpd
|
||||
nntpchan-tool
|
||||
.gdb_history
|
@ -1,5 +1,7 @@
|
||||
|
||||
EXE = nntpchan
|
||||
EXE = nntpd
|
||||
|
||||
TOOL = nntpchan-tool
|
||||
|
||||
CXX = clang++
|
||||
|
||||
@ -9,21 +11,24 @@ SOURCES := $(wildcard $(SRC_PATH)/*.cpp)
|
||||
HEADERS := $(wildcard $(SRC_PATH)/*.hpp)
|
||||
OBJECTS := $(SOURCES:.cpp=.o)
|
||||
|
||||
PKGS := libuv
|
||||
PKGS := libuv libsodium
|
||||
|
||||
LD_FLAGS := $(shell pkg-config --libs $(PKGS))
|
||||
INC_FLAGS := -I $(SRC_PATH) $(shell pkg-config --cflags $(PKGS))
|
||||
CXXFLAGS := -std=c++14 -Wall -Wextra $(INC_FLAGS)
|
||||
CXXFLAGS := -std=c++14 -Wall -Wextra $(INC_FLAGS) -g
|
||||
|
||||
|
||||
|
||||
all: $(EXE)
|
||||
all: $(EXE) $(TOOL)
|
||||
|
||||
$(EXE): $(OBJECTS)
|
||||
$(CXX) -o $(EXE) $(LD_FLAGS) $(OBJECTS)
|
||||
$(EXE): $(OBJECTS)
|
||||
$(CXX) -o $(EXE) $(LD_FLAGS) $(OBJECTS) $(CXXFLAGS) nntpchan.cpp
|
||||
|
||||
$(TOOL): $(OBJECTS)
|
||||
$(CXX) -o $(TOOL) $(LD_FLAGS) $(OBJECTS) $(CXXFLAGS) tool.cpp
|
||||
|
||||
%.o: src/%.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(EXE)
|
||||
rm -f $(OBJECTS) $(EXE) $(TOOL)
|
||||
|
234
contrib/frontends/cpp/nntpchan-daemon/src/base64.cpp
Normal file
234
contrib/frontends/cpp/nntpchan-daemon/src/base64.cpp
Normal file
@ -0,0 +1,234 @@
|
||||
#include "base64.hpp"
|
||||
|
||||
|
||||
// taken from i2pd
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
static void iT64Build(void);
|
||||
|
||||
/*
|
||||
*
|
||||
* BASE64 Substitution Table
|
||||
* -------------------------
|
||||
*
|
||||
* Direct Substitution Table
|
||||
*/
|
||||
|
||||
static const 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', '+', '/'
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Reverse Substitution Table (built in run time)
|
||||
*/
|
||||
|
||||
static char iT64[256];
|
||||
static int isFirstTime = 1;
|
||||
|
||||
/*
|
||||
* Padding
|
||||
*/
|
||||
|
||||
static char P64 = '=';
|
||||
|
||||
/*
|
||||
*
|
||||
* ByteStreamToBase64
|
||||
* ------------------
|
||||
*
|
||||
* Converts binary encoded data to BASE64 format.
|
||||
*
|
||||
*/
|
||||
static size_t /* Number of bytes in the encoded buffer */
|
||||
ByteStreamToBase64 (
|
||||
const uint8_t * InBuffer, /* Input buffer, binary data */
|
||||
size_t InCount, /* Number of bytes in the input buffer */
|
||||
char * OutBuffer, /* output buffer */
|
||||
size_t len /* length of output buffer */
|
||||
)
|
||||
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Base64ToByteStream
|
||||
* ------------------
|
||||
*
|
||||
* Converts BASE64 encoded data to binary format. If input buffer is
|
||||
* not properly padded, buffer of negative length is returned
|
||||
*
|
||||
*/
|
||||
static
|
||||
ssize_t /* Number of output bytes */
|
||||
Base64ToByteStream (
|
||||
const char * InBuffer, /* BASE64 encoded buffer */
|
||||
size_t InCount, /* Number of input bytes */
|
||||
uint8_t * OutBuffer, /* output buffer length */
|
||||
size_t len /* length of output buffer */
|
||||
)
|
||||
{
|
||||
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 -1;
|
||||
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;
|
||||
}
|
||||
|
||||
static size_t Base64EncodingBufferSize (const size_t input_size)
|
||||
{
|
||||
auto d = div (input_size, 3);
|
||||
if (d.rem) d.quot++;
|
||||
return 4*d.quot;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
std::string B64Encode(const uint8_t * data, const std::size_t l)
|
||||
{
|
||||
std::string out;
|
||||
out.reserve(i2p::data::Base64EncodingBufferSize(l));
|
||||
i2p::data::ByteStreamToBase64(data, l, &out[0], out.capacity());
|
||||
return out;
|
||||
}
|
||||
|
||||
bool B64Decode(const std::string & data, std::vector<uint8_t> & out)
|
||||
{
|
||||
out.resize(data.size());
|
||||
if(i2p::data::Base64ToByteStream(data.c_str(), data.size(), &out[0], out.size()) == -1) return false;
|
||||
out.shrink_to_fit();
|
||||
return true;
|
||||
}
|
||||
}
|
17
contrib/frontends/cpp/nntpchan-daemon/src/base64.hpp
Normal file
17
contrib/frontends/cpp/nntpchan-daemon/src/base64.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef NNTPCHAN_BASE64_HPP
|
||||
#define NNTPCHAN_BASE64_HPP
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
/** returns base64 encoded string */
|
||||
std::string B64Encode(const uint8_t * data, const std::size_t l);
|
||||
|
||||
/** @brief returns true if decode was successful */
|
||||
bool B64Decode(const std::string & data, std::vector<uint8_t> & out);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
9
contrib/frontends/cpp/nntpchan-daemon/src/crypto.cpp
Normal file
9
contrib/frontends/cpp/nntpchan-daemon/src/crypto.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "crypto.hpp"
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
void SHA512(const uint8_t * d, const std::size_t l, SHA512Digest & h)
|
||||
{
|
||||
crypto_hash(h.data(), d, l);
|
||||
}
|
||||
}
|
15
contrib/frontends/cpp/nntpchan-daemon/src/crypto.hpp
Normal file
15
contrib/frontends/cpp/nntpchan-daemon/src/crypto.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef NNTPCHAN_CRYPTO_HPP
|
||||
#define NNTPCHAN_CRYPTO_HPP
|
||||
|
||||
#include <sodium/crypto_hash.h>
|
||||
#include <array>
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
typedef std::array<uint8_t, crypto_hash_BYTES> SHA512Digest;
|
||||
|
||||
void SHA512(const uint8_t * d, std::size_t l, SHA512Digest & h);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
41
contrib/frontends/cpp/nntpchan-daemon/src/line.cpp
Normal file
41
contrib/frontends/cpp/nntpchan-daemon/src/line.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include "line.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace nntpchan {
|
||||
|
||||
void LineReader::OnData(const char * d, ssize_t l)
|
||||
{
|
||||
if(l <= 0) return;
|
||||
std::size_t idx = 0;
|
||||
while(l-- > 0) {
|
||||
char c = d[idx++];
|
||||
if(c == '\n') {
|
||||
OnLine(d, idx-2);
|
||||
d += idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LineReader::OnLine(const char *d, const size_t l)
|
||||
{
|
||||
std::string line(d, l);
|
||||
HandleLine(line);
|
||||
}
|
||||
|
||||
bool LineReader::HasNextLine()
|
||||
{
|
||||
return m_sendlines.size() > 0;
|
||||
}
|
||||
|
||||
std::string LineReader::GetNextLine()
|
||||
{
|
||||
std::string line = m_sendlines[0];
|
||||
m_sendlines.pop_front();
|
||||
return line;
|
||||
}
|
||||
|
||||
void LineReader::QueueLine(const std::string & line)
|
||||
{
|
||||
m_sendlines.push_back(line);
|
||||
}
|
||||
}
|
35
contrib/frontends/cpp/nntpchan-daemon/src/line.hpp
Normal file
35
contrib/frontends/cpp/nntpchan-daemon/src/line.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef NNTPCHAN_LINE_HPP
|
||||
#define NNTPCHAN_LINE_HPP
|
||||
#include <string>
|
||||
#include <deque>
|
||||
namespace nntpchan
|
||||
{
|
||||
|
||||
/** @brief a buffered line reader */
|
||||
class LineReader
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
/** @brief queue inbound data from connection */
|
||||
void OnData(const char * data, ssize_t s);
|
||||
|
||||
/** @brief do we have line to send to the client? */
|
||||
bool HasNextLine();
|
||||
/** @brief get the next line to send to the client, does not check if it exists */
|
||||
std::string GetNextLine();
|
||||
|
||||
protected:
|
||||
/** @brief handle a line from the client */
|
||||
virtual void HandleLine(const std::string & line) = 0;
|
||||
/** @brief queue the next line to send to the client */
|
||||
void QueueLine(const std::string & line);
|
||||
|
||||
private:
|
||||
void OnLine(const char * d, const size_t l);
|
||||
// lines to send
|
||||
std::deque<std::string> m_sendlines;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
61
contrib/frontends/cpp/nntpchan-daemon/src/nntp_auth.cpp
Normal file
61
contrib/frontends/cpp/nntpchan-daemon/src/nntp_auth.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include "nntp_auth.hpp"
|
||||
#include "crypto.hpp"
|
||||
#include "base64.hpp"
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
HashedCredDB::HashedCredDB(std::istream & i) :
|
||||
m_instream(i) {}
|
||||
|
||||
bool HashedCredDB::CheckLogin(const std::string & user, const std::string & passwd)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_access);
|
||||
m_found = false;
|
||||
m_user = user;
|
||||
m_passwd = passwd;
|
||||
m_instream.seekg(0, std::ios::end);
|
||||
const auto l = m_instream.tellg();
|
||||
m_instream.seekg(0, std::ios::beg);
|
||||
char * buff = new char[l];
|
||||
// read file
|
||||
m_instream.read(buff, l);
|
||||
OnData(buff, l);
|
||||
delete [] buff;
|
||||
return m_found;
|
||||
}
|
||||
|
||||
bool HashedCredDB::ProcessLine(const std::string & line)
|
||||
{
|
||||
// strip comments
|
||||
auto comment = line.find("#");
|
||||
std::string part = line;
|
||||
for (; comment != std::string::npos; comment = part.find("#")) {
|
||||
if(comment)
|
||||
part = part.substr(0, comment);
|
||||
else break;
|
||||
}
|
||||
if(!part.size()) return false; // empty line after comments
|
||||
auto idx = part.find(":");
|
||||
if (idx == std::string::npos) return false; // bad format
|
||||
if (m_user != part.substr(0, idx)) return false; // username mismatch
|
||||
part = part.substr(idx+1);
|
||||
|
||||
idx = part.find(":");
|
||||
if (idx == std::string::npos) return false; // bad format
|
||||
std::string cred = part.substr(0, idx);
|
||||
std::string salt = part.substr(idx+1);
|
||||
return Hash(m_passwd, salt) == cred;
|
||||
}
|
||||
|
||||
std::string HashedCredDB::Hash(const std::string & data, const std::string & salt)
|
||||
{
|
||||
SHA512Digest h;
|
||||
std::string d = data + salt;
|
||||
SHA512((const uint8_t*)d.c_str(), d.size(), h);
|
||||
return B64Encode(h.data(), h.size());
|
||||
}
|
||||
}
|
||||
|
38
contrib/frontends/cpp/nntpchan-daemon/src/nntp_auth.hpp
Normal file
38
contrib/frontends/cpp/nntpchan-daemon/src/nntp_auth.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef NNTPCHAN_NNTP_AUTH_HPP
|
||||
#define NNTPCHAN_NNTP_AUTH_HPP
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include "line.hpp"
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
/** @brief nntp credential db interface */
|
||||
class NNTPCredentialDB
|
||||
{
|
||||
public:
|
||||
/** @brief return true if username password combo is correct */
|
||||
virtual bool CheckLogin(const std::string & user, const std::string & passwd) = 0;
|
||||
};
|
||||
|
||||
/** @brief nntp credential db using hashed+salted passwords */
|
||||
class HashedCredDB : public NNTPCredentialDB, public LineReader
|
||||
{
|
||||
public:
|
||||
HashedCredDB(std::istream & i);
|
||||
bool CheckLogin(const std::string & user, const std::string & passwd);
|
||||
protected:
|
||||
std::string Hash(const std::string & data, const std::string & salt);
|
||||
private:
|
||||
|
||||
bool ProcessLine(const std::string & line);
|
||||
|
||||
std::mutex m_access;
|
||||
std::string m_user, m_passwd;
|
||||
bool m_found;
|
||||
/** return true if we have a line that matches this username / password combo */
|
||||
std::istream & m_instream;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
74
contrib/frontends/cpp/nntpchan-daemon/src/nntp_handler.cpp
Normal file
74
contrib/frontends/cpp/nntpchan-daemon/src/nntp_handler.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "nntp_handler.hpp"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
NNTPServerHandler::NNTPServerHandler(const std::string & storage) :
|
||||
m_store(storage),
|
||||
m_authed(false),
|
||||
m_state(eStateReadCommand)
|
||||
{
|
||||
}
|
||||
|
||||
void NNTPServerHandler::HandleLine(const std::string &line)
|
||||
{
|
||||
if(m_state == eStateReadCommand) {
|
||||
std::deque<std::string> command;
|
||||
std::istringstream s;
|
||||
s.str(line);
|
||||
for (std::string part; std::getline(s, part, ' '); ) {
|
||||
if(part.size()) command.push_back(std::string(part));
|
||||
}
|
||||
if(command.size())
|
||||
HandleCommand(command);
|
||||
else
|
||||
QueueLine("501 Syntax error");
|
||||
}
|
||||
}
|
||||
|
||||
void NNTPServerHandler::HandleCommand(const std::deque<std::string> & command)
|
||||
{
|
||||
auto cmd = command[0];
|
||||
std::transform(cmd.begin(), cmd.end(), cmd.begin(),
|
||||
[](unsigned char ch) { return std::toupper(ch); });
|
||||
std::size_t cmdlen = command.size();
|
||||
std::cerr << "handle command [" << cmd << "] " << (int) cmdlen << std::endl;
|
||||
if (cmd == "QUIT") {
|
||||
Quit();
|
||||
return;
|
||||
} else if (cmd == "MODE" ) {
|
||||
if(cmdlen == 1) {
|
||||
// set mode
|
||||
SwitchMode(command[1]);
|
||||
} else if(cmdlen) {
|
||||
// too many arguments
|
||||
} else {
|
||||
// get mode
|
||||
}
|
||||
|
||||
} else {
|
||||
// unknown command
|
||||
QueueLine("500 Unknown Command");
|
||||
}
|
||||
}
|
||||
|
||||
void NNTPServerHandler::SwitchMode(const std::string & mode)
|
||||
{
|
||||
}
|
||||
|
||||
void NNTPServerHandler::Quit()
|
||||
{
|
||||
std::cerr << "quitting" << std::endl;
|
||||
m_state = eStateQuit;
|
||||
QueueLine("205 quitting");
|
||||
}
|
||||
|
||||
bool NNTPServerHandler::Done()
|
||||
{
|
||||
return m_state == eStateQuit;
|
||||
}
|
||||
}
|
45
contrib/frontends/cpp/nntpchan-daemon/src/nntp_handler.hpp
Normal file
45
contrib/frontends/cpp/nntpchan-daemon/src/nntp_handler.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef NNTPCHAN_NNTP_HANDLER_HPP
|
||||
#define NNTPCHAN_NNTP_HANDLER_HPP
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include "line.hpp"
|
||||
#include "storage.hpp"
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
class NNTPServerHandler : public LineReader
|
||||
{
|
||||
public:
|
||||
NNTPServerHandler(const std::string & storage);
|
||||
|
||||
bool Done();
|
||||
|
||||
protected:
|
||||
void HandleLine(const std::string & line);
|
||||
void HandleCommand(const std::deque<std::string> & command);
|
||||
private:
|
||||
|
||||
enum State {
|
||||
eStateReadCommand,
|
||||
eStateStoreArticle,
|
||||
eStateQuit
|
||||
};
|
||||
|
||||
private:
|
||||
// handle quit command, this queues a reply
|
||||
void Quit();
|
||||
|
||||
// switch nntp modes, this queues a reply
|
||||
void SwitchMode(const std::string & mode);
|
||||
|
||||
private:
|
||||
|
||||
ArticleStorage m_store;
|
||||
std::string m_mode;
|
||||
bool m_authed;
|
||||
State m_state;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
@ -39,7 +39,7 @@ namespace nntpchan
|
||||
return;
|
||||
}
|
||||
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath);
|
||||
conn->SendCode(200, "Posting Allowed");
|
||||
conn->Greet();
|
||||
}
|
||||
|
||||
|
||||
@ -56,6 +56,7 @@ namespace nntpchan
|
||||
uv_accept(s, (uv_stream_t*) &m_conn);
|
||||
uv_read_start((uv_stream_t*) &m_conn, [] (uv_handle_t * h, size_t s, uv_buf_t * b) {
|
||||
NNTPServerConn * self = (NNTPServerConn*) h->data;
|
||||
if(self == nullptr) return;
|
||||
b->base = self->m_readbuff;
|
||||
if (s > sizeof(self->m_readbuff))
|
||||
b->len = sizeof(self->m_readbuff);
|
||||
@ -63,70 +64,56 @@ namespace nntpchan
|
||||
b->len = s;
|
||||
}, [] (uv_stream_t * s, ssize_t nread, const uv_buf_t * b) {
|
||||
NNTPServerConn * self = (NNTPServerConn*) s->data;
|
||||
if(self == nullptr) return;
|
||||
if(nread > 0) {
|
||||
self->ProcessData(b->base, nread);
|
||||
self->m_handler.OnData(b->base, nread);
|
||||
self->SendNextReply();
|
||||
if(self->m_handler.Done())
|
||||
self->Close();
|
||||
} else {
|
||||
if (nread != UV_EOF) {
|
||||
std::cerr << "error in nntp server conn alloc: ";
|
||||
std::cerr << uv_strerror(nread);
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
delete self;
|
||||
s->data = nullptr;
|
||||
|
||||
// got eof or error
|
||||
self->Close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
NNTPServerConn::~NNTPServerConn()
|
||||
{
|
||||
uv_close((uv_handle_t*)&m_conn, [] (uv_handle_t *) {});
|
||||
}
|
||||
|
||||
void NNTPServerConn::ProcessData(const char *d, ssize_t l)
|
||||
{
|
||||
m_handler.OnData(d, l);
|
||||
}
|
||||
|
||||
void NNTPServerConn::SendNextReply()
|
||||
{
|
||||
if(m_handler.HasNextLine()) {
|
||||
auto line = m_handler.GetNextLine();
|
||||
SendLine(line);
|
||||
SendString(line+"\n");
|
||||
}
|
||||
}
|
||||
|
||||
void NNTPServerConn::SendCode(const int code, const std::string & msg)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << code << " " << msg << std::endl;
|
||||
SendString(ss.str());
|
||||
}
|
||||
|
||||
void NNTPServerConn::SendString(const std::string & line)
|
||||
{
|
||||
WriteBuffer * b = new WriteBuffer(line);
|
||||
uv_write(&b->w, *this, &b->b, 1, [](uv_write_t * w, int status) {
|
||||
WriteBuffer * wb = (WriteBuffer *) w->data;
|
||||
delete wb;
|
||||
});
|
||||
}
|
||||
|
||||
NNTPServerHandler::NNTPServerHandler(const std::string & storagepath) :
|
||||
m_state(eNNTPStateGreet)
|
||||
{
|
||||
m_storage.SetPath(storagepath);
|
||||
}
|
||||
|
||||
NNTPServerHandler::~NNTPServerHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void NNTPServerHandler::OnData(const char * d, ssize_t l)
|
||||
void NNTPServerConn::Greet()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NNTPServerConn::SendString(const std::string & str)
|
||||
{
|
||||
WriteBuffer * b = new WriteBuffer(str);
|
||||
uv_write(&b->w, *this, &b->b, 1, [](uv_write_t * w, int status) {
|
||||
(void) status;
|
||||
WriteBuffer * wb = (WriteBuffer *) w->data;
|
||||
if(wb)
|
||||
delete wb;
|
||||
});
|
||||
}
|
||||
|
||||
void NNTPServerConn::Close()
|
||||
{
|
||||
uv_close((uv_handle_t*)&m_conn, [] (uv_handle_t * s) {
|
||||
NNTPServerConn * self = (NNTPServerConn*) s->data;
|
||||
if(self)
|
||||
delete self;
|
||||
s->data = nullptr;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,14 @@
|
||||
#define NNTPCHAN_NNTP_SERVER_HPP
|
||||
#include <uv.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include "storage.hpp"
|
||||
#include "nntp_auth.hpp"
|
||||
#include "nntp_handler.hpp"
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
|
||||
|
||||
class NNTPServerConn;
|
||||
|
||||
class NNTPServer
|
||||
@ -31,58 +33,24 @@ namespace nntpchan
|
||||
uv_tcp_t m_server;
|
||||
uv_loop_t * m_loop;
|
||||
|
||||
std::vector<NNTPServerConn *> m_conns;
|
||||
std::deque<NNTPServerConn *> m_conns;
|
||||
|
||||
std::string m_storagePath;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class NNTPServerHandler
|
||||
{
|
||||
public:
|
||||
|
||||
enum State {
|
||||
eNNTPStateGreet,
|
||||
eNNTPStateHandshake,
|
||||
eNNTPStateReader,
|
||||
eNNTPStateStream,
|
||||
eNNTPStateTAKETHIS,
|
||||
eNNTPStateIHAVE,
|
||||
eNNTPStateARTICLE,
|
||||
eNNTPStatePOST
|
||||
};
|
||||
|
||||
NNTPServerHandler(const std::string & storagepath);
|
||||
~NNTPServerHandler();
|
||||
|
||||
void OnData(const char * data, ssize_t s);
|
||||
|
||||
bool HasNextLine();
|
||||
std::string GetNextLine();
|
||||
|
||||
private:
|
||||
State m_state;
|
||||
ArticleStorage m_storage;
|
||||
};
|
||||
|
||||
|
||||
class NNTPServerConn
|
||||
{
|
||||
public:
|
||||
NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage);
|
||||
virtual ~NNTPServerConn();
|
||||
|
||||
/** @brief close connection, this connection cannot be used after calling this */
|
||||
void Close();
|
||||
|
||||
void Quit();
|
||||
|
||||
void SendLine(const std::string & line);
|
||||
void SendCode(const int code, const std::string & message);
|
||||
|
||||
void ProcessData(const char * d, ssize_t l);
|
||||
|
||||
/** @brief send next queued reply */
|
||||
void SendNextReply();
|
||||
|
||||
void Greet();
|
||||
|
||||
private:
|
||||
|
||||
@ -94,8 +62,10 @@ namespace nntpchan
|
||||
uv_tcp_t m_conn;
|
||||
|
||||
NNTPServerHandler m_handler;
|
||||
|
||||
NNTPCredentialDB * m_logindb;
|
||||
|
||||
char m_readbuff[1024];
|
||||
char m_readbuff[1028];
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -9,6 +9,10 @@ namespace nntpchan
|
||||
{
|
||||
}
|
||||
|
||||
ArticleStorage::ArticleStorage(const std::string & fpath) {
|
||||
SetPath(fpath);
|
||||
}
|
||||
|
||||
ArticleStorage::~ArticleStorage()
|
||||
{
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ namespace nntpchan
|
||||
{
|
||||
public:
|
||||
ArticleStorage();
|
||||
ArticleStorage(const std::string & fpath);
|
||||
~ArticleStorage();
|
||||
|
||||
void SetPath(const std::string & fpath);
|
||||
|
18
contrib/frontends/cpp/nntpchan-daemon/tool.cpp
Normal file
18
contrib/frontends/cpp/nntpchan-daemon/tool.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "base64.hpp"
|
||||
#include "crypto.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
static void print_help(const std::string & exename)
|
||||
{
|
||||
std::cout << "usage: " << exename << " [help|passwd|genconf]" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
if(argc == 1) {
|
||||
print_help(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user