/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuNetSocketOverlappedOperation.NT.cpp Date: 2022-8-17 Author: Reece ***/ #include "Networking.hpp" #include "AuNetSocketOverlappedOperation.hpp" #include #include "AuNetSocket.NT.hpp" #include "AuNetError.hpp" namespace Aurora::IO::Net { SocketOverlappedOperation::SocketOverlappedOperation(bool bMultipleTrigger) : bMultipleTrigger(bMultipleTrigger) { this->pEvent = AuLoop::NewLSEvent(false, true); if (!this->pEvent) { return; } this->overlapped.hEvent = AuReinterpretCast(AuStaticCast(this->pEvent)->GetHandle()); } bool SocketOverlappedOperation::FinishOperation(const AuSPtr &that, const AuSPtr &pWorker, bool bReturnCode) { return this->FinishOperationEx(that, pWorker, bReturnCode, GetLastError()); } bool SocketOverlappedOperation::FinishOperationEx(const AuSPtr &that, const AuSPtr &pWorker, bool bReturnCode, DWORD dwErrorCode) { if (bReturnCode) { this->OnIOComplete(); return true; } else { if (dwErrorCode == ERROR_IO_PENDING) { this->pSocket = that; SysAssert(pWorker->ToProcessor()->StartSimpleLSWatchEx(this->pEvent, AuSPtr(that, this), true)); return true; } else { // ERROR SysPushErrorIO("Couldn't connect [overlapped] (0x{:x})", dwErrorCode); this->uOsError = dwErrorCode; return false; } } } bool SocketOverlappedOperation::IsValid() { return bool(this->pEvent); } void SocketOverlappedOperation::OnIOTick() { if (!this->bMultipleTrigger) { return; } auto pTemp = AuExchange(this->pSocket, {}); if (this->HasFailed()) { this->OnOverlappedFailure(this->ToError()); } else { this->OnOverlappedComplete(); } } void SocketOverlappedOperation::OnIOComplete() { if (this->bMultipleTrigger) { return; } if (AuExchange(this->bHasFlipped, true)) { return; } if (this->HasFailed()) { this->OnOverlappedFailure(this->ToError()); } else { this->OnOverlappedComplete(); } this->pSocket.reset(); } void SocketOverlappedOperation::OnIOFailure() { if (AuExchange(this->bHasFlipped, true)) { return; } this->OnOverlappedFailure(this->ToError()); this->pSocket.reset(); } bool SocketOverlappedOperation::HasFailed() { auto code = this->ToOsError(); return (code != 0) && (code != STATUS_PENDING); } AuUInt SocketOverlappedOperation::ToOsError() { if (this->uOsError) { return this->uOsError; } return this->uOsError ? this->uOsError : this->overlapped.Internal; } bool SocketOverlappedOperation::HasComplete() { if (this->HasFailed()) { return false; } return this->ToOsError() != STATUS_PENDING; } NetError SocketOverlappedOperation::ToError() { NetError error; NetError_SetOsError(error, this->ToOsError()); return error; } }