/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuNetSocketServer.cpp Date: 2022-8-22 Author: Reece ***/ #include "Networking.hpp" #include "AuNetSocketServer.hpp" #include "AuNetEndpoint.hpp" #include "AuNetError.hpp" #include "AuNetWorker.hpp" namespace Aurora::IO::Net { SocketServer::SocketServer(NetInterface *pInterface, NetWorker *pWorker, const AuSPtr &pDriver, const AuSPtr &pFactory, AuUInt32 uMaxConnections, AuUInt32 uDefaultInputStreamSize, bool bMultiThreaded) : Socket(pInterface, pWorker, AuSPtr{}, -1), pDriver_(pDriver), pFactory_(pFactory), uMaxConnections_(uMaxConnections), uDefaultInputStreamSize(uDefaultInputStreamSize), bMultiThreaded(bMultiThreaded) { } void SocketServer::Init(const NetEndpoint &localAddress) { if (!this->InitSocket(localAddress)) { this->SendErrorNoStream(ENetworkError::eInitSocketFailed); return; } } void SocketServer::Listen(const NetEndpoint &localAddress, bool bBind, bool bListen) { if (this->bHasErrored_) { return; } this->localEndpoint_ = localAddress; this->endpointSize_ = OptimizeEndpoint(this->localEndpoint_); if (!this->endpointSize_) { this->SendErrorNoStream(ENetworkError::eBadAddress); return; } if (bBind) { if (!this->ImplBind()) { this->SendErrorNoStream(ENetworkError::eUnknown); return; } } if (bListen) { if (!this->ImplListen()) { this->SendErrorNoStream(ENetworkError::eUnknown); return; } } if ((!AuBuild::kIsNtDerived) || // NT accept doesnt need it (this->localEndpoint_.transportProtocol == ETransportProtocol::eProtocolUDP)) // only the recvfrom loop does { if (!this->MakeNonblocking()) { NetError error; NetError_SetCurrent(error); this->SendErrorNoStream(error); return; } } if (this->pDriver_) { try { this->pDriver_->OnBind(); } catch (...) { SysPushErrorCatch(); this->SendErrorNoStream(ENetworkError::eAsyncError); } } } void SocketServer::Accept() { if (this->bHasErrored_) { return; } if (!this->BeginAcceptLoop()) { this->SendErrorNoStream(NetError(ENetworkError::eCantAccept)); return; } } ///////////////////////////////////////////////////////////////////////////////////// // ISocketServer AuSPtr SocketServer::GetServerDriver() { return this->pDriver_; } AuSPtr SocketServer::GetFactory() { return this->pFactory_; } ///////////////////////////////////////////////////////////////////////////////////// // ISocketDriver bool SocketServer::OnPreestablish(const AuSPtr &pInforming) { return true; } void SocketServer::OnEstablish() { } void SocketServer::OnStreamUpdated() { } void SocketServer::OnFatalErrorReported(const NetError &error) { if (this->pDriver_) { this->pDriver_->OnFatalErrorReported(error); } } void SocketServer::OnEnd() { } void SocketServer::OnFinalize() { if (this->pDriver_) { this->pDriver_->OnFinalize(); } } ///////////////////////////////////////////////////////////////////////////////////// // SocketBase void SocketServer::FinishConstructAsync() { } void SocketServer::Shutdown(bool bNow) { Socket::Shutdown(bNow); } void SocketServer::Destroy() { Socket::Destroy(); } void SocketServer::ScheduleAcceptTick() { // WARNING: Accepts cannot be on the same tick as on-accept // We must reschedule to prevent add-source, under on tick callback, prior to removal eval of the very same event handle // (loopqueue constraint) auto shared = AuDynamicCast(this->SharedFromThis()); // C++ is cringe. cant static-up-cast a virtual base if (!this->ToWorkerEx()->TryScheduleInternalTemplate([that = shared](const AuSPtr> &info) { that->DoNonblockingReadTick(); }, AuSPtr>{})) { this->SendErrorBeginShutdown({}); } } bool SocketServer::PrepareConnectOperations() { return false; } bool SocketServer::UpdateLocalEndpoint() { socklen_t iLen { (int)this->endpointSize_ }; if (::getsockname(this->osHandle_, (sockaddr *)this->localEndpoint_.hint, &iLen) == -1) { SysPushErrorIO(); return false; } DeoptimizeEndpoint(this->localEndpoint_); return true; } bool SocketServer::UpdateRemoteEndpoint() { return false; } bool SocketServer::TryBindAnyLocal() { return false; } bool SocketServer::ConnectOverlapped() { return false; } bool SocketServer::ConnectNonblocking() { return false; } bool SocketServer::ConnectBlocking() { return false; } }