142 lines
3.3 KiB
C++
142 lines
3.3 KiB
C++
#include <nntpchan/buffer.hpp>
|
|
#include <nntpchan/server.hpp>
|
|
#include <nntpchan/net.hpp>
|
|
#include <cassert>
|
|
#include <iostream>
|
|
|
|
namespace nntpchan
|
|
{
|
|
Server::Server(uv_loop_t * loop)
|
|
{
|
|
m_loop = loop;
|
|
uv_tcp_init(m_loop, &m_server);
|
|
m_server.data = this;
|
|
}
|
|
|
|
void Server::Close()
|
|
{
|
|
std::cout << "Close server" << std::endl;
|
|
uv_close((uv_handle_t*)&m_server, [](uv_handle_t * s) {
|
|
Server * self = (Server*)s->data;
|
|
if (self) delete self;
|
|
s->data = nullptr;
|
|
});
|
|
}
|
|
|
|
void Server::Bind(const std::string & addr)
|
|
{
|
|
auto saddr = ParseAddr(addr);
|
|
assert(uv_tcp_bind(*this, saddr, 0) == 0);
|
|
auto cb = [] (uv_stream_t * s, int status) {
|
|
Server * self = (Server *) s->data;
|
|
self->OnAccept(s, status);
|
|
};
|
|
assert(uv_listen(*this, 5, cb) == 0);
|
|
}
|
|
|
|
void Server::OnAccept(uv_stream_t * s, int status)
|
|
{
|
|
if(status < 0) {
|
|
OnAcceptError(status);
|
|
return;
|
|
}
|
|
IServerConn * conn = CreateConn(s);
|
|
assert(conn);
|
|
m_conns.push_back(conn);
|
|
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)
|
|
{
|
|
m_sendlines.push_back(line);
|
|
}
|
|
|
|
bool IConnHandler::HasNextLine()
|
|
{
|
|
return m_sendlines.size() > 0;
|
|
}
|
|
|
|
std::string IConnHandler::GetNextLine()
|
|
{
|
|
std::string line = m_sendlines[0];
|
|
m_sendlines.pop_front();
|
|
return line;
|
|
}
|
|
|
|
IServerConn::IServerConn(uv_loop_t * l, uv_stream_t * st, Server * parent, IConnHandler * h)
|
|
{
|
|
m_loop = l;
|
|
m_parent = parent;
|
|
m_handler = h;
|
|
uv_tcp_init(l, &m_conn);
|
|
m_conn.data = this;
|
|
uv_accept(st, (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 = new char[s];
|
|
}, [] (uv_stream_t * s, ssize_t nread, const uv_buf_t * b) {
|
|
IServerConn * self = (IServerConn*) s->data;
|
|
if(self == nullptr) {
|
|
if(b->base)
|
|
delete [] b->base;
|
|
return;
|
|
}
|
|
if(nread > 0) {
|
|
self->m_handler->OnData(b->base, nread);
|
|
self->SendNextReply();
|
|
if(self->m_handler->ShouldClose())
|
|
self->Close();
|
|
delete [] b->base;
|
|
} 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, (uv_stream_t*)&m_conn, &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;
|
|
});
|
|
}
|
|
}
|