Archived
1
0
This commit is contained in:
Jeff Becker 2017-05-03 09:15:06 -04:00
parent 07e62d2057
commit dba185c6aa
7 changed files with 145 additions and 147 deletions

View File

@ -6,7 +6,7 @@ namespace nntpchan
{ {
/** @brief a buffered line reader */ /** @brief a buffered line reader */
class LineReader : public IConnHandler class LineReader
{ {
public: public:

View File

@ -21,6 +21,11 @@ namespace nntpchan
if(m_auth) delete m_auth; if(m_auth) delete m_auth;
} }
void NNTPServerHandler::OnData(const char * data, ssize_t sz)
{
LineReader::OnData(data, sz);
}
void NNTPServerHandler::HandleLine(const std::string &line) void NNTPServerHandler::HandleLine(const std::string &line)
{ {
if(m_state == eStateReadCommand) { if(m_state == eStateReadCommand) {
@ -92,7 +97,7 @@ namespace nntpchan
QueueLine("205 quitting"); QueueLine("205 quitting");
} }
bool NNTPServerHandler::Done() bool NNTPServerHandler::ShouldClose()
{ {
return m_state == eStateQuit; return m_state == eStateQuit;
} }

View File

@ -8,13 +8,15 @@
namespace nntpchan namespace nntpchan
{ {
class NNTPServerHandler : public LineReader class NNTPServerHandler : public LineReader, public IConnHandler
{ {
public: public:
NNTPServerHandler(const std::string & storage); NNTPServerHandler(const std::string & storage);
~NNTPServerHandler(); ~NNTPServerHandler();
bool Done(); virtual bool ShouldClose();
virtual void OnData(const char * data, ssize_t sz);
void SetAuth(NNTPCredentialDB * creds); void SetAuth(NNTPCredentialDB * creds);

View File

@ -1,6 +1,7 @@
#include "buffer.hpp"
#include "nntp_server.hpp" #include "nntp_server.hpp"
#include "nntp_auth.hpp" #include "nntp_auth.hpp"
#include "nntp_handler.hpp"
#include "net.hpp" #include "net.hpp"
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
@ -8,56 +9,29 @@
namespace nntpchan namespace nntpchan
{ {
NNTPServer::NNTPServer(uv_loop_t * loop)
{ NNTPServer::NNTPServer(uv_loop_t * loop) : Server(loop), m_frontend(nullptr) {}
uv_tcp_init(loop, &m_server);
m_loop = loop;
m_server.data = this;
}
NNTPServer::~NNTPServer() NNTPServer::~NNTPServer()
{ {
if (m_frontend) delete m_frontend; if (m_frontend) delete m_frontend;
} }
void NNTPServer::Close() IServerConn * NNTPServer::CreateConn(uv_stream_t * s)
{ {
uv_close((uv_handle_t*)&m_server, [](uv_handle_t * s) {
NNTPServer * self = (NNTPServer*)s->data;
if (self) delete self;
s->data = nullptr;
});
}
void NNTPServer::Bind(const std::string & addr)
{
auto saddr = ParseAddr(addr);
assert(uv_tcp_bind(*this, saddr, 0) == 0);
std::cerr << "nntp server bound to " << saddr.to_string() << std::endl;
auto cb = [] (uv_stream_t * s, int status) {
NNTPServer * self = (NNTPServer *) s->data;
self->OnAccept(s, status);
};
assert(uv_listen(*this, 5, cb) == 0);
}
void NNTPServer::OnAccept(uv_stream_t * s, int status)
{
if(status < 0) {
std::cerr << "nntp server OnAccept fail: " << uv_strerror(status) << std::endl;
return;
}
NNTPCredentialDB * creds = nullptr; NNTPCredentialDB * creds = nullptr;
std::ifstream i; std::ifstream i;
i.open(m_logindbpath); i.open(m_logindbpath);
if(i.is_open()) creds = new HashedFileDB(m_logindbpath); if(i.is_open()) creds = new HashedFileDB(m_logindbpath);
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath, creds); NNTPServerHandler * handler = new NNTPServerHandler(m_storagePath);
conn->Greet(); if(creds)
} handler->SetAuth(creds);
NNTPServerConn * conn = new NNTPServerConn(GetLoop(), s, this, handler);
return conn;
}
void NNTPServer::SetLoginDB(const std::string path) void NNTPServer::SetLoginDB(const std::string path)
{ {
@ -76,45 +50,16 @@ namespace nntpchan
m_frontend = f; m_frontend = f;
} }
NNTPServerConn::NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds) : void NNTPServer::OnAcceptError(int status)
m_handler(storage)
{ {
m_handler.SetAuth(creds); std::cerr << "nntpserver::accept() " << uv_strerror(status) << std::endl;
uv_tcp_init(l, &m_conn);
m_conn.data = this;
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);
else
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->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;
}
// got eof or error
self->Close();
}
});
} }
void NNTPServerConn::SendNextReply() void NNTPServerConn::SendNextReply()
{ {
if(m_handler.HasNextLine()) { IConnHandler * handler = GetHandler();
auto line = m_handler.GetNextLine(); if(handler->HasNextLine()) {
auto line = handler->GetNextLine();
SendString(line + "\n"); SendString(line + "\n");
} }
} }
@ -122,28 +67,11 @@ namespace nntpchan
void NNTPServerConn::Greet() void NNTPServerConn::Greet()
{ {
m_handler.Greet(); IConnHandler * handler = GetHandler();
handler->Greet();
SendNextReply(); SendNextReply();
} }
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;
});
}
} }

View File

@ -3,25 +3,19 @@
#include <uv.h> #include <uv.h>
#include <string> #include <string>
#include <deque> #include <deque>
#include "storage.hpp"
#include "frontend.hpp" #include "frontend.hpp"
#include "nntp_auth.hpp" #include "server.hpp"
#include "nntp_handler.hpp"
namespace nntpchan namespace nntpchan
{ {
class NNTPServerConn; class NNTPServer : public Server
class NNTPServer
{ {
public: public:
NNTPServer(uv_loop_t * loop); NNTPServer(uv_loop_t * loop);
~NNTPServer();
void Bind(const std::string & addr); virtual ~NNTPServer();
void OnAccept(uv_stream_t * s, int status);
void SetStoragePath(const std::string & path); void SetStoragePath(const std::string & path);
@ -31,17 +25,12 @@ namespace nntpchan
void Close(); void Close();
virtual IServerConn * CreateConn(uv_stream_t * s);
virtual void OnAcceptError(int status);
private: private:
operator uv_handle_t * () { return (uv_handle_t*) &m_server; }
operator uv_tcp_t * () { return &m_server; }
operator uv_stream_t * () { return (uv_stream_t *) &m_server; }
uv_tcp_t m_server;
uv_loop_t * m_loop;
std::deque<NNTPServerConn *> m_conns;
std::string m_logindbpath; std::string m_logindbpath;
std::string m_storagePath; std::string m_storagePath;
@ -49,30 +38,18 @@ namespace nntpchan
}; };
class NNTPServerConn class NNTPServerConn : public IServerConn
{ {
public: public:
NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds);
/** @brief close connection, this connection cannot be used after calling this */ NNTPServerConn(uv_loop_t * l, uv_stream_t * s, Server * parent, IConnHandler * h) : IServerConn(l, s, parent, h) {}
void Close();
virtual bool IsTimedOut() { return false; };
/** @brief send next queued reply */ /** @brief send next queued reply */
void SendNextReply(); virtual void SendNextReply();
void Greet(); virtual void Greet();
private:
void SendString(const std::string & line);
operator uv_stream_t * () { return (uv_stream_t *) &m_conn; }
uv_tcp_t m_conn;
NNTPServerHandler m_handler;
char m_readbuff[1028];
}; };
} }

View File

