Archived
1
0
This repository has been archived on 2023-08-12. You can view files and clone it, but cannot push or open issues or pull requests.
nntpchan/contrib/backends/nntpchan-daemon/libnntpchan/server.cpp
2018-05-06 11:03:53 -04:00

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();
}
}