📄 ioudpmodule.cc
字号:
// IOUDPModule.cc
/*/////////////////////////////////////////////////////////////////////////////
李亦
2006.06.
/*//////////////////////////////////////////////////////////////////////////////
//#include <platforms.h>
#include <winsock.h>
#include "server/strhandle.h"
#include "server/net/IOUDPModule.h"
#include "platform/platformAssert.h"
namespace CS
{
#pragma pack(push,1)
typedef struct __udpsocket
{
SOCKET sock;
SOCKADDR_IN sockAddr;
DWORD dwState;
DWORD dwTime;
char svConnectAddr[256];
__udpsocket *pParent;
__udpsocket **pChildSockets;
} UDPSOCKET;
typedef struct _tagUDPHeader
{
DWORD dwFlags;
} UDPHDR;
#pragma pack(pop)
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//CS_IOHANDLER IOUDPModule::m_ioHandler;
static IOUDPModule gs_udpIOModule;
IOUDPModule::IOUDPModule()
{
m_ioHandler.pGetError = GetError;
m_ioHandler.pClose = Close;
m_ioHandler.pConnect = Connect;
m_ioHandler.pFree = Free;
m_ioHandler.pListen = Listen;
m_ioHandler.pCheckAccept = CheckAccept;
m_ioHandler.pCheckSend = CheckSend;
m_ioHandler.pCheckRecv = CheckRecv;
m_ioHandler.pAccept = Accept;
m_ioHandler.pQuery = Query;
m_ioHandler.pRecv = Recv;
m_ioHandler.pInsert = Insert;
m_ioHandler.pRemove = Remove;
m_ioHandler.pSend = Send;
m_ioHandler.pRecvEx = RecvEx;
m_ioHandler.pSendEx = SendEx;
m_ioHandler.pGetConnectAddr = GetConnectAddr;
m_ioHandler.pGetNetAddress = GetNetAddress;
}
IOUDPModule::~IOUDPModule()
{
}
CS_IOHANDLER* IOUDPModule::GetIOHandler()
{
return &gs_udpIOModule.m_ioHandler;
//return &m_ioHandler;
}
INT RPGAPI IOUDPModule::GetError(void *data)
{
data;
return WSAGetLastError();
}
int RPGAPI IOUDPModule::Insert()
{
// Initialize Winsock 1.1
WSADATA wsaData;
if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0)
return E_IOFAILED;
if(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
return E_IOFAILED;
}
return E_IOOK;
}
int RPGAPI IOUDPModule::Remove()
{
// Clean up Winsock 1.1
WSACleanup();
return E_IOOK;
}
void * RPGAPI IOUDPModule::Listen(char *svTarget)
{
UDPSOCKET *pUDPSock;
// Get listen port
int nPort = 0;
in_addr bindAddr;
bindAddr.S_un.S_addr = INADDR_ANY;
if(svTarget == NULL)
{
//nPort=CConfig::GetCfgNum(CConfig::m_szUDPIOConfig,"Default Port");
}
else if(lstrcmpi(svTarget,"RANDOM") != 0)
{
char svAdr[ADDR_MAX],
*svPort;
lstrcpyn(svAdr,svTarget,ADDR_MAX);
svPort=BreakString(svAdr,":");
if(svPort == NULL)
{
nPort = atoi(svAdr);
}
else
{
bindAddr.S_un.S_addr = inet_addr(svAdr);
nPort = atoi(svPort);
}
}
// Create listener socket
SOCKET sock;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sock == INVALID_SOCKET)
return NULL;
// Bind socket
SOCKADDR_IN saddr;
dMemset(&saddr,0,sizeof(SOCKADDR_IN));
saddr.sin_addr.S_un.S_addr = INADDR_ANY;
saddr.sin_family = AF_INET;
saddr.sin_port = htons((WORD)nPort);
if(bind(sock,(SOCKADDR*) &saddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
closesocket(sock);
return NULL;
}
int namelen = sizeof(SOCKADDR_IN);
getsockname(sock, (SOCKADDR*)&saddr, &namelen);
// Allocate state structure
pUDPSock = (UDPSOCKET *)dMalloc(sizeof(UDPSOCKET));
if(pUDPSock == NULL)
{
closesocket(sock);
return NULL;
}
// Fill in state structure
dMemset(&(pUDPSock->sockAddr), 0, sizeof(SOCKADDR_IN));
pUDPSock->sock = sock;
pUDPSock->dwState = US_LISTEN;
pUDPSock->dwTime = 0; // No timeout on listening sockets
pUDPSock->pParent = NULL;
pUDPSock->pChildSockets = (UDPSOCKET **)dMalloc(MAX_UDP_CHILDREN * sizeof(UDPSOCKET *));
if(pUDPSock->pChildSockets == NULL)
{
dFree(pUDPSock);
closesocket(sock);
return NULL;
}
int i;
for(i = 0; i < MAX_UDP_CHILDREN; i++)
{
pUDPSock->pChildSockets[i] = NULL;
}
// Fill in connect address
if(bindAddr.S_un.S_addr == INADDR_ANY)
{
char svHostName[ADDR_MAX];
hostent *he;
in_addr *pAddr;
gethostname(svHostName,ADDR_MAX);
he = gethostbyname(svHostName);
if(he)
{
pAddr = (in_addr *)he->h_addr_list[0];
wsprintf(pUDPSock->svConnectAddr,"%u.%u.%u.%u:%u",pAddr->S_un.S_un_b.s_b1,pAddr->S_un.S_un_b.s_b2,pAddr->S_un.S_un_b.s_b3,pAddr->S_un.S_un_b.s_b4,ntohs(saddr.sin_port));
}
else
{
lstrcpyn(pUDPSock->svConnectAddr,"No Connect Addr",ADDR_MAX);
}
}
else
{
lstrcpyn(pUDPSock->svConnectAddr,svTarget,ADDR_MAX);
}
return pUDPSock;
}
BOOL RPGAPI IOUDPModule::CheckAccept(void *data)
{
// Check to see if this is a listening socket
return TRUE;
}
void * RPGAPI IOUDPModule::Accept(void *data, char *svAddr, int nMaxLen)
{
// Check for incoming data WSAENOTCONN Net
int nLen(0);
UDPSOCKET *pUDPSock = (UDPSOCKET*)data;
if(pUDPSock->dwState != US_LISTEN)
return NULL;
if(ioctlsocket(pUDPSock->sock, FIONREAD, (DWORD*)&nLen) < 0)
return NULL;
if(nLen > 0)
{
// Allocate memory for packet
SOCKADDR_IN sockAddrFrom;
int nFromLen = sizeof(SOCKADDR_IN);
BYTE *buf = (BYTE *)dMalloc(nLen);
if(buf == NULL)
return NULL;
// Peek the message
nLen = recvfrom(pUDPSock->sock, (char*)buf, nLen, MSG_PEEK, (SOCKADDR *)&sockAddrFrom, &nFromLen);
if(nLen < 0)
{
dFree(buf);
return NULL;
}
// Check to see if this is a new connection
int i;
for(i = 0;i < MAX_UDP_CHILDREN; i++)
{
if(pUDPSock->pChildSockets[i])
{
if(memcmp(&(pUDPSock->pChildSockets[i]->sockAddr), &sockAddrFrom, sizeof(SOCKADDR_IN)) == 0)
{
// Woops, it'sock for another child socket
dFree(buf);
return NULL;
}
}
}
// Check to make sure it isn't a 'close' message
if( (((UDPHDR *)buf)->dwFlags & UF_RST) == UF_RST )
{
// If so, it isn't for a child connection, so we throw it away.
nLen = recvfrom(pUDPSock->sock, (char *)buf,nLen,0,(SOCKADDR *)&sockAddrFrom,&nFromLen);
dFree(buf);
return NULL;
}
dFree(buf);
// Find connections table slot
int nTimeout = -1;
DWORD dwTimeDiff,
dwLastTimeDiff = 0;
for(i = 0;i < MAX_UDP_CHILDREN; i++)
{
if(pUDPSock->pChildSockets[i] == NULL)
break;
dwTimeDiff = (GetTickCount() - pUDPSock->pChildSockets[i]->dwTime);
if(dwTimeDiff > dwLastTimeDiff)
{
nTimeout = i;
dwLastTimeDiff = dwTimeDiff;
}
}
// Clean out connections table if things are full
if(i == MAX_UDP_CHILDREN)
{
if(dwLastTimeDiff >= UDP_TIMEOUT)
{
UDPSOCKET *pios = pUDPSock->pChildSockets[nTimeout];
pUDPSock->pChildSockets[nTimeout] = NULL;
closesocket(pios->sock);
pios->dwState = 0;
i = nTimeout;
}
else
{
// Reject accept if things don't work
return NULL;
}
}
// Create accepted socket
UDPSOCKET *pIOSockNew;
pIOSockNew = (UDPSOCKET *)dMalloc(sizeof(UDPSOCKET));
if(pIOSockNew == NULL)
return NULL;
// Add to connections table
pUDPSock->pChildSockets[i] = pIOSockNew;
// Fill in accepted socket
DuplicateHandle(GetCurrentProcess(), (HANDLE)(pUDPSock->sock), GetCurrentProcess(), (HANDLE *)&(pIOSockNew->sock),0,FALSE,DUPLICATE_SAME_ACCESS);
pIOSockNew->sockAddr = sockAddrFrom;
pIOSockNew->dwState = US_CONNECTED;
pIOSockNew->dwTime = GetTickCount();
pIOSockNew->pParent = pUDPSock;
pIOSockNew->pChildSockets = NULL; // No child sockets for accepted sockets
if(nMaxLen > 16)
{
wsprintf(svAddr,"%3u.%3u.%3u.%3u",
sockAddrFrom.sin_addr.S_un.S_un_b.s_b1,
sockAddrFrom.sin_addr.S_un.S_un_b.s_b2,
sockAddrFrom.sin_addr.S_un.S_un_b.s_b3,
sockAddrFrom.sin_addr.S_un.S_un_b.s_b4);
}
return pIOSockNew;
}
return NULL;
}
void * RPGAPI IOUDPModule::Connect(char *svTarget)
{
// Create socket
SOCKET sock;
sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(sock == INVALID_SOCKET)
return NULL;
// Get target port
int nPort;
char svHost[256],
*ptr;
lstrcpyn(svHost,svTarget,256);
for(ptr = svHost; ((*ptr)!=':') && ((*ptr)!=NULL); ptr++);
if((*ptr)==':')
{
*ptr = '\0';
ptr++;
nPort = atoi(ptr);
}
else
return NULL;//nPort=CConfig::GetCfgNum(CConfig::m_szUDPIOConfig,"Default Port");
// Resolve hostname
DWORD addr;
addr = inet_addr(svHost);
if(addr == INADDR_NONE)
{
hostent *he = gethostbyname(svHost);
if(he == NULL)
{
closesocket(sock);
return NULL;
}
addr = *(DWORD *)(he->h_addr_list[0]);
}
// Create socket address
SOCKADDR_IN saddr;
dMemset(&saddr,0,sizeof(SOCKADDR_IN));
saddr.sin_addr.S_un.S_addr = addr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons((WORD)nPort);
// Allocate internal state structure
UDPSOCKET *pUDPSock = (UDPSOCKET *)dMalloc(sizeof(UDPSOCKET));
if(pUDPSock == NULL)
{
closesocket(sock);
return NULL;
}
// Always 'connected' since there is no handshake
pUDPSock->sock = sock;
pUDPSock->sockAddr= saddr;
pUDPSock->dwState = US_CONNECTED;
pUDPSock->dwTime = GetTickCount();
pUDPSock->pParent = NULL;
pUDPSock->pChildSockets = NULL; // No child sockets for source socket
return pUDPSock;
}
int RPGAPI IOUDPModule::Close(void *ios)
{
int i;
UDPSOCKET *pUDPSock = (UDPSOCKET *)ios;
if(pUDPSock == NULL)
return E_IOFAILED;
if((pUDPSock->dwState & US_CONNECTED) || (pUDPSock->dwState & US_LISTEN))
{
if(pUDPSock->dwState & US_CONNECTED)
{
// Send close packet (don't care if it makes it over though)
UDPHDR hdr;
hdr.dwFlags = UF_RST;
sendto(pUDPSock->sock,
(char *)&hdr,
sizeof(UDPHDR),
0,
(SOCKADDR *)&(pUDPSock->sockAddr),
sizeof(SOCKADDR_IN));
if(pUDPSock->pParent != NULL)
{
for(i = 0; i < MAX_UDP_CHILDREN; i++)
{
if(pUDPSock->pParent->pChildSockets[i] == pUDPSock)
{
pUDPSock->pParent->pChildSockets[i]=NULL;
}
}
}
}
if(pUDPSock->dwState & US_LISTEN)
{
for(i = 0;i < MAX_UDP_CHILDREN; i++)
{
if(pUDPSock->pChildSockets[i] != NULL)
{
pUDPSock->pChildSockets[i]->pParent = NULL;
}
}
dFree(pUDPSock->pChildSockets);
}
closesocket(pUDPSock->sock);
}
dFree(pUDPSock);
return E_IOOK;
}
char * RPGAPI IOUDPModule::Query()
{
return "UDPIO: Back Orifice UDP IO Module v1.0";
}
BOOL RPGAPI IOUDPModule::CheckRecv(void *data)
{
return TRUE;
}
int RPGAPI IOUDPModule::Recv(void *data, BYTE *pInData, int *pnInDataLen)
{
AssertWarn(0,"RecvEx调整此处逻辑");
return RecvEx(data,&pInData, pnInDataLen);
}
int RPGAPI IOUDPModule::RecvEx(void *data, BYTE **pInData, int *pnInDataLen)
{
UDPSOCKET *pUDPSock = (UDPSOCKET *)data;
// Ensure socket is connected
if(pUDPSock->dwState != US_CONNECTED)
return E_IOFAILED;
// Check for incoming data
int nLen(0);
ioctlsocket(pUDPSock->sock, FIONREAD, (DWORD*)&nLen);
if(nLen >= sizeof(UDPHDR))
{
// Allocate buffer for data
BYTE *buf=(BYTE *)dMalloc(nLen);
if(buf == NULL)
{
*pInData = NULL;
*pnInDataLen= 0;
return E_IOFAILED;
}
// Peek at data
SOCKADDR_IN sockAddrFrom;
int nFromLen = sizeof(SOCKADDR_IN);
INT lenret;
lenret = recvfrom(pUDPSock->sock,(char *)buf,nLen,MSG_PEEK,(sockaddr *)&sockAddrFrom,&nFromLen);
if(lenret < nLen)
{
dFree(buf);
*pInData = NULL;
*pnInDataLen= 0;
return E_IOFAILED;
}
// Ensure that it'sock for this socket
if(memcmp(&(pUDPSock->sockAddr), &sockAddrFrom, sizeof(SOCKADDR_IN)) != 0)
{
dFree(buf);
*pInData = NULL;
*pnInDataLen= 0;
return E_IOINVALID;
}
// Get real packet
nFromLen=sizeof(SOCKADDR_IN);
lenret=recvfrom(pUDPSock->sock,(char *)buf,nLen,0,(sockaddr *)&sockAddrFrom,&nFromLen);
if(lenret < nLen)
{
dFree(buf);
*pInData = NULL;
*pnInDataLen= 0;
return E_IOFAILED;
}
// Check for connection reset
if(((UDPHDR *)buf)->dwFlags & UF_RST)
{
dFree(buf);
*pInData = NULL;
*pnInDataLen= 0;
return E_IOFAILED;
}
// Pass data back to application
*pInData = (buf+sizeof(UDPHDR));
*pnInDataLen= (nLen-sizeof(UDPHDR));
return E_IOOK;
}
*pInData = NULL;
*pnInDataLen= 0;
return E_IOINVALID;
}
BOOL RPGAPI IOUDPModule::CheckSend(void *data)
{
data;
return TRUE;
}
int RPGAPI IOUDPModule::Send(void *data, BYTE *pData, int nDataLen)
{
return SendEx(data, pData, nDataLen);
}
int RPGAPI IOUDPModule::SendEx(void *data, BYTE *pData, int nDataLen)
{
UDPSOCKET *pUDPSock = (UDPSOCKET *)data;
// Ensure socket is connected
if(pUDPSock->dwState != US_CONNECTED)
return E_IOFAILED;
// Allocate buffer for header and data
BYTE *buf = (BYTE *)dMalloc(nDataLen+sizeof(UDPHDR));
if(buf == NULL)
return E_IOFAILED;
// Create packet
((UDPHDR *)buf)->dwFlags = 0;
dMemcpy(buf+sizeof(UDPHDR), pData, nDataLen);
// Send packet
int lenret;
lenret = sendto(pUDPSock->sock,(char *)buf,nDataLen+sizeof(UDPHDR),0,(SOCKADDR *)&(pUDPSock->sockAddr),sizeof(SOCKADDR_IN));
dFree(buf);
if(lenret == SOCKET_ERROR)
return E_IOFAILED;
if(lenret < nDataLen)
return E_IOINVALID;
return E_IOOK;
}
void RPGAPI IOUDPModule::Free(void *data, BYTE *pBuffer)
{
if(pBuffer == NULL)
return;
dFree(pBuffer-sizeof(UDPHDR));
}
void* RPGAPI IOUDPModule::GetNetAddress(void *data)
{
UDPSOCKET *pUDPSock = (UDPSOCKET *)data;
return &pUDPSock->sockAddr;
}
int RPGAPI IOUDPModule::GetConnectAddr(void *data, char *svAddr, int nMaxLen)
{
UDPSOCKET *pUDPSock = (UDPSOCKET *)data;
if(nMaxLen < 0)
return E_IOFAILED;
if(nMaxLen > ADDR_MAX)
nMaxLen = ADDR_MAX;
lstrcpyn(svAddr, pUDPSock->svConnectAddr, nMaxLen);
return E_IOOK;
}
};//namespace CS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -