|
|
71057f |
|
|
|
71057f |
#include <cstring></cstring>
|
|
|
71057f |
|
|
|
71057f |
#include <chrono></chrono>
|
|
|
71057f |
#include <thread></thread>
|
|
|
71057f |
#include <mutex></mutex>
|
|
|
71057f |
|
|
|
71057f |
#include "protocol.h"
|
|
|
71057f |
#include "server.h"
|
|
|
71057f |
|
|
|
71057f |
|
|
|
61c265 |
#define DebugMSG ShowDebugMSG
|
|
|
61c265 |
|
|
|
61c265 |
|
|
|
71057f |
Server::Server():
|
|
|
71057f |
state(STATE_NONE),
|
|
|
71057f |
stateWanted(STATE_NONE),
|
|
|
71057f |
enqueued(false),
|
|
|
51b3f0 |
error(false),
|
|
|
51b3f0 |
closeWaiters(0),
|
|
|
51b3f0 |
finishWaiters(0),
|
|
|
71057f |
address(),
|
|
|
71057f |
addressSize(),
|
|
|
71057f |
protocol(),
|
|
|
71057f |
prev(), next(),
|
|
|
71057f |
queueNext(),
|
|
|
71057f |
connFirst(), connLast(),
|
|
|
71057f |
sockId(-1),
|
|
|
71057f |
stateLocal()
|
|
|
71057f |
{ }
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
Server::~Server() {
|
|
|
61c265 |
assert(state == STATE_NONE || state == STATE_FINISHED);
|
|
|
71057f |
closeWait();
|
|
|
71057f |
while(finishWaiters > 0) std::this_thread::yield();
|
|
|
71057f |
}
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
bool Server::open(Protocol &protocol, void *address, size_t addressSize) {
|
|
|
61c265 |
if (!address || !addressSize || addressSize > MAX_ADDR_SIZE)
|
|
|
61c265 |
{ DebugMSG("bad args"); return false; }
|
|
|
71057f |
|
|
|
71057f |
State s = state;
|
|
|
71057f |
do {
|
|
|
61c265 |
if (s != STATE_NONE && s != STATE_FINISHED)
|
|
|
61c265 |
{ DebugMSG("already open or in closing state"); return false; }
|
|
|
71057f |
} while(!state.compare_exchange_weak(s, STATE_OPENING));
|
|
|
71057f |
if (s == STATE_FINISHED) while(finishWaiters > 0) std::this_thread::yield();
|
|
|
71057f |
|
|
|
71057f |
ReadLock lock(protocol.stateProtector);
|
|
|
71057f |
Protocol::State ps = protocol.state;
|
|
|
61c265 |
if (ps < Protocol::STATE_INITIALIZING || ps >= Protocol::STATE_CLOSE_REQ)
|
|
|
61c265 |
{ DebugMSG("protocol is closed"); state = STATE_NONE; return false; }
|
|
|
71057f |
|
|
|
71057f |
memcpy(this->address, address, addressSize);
|
|
|
71057f |
this->addressSize = addressSize;
|
|
|
71057f |
|
|
|
71057f |
this->protocol = &protocol;
|
|
|
71057f |
state = STATE_INITIALIZING;
|
|
|
71057f |
if (!enqueued.exchange(true)) protocol.srvQueue.push(*this);
|
|
|
71057f |
protocol.wakeup();
|
|
|
71057f |
return true;
|
|
|
71057f |
}
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
void Server::wantState(State state, bool error) {
|
|
|
71057f |
ReadLock lock(stateProtector);
|
|
|
71057f |
State s = this->state;
|
|
|
71057f |
if (s <= STATE_OPENING || s >= STATE_CLOSING_CONNECTIONS || s >= state) return;
|
|
|
71057f |
|
|
|
71057f |
State sw = stateWanted;
|
|
|
71057f |
do {
|
|
|
61c265 |
if (sw >= state) return;
|
|
|
71057f |
} while(!stateWanted.compare_exchange_weak(sw, state));
|
|
|
71057f |
if (error) { error = false; this->error.compare_exchange_strong(error, true); }
|
|
|
71057f |
if (!enqueued.exchange(true)) protocol->srvQueue.push(*this);
|
|
|
71057f |
protocol->wakeup();
|
|
|
71057f |
}
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
void Server::closeReq()
|
|
|
71057f |
{ wantState(STATE_CLOSE_REQ, false); }
|
|
|
71057f |
void Server::close(bool error)
|
|
|
71057f |
{ wantState(STATE_CLOSING_CONNECTIONS, error); }
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
void Server::closeWait(unsigned long long timeoutUs, bool withReq) {
|
|
|
71057f |
stateProtector.lock();
|
|
|
71057f |
State s = state;
|
|
|
71057f |
if (s <= STATE_OPENING || s >= STATE_FINISHED)
|
|
|
71057f |
{ stateProtector.unlock(); return; }
|
|
|
71057f |
|
|
|
71057f |
if (s == STATE_CLOSED) {
|
|
|
71057f |
finishWaiters++;
|
|
|
71057f |
stateProtector.unlock();
|
|
|
71057f |
} else {
|
|
|
71057f |
if (withReq && s < STATE_CLOSE_REQ) closeReq();
|
|
|
71057f |
closeWaiters++;
|
|
|
71057f |
stateProtector.unlock();
|
|
|
71057f |
|
|
|
71057f |
std::mutex fakeMutex;
|
|
|
71057f |
{
|
|
|
71057f |
std::unique_lock<std::mutex> fakeLock(fakeMutex);</std::mutex>
|
|
|
71057f |
if (timeoutUs && s < STATE_CLOSING) {
|
|
|
71057f |
std::chrono::steady_clock::time_point t
|
|
|
71057f |
= std::chrono::steady_clock::now()
|
|
|
71057f |
+ std::chrono::microseconds(timeoutUs);
|
|
|
71057f |
while(s < STATE_CLOSED) {
|
|
|
71057f |
if (t <= std::chrono::steady_clock::now()) { close(true); break; }
|
|
|
71057f |
closeCondition.wait_until(fakeLock, t);
|
|
|
71057f |
s = state;
|
|
|
71057f |
}
|
|
|
71057f |
}
|
|
|
71057f |
if (s < STATE_CLOSING) close(true);
|
|
|
71057f |
while(s < STATE_CLOSED) {
|
|
|
71057f |
closeCondition.wait(fakeLock);
|
|
|
71057f |
s = state;
|
|
|
71057f |
}
|
|
|
71057f |
}
|
|
|
71057f |
|
|
|
71057f |
finishWaiters++;
|
|
|
71057f |
closeWaiters--;
|
|
|
71057f |
}
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
while(s != STATE_FINISHED) { std::this_thread::yield(); s = state; }
|
|
|
71057f |
|
|
|
71057f |
finishWaiters--;
|
|
|
71057f |
}
|
|
|
71057f |
|
|
|
71057f |
|
|
|
71057f |
void Server::onOpeningError() { }
|
|
|
71057f |
void Server::onOpen() { }
|
|
|
51b3f0 |
Connection* Server::onConnect(const void*, size_t) { return nullptr; }
|
|
|
71057f |
void Server::onDisconnect(Connection*, bool) { }
|
|
|
71057f |
void Server::onCloseReqested() { }
|
|
|
71057f |
void Server::onClose(bool) { }
|
|
|
71057f |
|