157 lines
2.9 KiB
C++
157 lines
2.9 KiB
C++
#include <cassert>
|
|
#include <iostream>
|
|
#include <nntpchan/net.hpp>
|
|
#include <nntpchan/server.hpp>
|
|
|
|
namespace nntpchan
|
|
{
|
|
|
|
Server::Server(ev::Loop *loop) : ev::io(-1), m_Loop(loop) {}
|
|
|
|
void Server::close()
|
|
{
|
|
auto itr = m_conns.begin();
|
|
while (itr != m_conns.end())
|
|
{
|
|
itr = m_conns.erase(itr);
|
|
}
|
|
m_Loop->UntrackConn(this);
|
|
ev::io::close();
|
|
}
|
|
bool Server::Bind(const std::string &addr)
|
|
{
|
|
auto saddr = ParseAddr(addr);
|
|
return m_Loop->BindTCP(saddr, this);
|
|
}
|
|
|
|
void Server::OnAccept(int f)
|
|
{
|
|
IServerConn *conn = CreateConn(f);
|
|
if (!m_Loop->SetNonBlocking(conn))
|
|
{
|
|
conn->close();
|
|
delete conn;
|
|
}
|
|
else if (m_Loop->TrackConn(conn))
|
|
{
|
|
m_conns.push_back(conn);
|
|
conn->Greet();
|
|
conn->write(1024);
|
|
}
|
|
else
|
|
{
|
|
conn->close();
|
|
delete conn;
|
|
}
|
|
}
|
|
|
|
int Server::accept()
|
|
{
|
|
int res = ::accept(fd, nullptr, nullptr);
|
|
if (res == -1)
|
|
return res;
|
|
OnAccept(res);
|
|
return res;
|
|
}
|
|
|
|
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;
|
|
}
|
|
m_Loop->UntrackConn(conn);
|
|
}
|
|
|
|
void IConnHandler::QueueLine(const std::string &line) { m_sendlines.push_back(line + "\r\n"); }
|
|
|
|
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(int fd, Server *parent, IConnHandler *h) : ev::io(fd), m_parent(parent), m_handler(h) {}
|
|
|
|
IServerConn::~IServerConn() { delete m_handler; }
|
|
|
|
int IServerConn::read(char *buf, size_t sz)
|
|
{
|
|
ssize_t readsz = ::read(fd, buf, sz);
|
|
if (readsz > 0)
|
|
{
|
|
m_handler->OnData(buf, readsz);
|
|
}
|
|
return readsz;
|
|
}
|
|
|
|
bool IServerConn::keepalive() { return !m_handler->ShouldClose(); }
|
|
|
|
int IServerConn::write(size_t avail)
|
|
{
|
|
auto leftovers = m_writeLeftover.size();
|
|
int written = 0;
|
|
if (leftovers)
|
|
{
|
|
if (leftovers > avail)
|
|
{
|
|
leftovers = avail;
|
|
}
|
|
written = ::write(fd, m_writeLeftover.c_str(), leftovers);
|
|
if (written > 0)
|
|
{
|
|
avail -= written;
|
|
m_writeLeftover = m_writeLeftover.substr(written);
|
|
}
|
|
else
|
|
{
|
|
// too much leftovers
|
|
return -1;
|
|
}
|
|
}
|
|
do
|
|
{
|
|
if (!m_handler->HasNextLine())
|
|
{
|
|
return written;
|
|
}
|
|
auto line = m_handler->GetNextLine();
|
|
int wrote;
|
|
if (line.size() <= avail)
|
|
{
|
|
wrote = ::write(fd, line.c_str(), line.size());
|
|
}
|
|
else
|
|
{
|
|
auto subline = line.substr(0, avail);
|
|
wrote = ::write(fd, subline.c_str(), subline.size());
|
|
}
|
|
if (wrote > 0)
|
|
{
|
|
written += wrote;
|
|
avail -= wrote;
|
|
m_writeLeftover = line.substr(wrote);
|
|
}
|
|
else
|
|
{
|
|
m_writeLeftover = line;
|
|
return -1;
|
|
}
|
|
} while (avail > 0);
|
|
return written;
|
|
}
|
|
|
|
void IServerConn::close()
|
|
{
|
|
m_parent->RemoveConn(this);
|
|
ev::io::close();
|
|
}
|
|
}
|