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-04 08:17:49 -04:00

155 lines
2.7 KiB
C++

#include <cassert>
#include <iostream>
#include <nntpchan/buffer.hpp>
#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, int status)
{
if (status)
{
OnAcceptError(status);
return;
}
IServerConn *conn = CreateConn(f);
if(m_Loop->TrackConn(conn))
{
m_conns.push_back(conn);
conn->Greet();
conn->write();
}
else
{
std::cout << "accept track conn failed" << std::endl;
conn->close();
delete conn;
}
}
int Server::accept()
{
int res = ::accept4(fd, nullptr, nullptr, SOCK_NONBLOCK);
if(res == -1) return res;
OnAccept(res, errno);
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()
{
auto leftovers = m_writeLeftover.size();
ssize_t written;
if(leftovers)
{
if(leftovers > 1024)
{
leftovers = 1024;
}
written = ::write(fd, m_writeLeftover.c_str(), leftovers);
if(written > 0)
{
m_writeLeftover = m_writeLeftover.substr(written);
}
else
{
// too much leftovers
return -1;
}
}
do
{
if(!m_handler->HasNextLine())
{
return 0;
}
auto line = m_handler->GetNextLine();
written = ::write(fd, line.c_str(), line.size());
if(written > 0)
{
m_writeLeftover = line.substr(written);
}
else
{
m_writeLeftover = line;
return -1;
}
}
while(written > 0);
return 0;
}
void IServerConn::close()
{
m_parent->RemoveConn(this);
ev::io::close();
}
}