www.pudn.com > IOCPNet_Demo.zip > TCPFunc.cpp
////////////////////////////////////////////////////////////////////////////////////////////////////
// Module Name:
// TCPFunc.cpp
// Author:
// Chun-Hyok, Chong.
// Description:
// It provides the basic network functions handle reading/writing/packaging rough(?) data.
////////////////////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Workframe.h"
#include "TCPFunc.h"
#include "WorkframeReturnCode.h"
#include "SafeDynMem.h"
#ifdef BLOCK
#undef BLOCK
#endif // BLOCK
#define READ_UNIT_SIZE 512 // less than general MTU size.
#define WRITE_UNIT_SIZE 512 // less than general MTU size.
#define MSG_LEN_INFO_SIZE 4
#define MAX_NET_TRIAL 30
#define CHECK_ALIVE_VALUE -987654321
#define MAX_RECV_AGAIN 3
int TCPRead(SOCKET Socket, char *Buffer, DWORD BufferSize, DWORD TimeoutMilli, DWORD *ErrorCode)
{
BOOL bError;
int ReturnCode;
char LenInfo[MSG_LEN_INFO_SIZE];
int RetLen;
char ReadBuff[READ_UNIT_SIZE];
DWORD CopyingSize;
int ResRecv;
int Timeout;
char *pReadingPoint;
int ToReadSize;
int UnitReadSize;
int TimeoutOld;
int OutLen;
int LoopCount;
int RecvAgainCount;
bError = 0;
ReturnCode = RET_FAIL;
TimeoutOld = -1;
if (0 > Socket || 0 == ErrorCode)
{
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
*ErrorCode = 0;
OutLen = sizeof (TimeoutOld);
if (SOCKET_ERROR == getsockopt(Socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&TimeoutOld, &OutLen))
{
*ErrorCode = WSAGetLastError();
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
Timeout = TimeoutMilli; // Assigning is due to input the address of the Timeout. 0 = infinite.
if (SOCKET_ERROR == setsockopt(Socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&Timeout, sizeof (Timeout)))
{
*ErrorCode = WSAGetLastError();
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
if (0 == Buffer || 0 == BufferSize)
{
RecvAgainNew:
RecvAgainCount = 0;
RecvAgain:
ZeroMemory(LenInfo, sizeof (LenInfo));
ResRecv = recv(Socket, LenInfo, sizeof (LenInfo), MSG_PEEK);
if (SOCKET_ERROR == ResRecv)
{
*ErrorCode = WSAGetLastError();
if (WSAECONNRESET == *ErrorCode || WSAECONNABORTED == *ErrorCode || WSAESHUTDOWN == *ErrorCode || WSAENETRESET == *ErrorCode)
{
bError = 1;
ReturnCode = RET_SOCKET_SHUT_DOWN;
goto ErrHand;
}
else if (WSAETIMEDOUT == *ErrorCode)
{
bError = 1;
ReturnCode = RET_TIMEOUT;
goto ErrHand;
}
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
else if (0 == ResRecv) // socket closed.
{
bError = 1;
ReturnCode = RET_SOCKET_CLOSED;
goto ErrHand;
}
else if (sizeof (LenInfo) > ResRecv)
{
if (MAX_RECV_AGAIN <= RecvAgainCount)
{
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
RecvAgainCount++;
goto RecvAgain;
}
else if (sizeof (LenInfo) != ResRecv)
{
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
else
{
memcpy(&RetLen, LenInfo, sizeof (LenInfo));
if (CHECK_ALIVE_VALUE == RetLen)
{
ResRecv = recv(Socket, LenInfo, sizeof (LenInfo), 0); // recv() may return arbitrary value. <- but it can handle the size of data as much as MTU.
if (SOCKET_ERROR == ResRecv)
{
*ErrorCode = WSAGetLastError();
if (WSAECONNRESET == *ErrorCode || WSAECONNABORTED == *ErrorCode || WSAESHUTDOWN == *ErrorCode || WSAENETRESET == *ErrorCode)
{
bError = 1;
ReturnCode = RET_SOCKET_SHUT_DOWN;
goto ErrHand;
}
else if (WSAETIMEDOUT == *ErrorCode)
{
bError = 1;
ReturnCode = RET_TIMEOUT;
goto ErrHand;
}
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
else if (0 == ResRecv) // socket closed.
{
bError = 1;
ReturnCode = RET_SOCKET_CLOSED;
goto ErrHand;
}
goto RecvAgainNew;
}
else if (0 >= RetLen)
{
bError = 1;
ReturnCode = RET_SOCKET_NO_ORDER;
goto ErrHand;
}
else
{
bError = 0;
ReturnCode = RetLen;
goto ErrHand;
}
}
}
else // read the data.
{
CopyingSize = 0;
LoopCount = 0;
ToReadSize = BufferSize + sizeof (LenInfo);
while (1)
{
if (sizeof (ReadBuff) <= ToReadSize)
{
UnitReadSize = sizeof (ReadBuff);
}
else
{
UnitReadSize = ToReadSize;
}
ZeroMemory(ReadBuff, sizeof (ReadBuff));
pReadingPoint = ReadBuff;
ResRecv = recv(Socket, pReadingPoint, UnitReadSize, 0);
if (SOCKET_ERROR == ResRecv)
{
*ErrorCode = WSAGetLastError();
if (WSAECONNRESET == *ErrorCode || WSAECONNABORTED == *ErrorCode || WSAESHUTDOWN == *ErrorCode || WSAENETRESET == *ErrorCode)
{
bError = 1;
ReturnCode = RET_SOCKET_SHUT_DOWN;
goto ErrHand;
}
else if (WSAETIMEDOUT == *ErrorCode)
{
bError = 1;
ReturnCode = RET_TIMEOUT;
goto ErrHand;
}
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
else if (0 == ResRecv) // socket closed.
{
bError = 1;
ReturnCode = RET_SOCKET_CLOSED;
goto ErrHand;
}
else
{
if (0 == LoopCount)
{
memcpy(Buffer + CopyingSize, ReadBuff + sizeof (LenInfo), ResRecv - sizeof (LenInfo));
CopyingSize += ResRecv - sizeof (LenInfo);
}
else
{
memcpy(Buffer + CopyingSize, ReadBuff, ResRecv);
CopyingSize += ResRecv;
}
LoopCount++;
ToReadSize -= ResRecv;
if (0 >= ToReadSize)
{
break;
}
}
}
bError = 0;
ReturnCode = CopyingSize;
goto ErrHand;
}
ErrHand:
if (-1 != TimeoutOld)
{
Timeout = TimeoutOld;
if (SOCKET_ERROR == setsockopt(Socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&Timeout, sizeof (Timeout)))
{
*ErrorCode = WSAGetLastError();
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
}
return ReturnCode;
} // TCPRead()
int TCPWrite(SOCKET Socket, char *Buffer, DWORD BufferSize, DWORD TimeoutMilli, DWORD *ErrorCode)
{
BOOL bError;
int ReturnCode;
DWORD WritingSize;
int ResSend;
int Timeout;
int TimeoutOld;
int OutLen;
int ToSendSize;
int ToSendSizeUnit;
int RemainedUnit;
int Loop;
int SendingNumber;
char *pIndex;
char WriteBuf[WRITE_UNIT_SIZE];
char *pIndexUnit;
bError = 0;
ReturnCode = RET_FAIL;
TimeoutOld = -1;
if (0 > Socket || 0 == Buffer || 0 == BufferSize || 0 == ErrorCode)
{
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
*ErrorCode = 0;
OutLen = sizeof (TimeoutOld);
if (SOCKET_ERROR == getsockopt(Socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&TimeoutOld, &OutLen))
{
*ErrorCode = WSAGetLastError();
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
Timeout = TimeoutMilli; // Assigning is due to input the address of the Timeout. 0 = infinite.
if (SOCKET_ERROR == setsockopt(Socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&Timeout, sizeof (Timeout)))
{
*ErrorCode = WSAGetLastError();
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
SendingNumber = ((BufferSize + sizeof (BufferSize)) / WRITE_UNIT_SIZE) + ((0 != ((BufferSize + sizeof (BufferSize)) % WRITE_UNIT_SIZE)) ? 1 : 0);
WritingSize = 0;
pIndex = Buffer;
ToSendSize = BufferSize;
for (Loop = 0; Loop < SendingNumber; Loop++)
{
if (0 == Loop)
{
ZeroMemory(WriteBuf, sizeof (WriteBuf));
ToSendSizeUnit = ((WRITE_UNIT_SIZE - sizeof (BufferSize)) > ToSendSize) ? ToSendSize : WRITE_UNIT_SIZE - sizeof (BufferSize);
memcpy(WriteBuf, &BufferSize, sizeof (BufferSize));
memcpy(WriteBuf + sizeof (BufferSize), pIndex, ToSendSizeUnit);
pIndex += ToSendSizeUnit;
ToSendSize -= ToSendSizeUnit;
ToSendSizeUnit += sizeof (BufferSize); // compensation.
}
else
{
ZeroMemory(WriteBuf, sizeof (WriteBuf));
ToSendSizeUnit = (WRITE_UNIT_SIZE > ToSendSize) ? ToSendSize : WRITE_UNIT_SIZE;
memcpy(WriteBuf, pIndex, ToSendSizeUnit);
pIndex += ToSendSizeUnit;
ToSendSize -= ToSendSizeUnit;
}
RemainedUnit = ToSendSizeUnit;
pIndexUnit = WriteBuf;
while (0 < RemainedUnit)
{
ResSend = send(Socket, pIndexUnit, RemainedUnit, 0); // send() operates as all or nothing.
if (SOCKET_ERROR == ResSend)
{
*ErrorCode = WSAGetLastError();
if (WSAECONNRESET == *ErrorCode || WSAECONNABORTED == *ErrorCode || WSAESHUTDOWN == *ErrorCode || WSAENETRESET == *ErrorCode)
{
bError = 1;
ReturnCode = RET_SOCKET_SHUT_DOWN;
goto ErrHand;
}
else if (WSAETIMEDOUT == *ErrorCode)
{
bError = 1;
ReturnCode = RET_TIMEOUT;
goto ErrHand;
}
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
else if (0 == ResSend) // socket closed.
{
bError = 1;
ReturnCode = RET_SOCKET_CLOSED;
goto ErrHand;
}
else if (ResSend == RemainedUnit) // the normal case.
{
WritingSize += ResSend;
RemainedUnit -= ResSend;
}
else if (ResSend > RemainedUnit)
{
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
else if (ResSend < RemainedUnit)
{
WritingSize += ResSend;
RemainedUnit -= ResSend;
pIndexUnit += ResSend;
}
else // what? error.
{
bError = 1;
ReturnCode = RET_FAIL;
goto ErrHand;
}
}
}
ErrHand:
if (-1 != TimeoutOld)
{
Timeout = TimeoutOld;
if (SOCKET_ERROR == setsockopt(Socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&Timeout, sizeof (Timeout)))
{
*ErrorCode = WSAGetLastError();
bError = 1;
ReturnCode = RET_FAIL;
}
}
if (1 == bError)
{
return ReturnCode;
}
ReturnCode = WritingSize - sizeof (BufferSize);
return ReturnCode;
} // TCPWrite()