Blob Blame Raw

#include "utils.h"
#include "protocol.h"
#include "server.h"
#include "connection.h"



Socket::Socket(
	Protocol &protocol,
	const Connection::Handle &connection,
	const Server::Handle &server,
	const Address &address
):
	protocol(protocol), connection(connection), server(server), address(address),
	flags(), prev(), next(), chPrev(), chNext()
{
	prev = protocol.last;
	(prev ? prev->next : protocol.first) = this;
}


Socket::~Socket() {
	setChanged(false);
	(prev ? prev->next : protocol.first) = next;
	(next ? next->prev : protocol.last) = prev;
	prev = next = nullptr;
}


void Socket::onConstructionComplete() {
	flags |= CREATED;
	setChanged(true);
}


void Socket::setChanged(bool changed) {
	if ((bool)(flags & CHANGED) == changed) return;
	if (changed) {
		flags |= CHANGED;
		chPrev = protocol.chLast;
		(chPrev ? chPrev->chNext : protocol.chFirst) = this;
		protocol.onSocketChanged(this);
	} else {
		flags &= ~(CHANGED | CREATED);
		(chPrev ? chPrev->chNext : protocol.chFirst) = chNext;
		(chNext ? chNext->chPrev : protocol.chLast) = chPrev;
		chPrev = chNext = nullptr;
	}
}


void Socket::setWantRead(bool want) {
	Protocol::Lock lock(protocol.mutex);
	if ((bool)(flags & WANTREAD) == want) return;
	flags = want ? flags | WANTREAD : flags & ~WANTREAD;
	setChanged(true);
}


void Socket::setWantWrite(bool want) {
	Protocol::Lock lock(protocol.mutex);
	if ((bool)(flags & WANTWRITE) == want) return;
	flags = want ? flags | WANTWRITE : flags & ~WANTWRITE;
	setChanged(true);
}


void Socket::finalize() {
	Protocol::Lock lock(protocol.mutex);
	if (flags & REMOVED) return;
	flags |= REMOVED;
	setChanged(true);
}



Protocol::Protocol():
	first(), last(), chFirst(), chLast(),
	started(), switching(), stopRequested(), stopTimeUs() { }


Protocol::~Protocol() {
	Lock lockStartStop(mutexStartStop);
	Lock lock(mutex);
	assert(!started);
	clean();
}


ErrorCode Protocol::connectionOpen(const Connection::Handle &connection, Socket *socket) {
	if (!connection || !socket) return ERR_INVALID_ARGS;
	if (!isFullActive()) return ERR_PROTOCOL_NOT_INITIALIZED;
	return connection->open(socket);
}


ErrorCode Protocol::serverStart(const Server::Handle &server, Socket *socket) {
	if (!server || !socket) return ERR_INVALID_ARGS;
	if (!isFullActive()) return ERR_PROTOCOL_NOT_INITIALIZED;
	return server->start(socket);
}


Connection::Handle Protocol::serverConnect(const Server::Handle &server, const Address &address) {
	if (!server) return nullptr;
	if (!isFullActive()) return nullptr;
	return server->connect(address);
}


void Protocol::serverDisconnect(const Server::Handle &server, const Connection::Handle &connection) {
	if (!server || !connection) return;
	server->disconnect(connection);
}



int Protocol::stopServer(Server &server) {
	Lock lock(mutex);
	int count = 0;
	if (started)
		for(Socket *s = socketFirst(); s; s = socketNext(s))
			if (socketToRemove(s) && s->server == &server && s->connection)
				{ s->connection->close(ERR_CONNECTION_LOST); ++count; }
	return count;
}


int Protocol::stopServerReq(Server &server) {
	Lock lock(mutex);
	int count = 0;
	if (started)
		for(Socket *s = socketFirst(); s; s = socketNext(s))
			if (socketToRemove(s) && s->server == &server && s->connection)
				{ s->connection->closeReq(); ++count; }
	return count;
}


void Protocol::clean() {
	assert(!socketFirst());
	while(socketFirst()) delete socketFirst();
	started = false;
	stopRequested = false;
	stopTimeUs = 0;
}


ErrorCode Protocol::start() {
	Lock lockStartStop(mutexStartStop);
	Lock lock(mutex);
	stop();
	
	if (switching) return ERR_PROTOCOL_IS_SWITCHING;
	
	switching = true;
	ErrorCode errorCode = onStart();
	if (errorCode) clean(); else started = true;
	switching = false;
	
	return errorCode;
}


void Protocol::stop(ErrorCode errorCode) {
	Lock lockStartStop(mutexStartStop);
	Lock lock(mutex);
	if (!started || switching) return;
	
	switching = true;
	int unfinishedConnections = 0;
	for(Socket *s = socketFirst(); s; s = socketNext(s)) {
		if (!socketToRemove(s)) {
			if (!s->server && s->connection) {
				s->connection->close(ERR_CONNECTION_LOST);
				++unfinishedConnections;
			} else
			if (s->server && !s->connection) {
				s->server->stop(ERR_SERVER_LISTENING_LOST);
				++unfinishedConnections;
			}
		}
	}
	if (!errorCode && unfinishedConnections) errorCode = ERR_PROTOCOL_UNFINISHED_CONNECTIONS;
	onStop(errorCode);
	clean();
	switching = false;
	
	stopWaitCondition.notify_all();
}


void Protocol::stopReq() {
	Lock lock(mutex);
	if (!started || switching || stopRequested) return;
	stopRequested = true;
	for(Socket *s = socketFirst(); s; s = socketNext(s)) {
		if (!(socketFlags(s) & Socket::REMOVED)) {
			if (!s->server && s->connection)
				s->connection->closeReq();
			else
			if (s->server && !s->connection)
				s->server->stopReq();
		}
	}
	onStopRequested();
}


void Protocol::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(); break; }
		stopWaitCondition.wait_for(uniqlock, std::chrono::microseconds(stopTimeUs - timeUs));
	}
}


ErrorCode Protocol::connect(const Connection::Handle &connection, const Address &address) {
	if (!connection) return ERR_INVALID_ARGS;	
	Address resolvedAddress = address;
	ErrorCode errorCode = resolve(resolvedAddress);
	if (errorCode) return errorCode;

	Lock lock(mutex);
	if (!isFullActive()) return ERR_PROTOCOL_NOT_INITIALIZED;
	return onConnect(connection, resolvedAddress);
}


ErrorCode Protocol::listen(const Server::Handle &server, const Address &address) {
	if (!server) return ERR_INVALID_ARGS;	
	Address resolvedAddress = address;
	ErrorCode errorCode = resolve(resolvedAddress);
	if (errorCode) return errorCode;
	
	Lock lock(mutex);
	if (!isFullActive()) return ERR_PROTOCOL_NOT_INITIALIZED;
	return onListen(server, resolvedAddress);
}


ErrorCode Protocol::resolve(Address&)
	{ return ERR_ADDRESS_INCORRECT; }


ErrorCode Protocol::onStart()
	{ return ERR_NONE; }
void Protocol::onStopRequested()
	{ }
void Protocol::onStop(ErrorCode)
	{ }
void Protocol::onSocketChanged(Socket *socket)
	{ if (socketToRemove(socket)) socketRemove(socket); }
ErrorCode Protocol::onConnect(const Connection::Handle&, const Address&)
	{ return ERR_CONNECTION_FAILED; }
ErrorCode Protocol::onListen(const Server::Handle&, const Address&)
	{ return ERR_SERVER_LISTENING_FAILED; }