#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; }