2017-05-03 17:09:23 +05:00
|
|
|
#include <cassert>
|
2017-05-03 18:15:06 +05:00
|
|
|
#include <iostream>
|
2017-10-17 19:29:56 +05:00
|
|
|
#include <nntpchan/buffer.hpp>
|
|
|
|
#include <nntpchan/net.hpp>
|
|
|
|
#include <nntpchan/server.hpp>
|
2017-05-03 17:09:23 +05:00
|
|
|
|
|
|
|
namespace nntpchan
|
|
|
|
{
|
2017-10-17 19:29:56 +05:00
|
|
|
Server::Server(uv_loop_t *loop)
|
|
|
|
{
|
|
|
|
m_loop = loop;
|
|
|
|
uv_tcp_init(m_loop, &m_server);
|
|
|
|
m_server.data = this;
|
|
|
|
}
|
2017-05-03 17:09:23 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
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;
|
|
|
|
});
|
|
|
|
}
|
2017-05-03 17:09:23 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
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);
|
|
|
|
}
|
2017-05-03 17:09:23 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
void Server::OnAccept(uv_stream_t *s, int status)
|
|
|
|
{
|
|
|
|
if (status < 0)
|
2017-05-03 17:09:23 +05:00
|
|
|
{
|
2017-10-17 19:29:56 +05:00
|
|
|
OnAcceptError(status);
|
|
|
|
return;
|
2017-05-03 17:09:23 +05:00
|
|
|
}
|
2017-10-17 19:29:56 +05:00
|
|
|
IServerConn *conn = CreateConn(s);
|
|
|
|
assert(conn);
|
|
|
|
m_conns.push_back(conn);
|
|
|
|
conn->Greet();
|
|
|
|
}
|
2017-05-03 17:09:23 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
void Server::RemoveConn(IServerConn *conn)
|
|
|
|
{
|
|
|
|
auto itr = m_conns.begin();
|
|
|
|
while (itr != m_conns.end())
|
2017-05-03 18:15:06 +05:00
|
|
|
{
|
2017-10-17 19:29:56 +05:00
|
|
|
if (*itr == conn)
|
|
|
|
itr = m_conns.erase(itr);
|
|
|
|
else
|
|
|
|
++itr;
|
2017-05-03 18:15:06 +05:00
|
|
|
}
|
2017-10-17 19:29:56 +05:00
|
|
|
}
|
2017-05-03 18:15:06 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
void IConnHandler::QueueLine(const std::string &line) { m_sendlines.push_back(line); }
|
2017-05-03 17:09:23 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
bool IConnHandler::HasNextLine() { return m_sendlines.size() > 0; }
|
2017-05-03 17:09:23 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
std::string IConnHandler::GetNextLine()
|
|
|
|
{
|
|
|
|
std::string line = m_sendlines[0];
|
|
|
|
m_sendlines.pop_front();
|
|
|
|
return line;
|
|
|
|
}
|
2017-05-03 18:15:06 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2017-05-03 18:15:06 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
IServerConn::~IServerConn() { delete m_handler; }
|
2017-05-03 18:15:06 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
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;
|
|
|
|
});
|
|
|
|
}
|
2017-05-03 18:15:06 +05:00
|
|
|
|
2017-10-17 19:29:56 +05:00
|
|
|
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;
|
|
|
|
});
|
|
|
|
}
|
2017-05-03 17:09:23 +05:00
|
|
|
}
|