#include <cstring>
#include <chrono>
#include <thread>
#include <mutex>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include "protocol.h"
#include "server.h"
#define DebugMSG ShowDebugMSG
Server::Server():
connFirst(), connLast()
{ }
Server::~Server()
{ destroy();}
bool Server::open(Protocol &protocol, void *address, size_t addressSize)
{ OpenLock lock(*this, protocol, address, addressSize); return lock.success; }
void Server::handleDisconnect(Connection &connection, bool error) {
onDisconnect(&connection, error);
if (!connFirst && stateLocal == STATE_CLOSING_CONNECTIONS) {
DebugMSG("to closing");
state = stateLocal = STATE_CLOSING;
stateProtector.wait();
onClose(error);
enqueue();
}
}
void Server::handleState() {
if (stateLocal == STATE_NONE) {
DebugMSG("none");
int sockId = -1;
if (addressSize >= sizeof(sa_family_t)) {
struct sockaddr *addr = (struct sockaddr*)address;
sockId = ::socket(addr->sa_family, SOCK_STREAM, 0);
if (sockId >= 0) {
initSocket(sockId);
if ( 0 != ::bind(sockId, addr, (int)addressSize)
|| 0 != ::listen(sockId, 128) )
{
DebugMSG("cannot bind/listen");
::close(sockId);
sockId = -1;
}
} else {
DebugMSG("cannot create socket");
}
}
if (sockId >= 0) {
DebugMSG("to open");
prev = protocol->sockLast;
(prev ? prev->next : protocol->sockFirst) = this;
this->sockId = sockId;
updateEvents(true, false);
state = stateLocal = STATE_OPEN;
stateProtector.wait();
onOpen(address, addressSize);
} else {
DebugMSG("opening error -> to closed");
onOpeningError();
state = STATE_CLOSED;
while(closeWaiters > 0)
{ closeCondition.notify_all(); std::this_thread::yield(); }
state = STATE_FINISHED;
DebugMSG("opening error -> finished");
}
} else {
State sw = stateWanted;
if ( stateLocal == STATE_OPEN
&& sw == STATE_CLOSE_REQ )
{
DebugMSG("to close req");
for(Connection *conn = connFirst; conn; conn = conn->srvNext)
conn->closeReq();
updateEvents(false, false);
state = stateLocal = STATE_CLOSE_REQ;
stateProtector.wait();
onCloseReqested();
}
if ( stateLocal >= STATE_OPEN
&& stateLocal <= STATE_CLOSE_REQ
&& sw == STATE_CLOSING )
{
DebugMSG("to closing connections");
updateEvents(false, false);
if (connFirst) {
for(Connection *conn = connFirst; conn; conn = conn->srvNext)
conn->close(true);
state = stateLocal = STATE_CLOSING_CONNECTIONS;
stateProtector.wait();
} else {
DebugMSG("to closing");
state = stateLocal = STATE_CLOSING;
stateProtector.wait();
onClose(error);
}
}
if ( stateLocal == STATE_CLOSING && !enqueued ) {
DebugMSG("to closed");
if (sockId >= 0) {
struct epoll_event event = {};
epoll_ctl(protocol->epollFd, EPOLL_CTL_DEL, sockId, &event);
::close(sockId);
sockId = -1;
}
events = 0xffffffff;
(prev ? prev->next : protocol->sockFirst) = next;
(next ? next->prev : protocol->sockLast ) = prev;
protocol = nullptr;
memset(this->address, 0, sizeof(address));
addressSize = 0;
stateWanted = STATE_NONE;
stateLocal = STATE_NONE;
DebugMSG("closeWaiters");
state = STATE_CLOSED;
while(closeWaiters > 0)
{ closeCondition.notify_all(); std::this_thread::yield(); }
state = STATE_FINISHED;
DebugMSG("finished");
}
}
}
void Server::handleEvents(unsigned int events) {
if (events & (EPOLLHUP | EPOLLERR)) {
if ( stateLocal >= STATE_OPEN
&& stateLocal < STATE_CLOSING )
close((bool)(events & EPOLLERR));
return;
}
if (events & EPOLLIN) {
if ( stateLocal >= STATE_OPEN
&& stateLocal < STATE_CLOSE_REQ)
{
unsigned char address[MAX_ADDR_SIZE] = {};
socklen_t len = sizeof(address);
int res = ::accept(sockId, (struct sockaddr*)address, &len);
assert(len < sizeof(address));
if (res >= 0)
if (Connection *conn = onConnect(address, len))
if (!conn->open(*protocol, address, len, res, this))
onDisconnect(conn, true);
}
}
}
Connection* Server::onConnect(const void*, size_t) { return nullptr; }
void Server::onDisconnect(Connection*, bool) { }