Blob Blame Raw

#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&)
	{ }