#include "utils.h"
#include "protocol.h"
#include "server.h"
#include "connection.h"
Server::Server():
started(), switching(), socket(), stopRequested(), stopTimeUs() { }
Server::~Server() {
Lock lock(mutex);
assert(!started && !socket);
clean();
}
Protocol& Server::getProtocol() const
{ assert(socket); return socket->protocol; }
const Address& Server::getLocalAddress() const
{ assert(socket); return socket->address; }
void Server::clean() {
started = false;
socket = nullptr;
stopRequested = false;
stopTimeUs = 0;
}
ErrorCode Server::start(Socket *socket) {
Lock lock(mutex);
stop();
if (!socket) return ERR_INVALID_ARGS;
if (switching) return ERR_SERVER_IS_SWITCHING;
this->socket = socket;
switching = true;
ErrorCode errorCode = onStart();
if (errorCode) clean(); else started = true;
switching = false;
return errorCode;
}
void Server::stop(ErrorCode errorCode) {
Lock lock(mutex);
if (!started || switching) return;
switching = true;
int unfinichedConnections = getProtocol().stopServer(*this);
if (!errorCode && unfinichedConnections) errorCode = ERR_SERVER_UNFINISHED_CONNECTIONS;
onStop(errorCode);
Socket *socketCopy = socket;
clean();
switching = false;
socketCopy->finalize();
}
void Server::stopReq() {
Lock lock(mutex);
if (!started || switching || stopRequested) return;
stopRequested = true;
getProtocol().stopServerReq(*this);
onStopRequested();
}
void Server::stopWait(unsigned long long timeoutUs, bool withRequest) {
std::unique_lock<Mutex> uniqlock(mutex);
if (!started || switching) return;
if (withRequest) stopReq();
unsigned long long timeUs = monotonicTimeUs() + timeoutUs;
if (stopTimeUs > timeUs)
{ stopTimeUs = timeUs; stopWaitCondition.notify_all(); }
while(started) {
unsigned long long timeUs = monotonicTimeUs();
if (timeUs >= stopTimeUs)
{ stop(ERR_CONNECTION_LOST); break; }
stopWaitCondition.wait_for(uniqlock, std::chrono::microseconds(stopTimeUs - timeUs));
}
}
Connection::Handle Server::connect(const Address &remoteAddress)
{ return onConnect(remoteAddress); }
void Server::disconnect(const Connection::Handle &connection)
{ onDisconnect(connection); }
ErrorCode Server::onStart()
{ return ERR_NONE; }
void Server::onStopRequested()
{ }
void Server::onStop(ErrorCode)
{ }
Connection::Handle Server::onConnect(const Address&)
{ return nullptr; }
void Server::onDisconnect(const Connection::Handle&)
{ }