/* * Copyright: JessMA Open Source (ldcsaa@gmail.com) * * Author : Bruce Liang * Website : https://github.com/ldcsaa * Project : https://github.com/ldcsaa/HP-Socket * Blog : http://www.cnblogs.com/ldcsaa * Wiki : http://www.oschina.net/p/hp-socket * QQ Group : 44636872, 75375912 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "SocketHelper.h" /* Pack Data Info */ template struct TPackInfo { bool header; DWORD length; B* pBuffer; static TPackInfo* Construct(B* pbuf = nullptr, bool head = true, DWORD len = sizeof(DWORD)) { return new TPackInfo(pbuf, head, len); } static void Destruct(TPackInfo* pPackInfo) { if(pPackInfo) delete pPackInfo; } TPackInfo(B* pbuf = nullptr, bool head = true, DWORD len = sizeof(DWORD)) : header(head), length(len), pBuffer(pbuf) { } void Reset() { header = true; length = sizeof(DWORD); pBuffer = nullptr; } }; typedef TPackInfo TBufferPackInfo; BOOL AddPackHeader(const WSABUF * pBuffers, int iCount, unique_ptr& buffers, DWORD dwMaxPackSize, USHORT usPackHeaderFlag, DWORD& dwHeader); template EnFetchResult FetchBuffer(B* pBuffer, BYTE* pData, int iLength) { ASSERT(pBuffer != nullptr); ASSERT(pData != nullptr && iLength > 0); EnFetchResult result = FR_OK; if(pBuffer->Length() >= iLength) pBuffer->Fetch(pData, iLength); else result = FR_LENGTH_TOO_LONG; return result; } template EnFetchResult PeekBuffer(B* pBuffer, BYTE* pData, int iLength) { ASSERT(pBuffer != nullptr); ASSERT(pData != nullptr && iLength > 0); EnFetchResult result = FR_OK; if(pBuffer->Length() >= iLength) pBuffer->Peek(pData, iLength); else result = FR_LENGTH_TOO_LONG; return result; } template EnHandleResult ParsePack(T* pThis, TPackInfo* pInfo, B* pBuffer, S* pSocket, DWORD dwMaxPackSize, USHORT usPackHeaderFlag) { EnHandleResult rs = HR_OK; int required = pInfo->length; int remain = pBuffer->Length(); while(remain >= required) { if(pSocket->IsPaused()) break; remain -= required; CBufferPtr buffer(required); pBuffer->Fetch(buffer, (int)buffer.Size()); if(pInfo->header) { DWORD header = ::HToLE32(*((DWORD*)(byte*)buffer)); if(usPackHeaderFlag != 0) { USHORT flag = (USHORT)(header >> TCP_PACK_LENGTH_BITS); if(flag != usPackHeaderFlag) { ::SetLastError(ERROR_INVALID_DATA); return HR_ERROR; } } DWORD len = header & TCP_PACK_LENGTH_MASK; if(len == 0 || len > dwMaxPackSize) { ::SetLastError(ERROR_BAD_LENGTH); return HR_ERROR; } required = len; } else { rs = pThis->DoFireSuperReceive(pSocket, (const BYTE*)buffer, (int)buffer.Size()); if(rs == HR_ERROR) return rs; required = sizeof(DWORD); } pInfo->header = !pInfo->header; pInfo->length = required; } return rs; } template EnHandleResult ParsePack(T* pThis, TPackInfo* pInfo, B* pBuffer, S* pSocket, DWORD dwMaxPackSize, USHORT usPackHeaderFlag, const BYTE* pData, int iLength) { pBuffer->Cat(pData, iLength); return ParsePack(pThis, pInfo, pBuffer, pSocket, dwMaxPackSize, usPackHeaderFlag); } template BOOL ContinueReceive(T* pThis, TSocketObj* pSocketObj, TBufferObj* pBufferObj, EnHandleResult& hr) { int rs = NO_ERROR; for(int i = 0; i < MAX_IOCP_CONTINUE_RECEIVE || MAX_IOCP_CONTINUE_RECEIVE < 0; i++) { if(pSocketObj->paused) break; if(hr != HR_OK && hr != HR_IGNORE) break; pBufferObj->buff.len = pThis->GetSocketBufferSize(); rs = ::NoBlockReceiveNotCheck(pBufferObj); if(rs != NO_ERROR) break; hr = pThis->TriggerFireReceive(pSocketObj, pBufferObj); } if(hr != HR_OK && hr != HR_IGNORE) return FALSE; if(rs != NO_ERROR && rs != WSAEWOULDBLOCK) { if(rs == WSAEDISCON) pThis->AddFreeSocketObj(pSocketObj, SCF_CLOSE); else pThis->CheckError(pSocketObj, SO_RECEIVE, rs); pThis->AddFreeBufferObj(pBufferObj); return FALSE; } return TRUE; } template void ContinueReceiveFrom(T* pThis, TUdpBufferObj* pBufferObj) { int rs; while(TRUE) { pBufferObj->buff.len = pThis->GetMaxDatagramSize(); rs = ::NoBlockReceiveFromNotCheck(pThis->GetListenSocket(), pBufferObj); if(rs != NO_ERROR) break; pThis->ProcessReceiveBufferObj(pBufferObj); } }