@ -1,6 +1,8 @@
#include "buffer.hpp"
#include "server.hpp" #include "server.hpp"
#include "net.hpp" #include "net.hpp"
#include <cassert> #include <cassert>
#include <iostream>
namespace nntpchan namespace nntpchan
{ {
@ -42,6 +44,18 @@ namespace nntpchan
conn->Greet(); conn->Greet();
} }
void Server::RemoveConn(IServerConn * conn)
{
auto itr = m_conns.begin();
while(itr != m_conns.end())
{
if(*itr == conn)
itr = m_conns.erase(itr);
else
++itr;
}
}
void IConnHandler::QueueLine(const std::string & line) void IConnHandler::QueueLine(const std::string & line)
{ {
m_sendlines.push_back(line); m_sendlines.push_back(line);
@ -58,4 +72,68 @@ namespace nntpchan
m_sendlines.pop_front(); m_sendlines.pop_front();
return line; return line;
} }
IServerConn::IServerConn(uv_loop_t * l, uv_stream_t * s, Server * parent, IConnHandler * h)
{
m_loop = l;
m_stream = s;
m_parent = parent;
m_handler = h;
uv_tcp_init(l, &m_conn);
m_conn.data = this;
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) {
IServerConn * self = (IServerConn*) h->data;
if(self == nullptr) return;
b->base = self->m_readbuff;
if (s > sizeof(self->m_readbuff))
b->len = sizeof(self->m_readbuff);
else
b->len = s;
}, [] (uv_stream_t * s, ssize_t nread, const uv_buf_t * b) {
IServerConn * self = (IServerConn*) s->data;
if(self == nullptr) return;
if(nread > 0) {
self->m_handler->OnData(b->base, nread);
self->SendNextReply();
if(self->m_handler->ShouldClose())
self->Close();
} else {
if (nread != UV_EOF) {
std::cerr << "error in nntp server conn alloc: ";
std::cerr << uv_strerror(nread);
std::cerr << std::endl;
}
// got eof or error
self->Close();
}
});
}
IServerConn::~IServerConn()
{
delete m_handler;
}
void IServerConn::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 IServerConn::Close()
{
m_parent->RemoveConn(this);
uv_close((uv_handle_t*)&m_conn, [] (uv_handle_t * s) {
IServerConn * self = (IServerConn*) s->data;
if(self)
delete self;
s->data = nullptr;
});
}
} }

View File

@ -4,7 +4,6 @@
#include <deque> #include <deque>
#include <functional> #include <functional>
#include <string> #include <string>
#include <vector>
namespace nntpchan namespace nntpchan
{ {
@ -14,6 +13,9 @@ namespace nntpchan
struct IConnHandler struct IConnHandler
{ {
virtual ~IConnHandler() {};
/** got inbound data */ /** got inbound data */
virtual void OnData(const char * data, ssize_t s) = 0; virtual void OnData(const char * data, ssize_t s) = 0;
@ -29,6 +31,9 @@ namespace nntpchan
/** queue a data send */ /** queue a data send */
void QueueLine(const std::string & line); void QueueLine(const std::string & line);
virtual void Greet() = 0;
private: private:
std::deque<std::string> m_sendlines; std::deque<std::string> m_sendlines;
}; };
@ -37,20 +42,23 @@ namespace nntpchan
struct IServerConn struct IServerConn
{ {
IServerConn(uv_loop_t * l, uv_stream_t * s, Server * parent, IConnHandler * h); IServerConn(uv_loop_t * l, uv_stream_t * s, Server * parent, IConnHandler * h);
virtual ~IServerConn() = 0; virtual ~IServerConn();
virtual void Close() = 0; virtual void Close();
virtual void Greet() = 0; virtual void Greet() = 0;
virtual void SendNextReply() = 0; virtual void SendNextReply() = 0;
virtual bool IsTimedOut() = 0; virtual bool IsTimedOut() = 0;
void SendString(const std::string & str);
Server * Parent() { return m_parent; }; Server * Parent() { return m_parent; };
IConnHandler * GetHandler() { return m_handler; }; IConnHandler * GetHandler() { return m_handler; };
operator uv_stream_t * () { return m_stream; }; operator uv_stream_t * () { return m_stream; };
uv_loop_t * GetLoop() { return m_loop; }; uv_loop_t * GetLoop() { return m_loop; };
private: private:
uv_tcp_t m_conn;
uv_stream_t * m_stream; uv_stream_t * m_stream;
uv_loop_t * m_loop; uv_loop_t * m_loop;
Server * m_parent; Server * m_parent;
IConnHandler * m_handler; IConnHandler * m_handler;
char m_readbuff[4096];
}; };
class Server class Server
@ -83,7 +91,7 @@ namespace nntpchan
operator uv_stream_t * () { return (uv_stream_t *) &m_server; } operator uv_stream_t * () { return (uv_stream_t *) &m_server; }
void OnAccept(uv_stream_t * s, int status); void OnAccept(uv_stream_t * s, int status);
std::vector<IServerConn *> m_conns; std::deque<IServerConn *> m_conns;
uv_tcp_t m_server; uv_tcp_t m_server;
uv_loop_t * m_loop; uv_loop_t * m_loop;
}; };