📄 socket.c
字号:
#include "socket.h"
#include "base64.h"
#include "myos.h"
#include "Cram_md5.h"
//#include "blowfish.h"
//#include "udp.h"
#include <stdlib.h>
#include <netinet/in.h>
#include <netdb.h>
#ifdef _WIN
static DWORD WINAPI SocketRecvThread( LPVOID pPara ); //Socket循环检查可读数据线程
#endif
#ifdef _LINUX
static void* SocketRecvThread( void* pPara );
#endif
#ifdef _WIN
static DWORD WINAPI SocketSendThread( LPVOID pPara ); //Socket循环从发送队列取数据进行发送线程
#endif
#ifdef _LINUX
static void* SocketSendThread( void* pPara );
#endif
MY_SOCKET CreateConnection( unsigned short nPort );
extern void InitProtocolProcess( void );
extern void UninitProtocolProcess( void );
SocketEntry gSocketEntry;
int InitSocketEntry( SocketEntry *pEntry );
void UninitSocketEntry( SocketEntry *pEntry );
void OnReconnected( void );
void ProcessData( SocketEntry *pEntry, void* pBuffer, int nLen );
extern char gszUserName[ 32 ];
extern char gszPwd[ 32 ];
void OnSrvAuthCode( char *pszText );
void OnSrvResponseOK( char *pszCmdText );
void SendDomainReg( void );
char gszAuthCode[ 32 ] = { 0 };
char gDomainList[ 1 ][ MAX_IP_LEN ] = { 0 }; //域名列表,暂时先只支持一个
unsigned int gnLoginID = 0; //登录ID
unsigned int gnSequence = 0; //Sequence
//------------------------------------------------------------------------
int InitSocket()
{
int ret;
int i;
#ifdef _WIN
WORD wMajorVersion, wMinorVersion;
WSADATA wsaData;
WORD VersionReqd;
wMajorVersion = 2;
wMinorVersion = 0;
VersionReqd = MAKEWORD( wMajorVersion, wMinorVersion );
ret = WSAStartup( VersionReqd, &wsaData );
if ( ret != 0 )
{
printf( "WSAStartup Error, GetLastError = %d\n", GetLastError() );
return SOCKET_RESULT_EOSERROR;
}
#endif
printf( "InitSocketEntry is beginning \n");
ret = InitSocketEntry( &gSocketEntry );
if ( ret != 0 )
{
printf( "Error create connection to DDNS server, code: %d\n", ret );
return SOCKET_RESULT_EOSERROR;
}
printf( "InitSocketEntry is ok\n");
return SOCKET_RESULT_SUCCESS;
}
//------------------------------------------------------------------------
int SendPacket( void* pBuffer, Uint32 Len )
{
AddPacketToQueue( &gSocketEntry.SendQueue, &gSocketEntry, pBuffer, Len );//AddToSendQueue( pBuffer, Size );
printf( "Send: %s\r\n", pBuffer );
return SOCKET_RESULT_SUCCESS;
}
//------------------------------------------------------------------------
MY_SOCKET CreateConnection( unsigned short nPort )
{
struct sockaddr_in RemoteAddr;
int nRet;
struct hostent* pRemoteHost;
MY_SOCKET retSocket;
pRemoteHost = gethostbyname( PHLOGIN_SERVER_ADDR );
if ( pRemoteHost == NULL )
{
printf( "Error resolving host!\n" );
return INVALID_SOCK;
}
retSocket = socket( AF_INET, SOCK_STREAM, 0 );
if ( INVALID_SOCK == retSocket )
{
return retSocket;
}
memset( &RemoteAddr, 0, sizeof( RemoteAddr ) );
RemoteAddr.sin_family = AF_INET;
RemoteAddr.sin_port = htons( nPort );
//RemoteAddr.sin_addr.S_un.S_addr = *( unsigned long* )pRemoteHost->h_addr;
RemoteAddr.sin_addr.s_addr = *( unsigned long* )pRemoteHost->h_addr;
nRet = connect( retSocket, ( struct sockaddr* )&RemoteAddr, sizeof( RemoteAddr ) );
#ifdef _WIN
if ( nRet == SOCKET_ERROR )
{
MyCloseSocket( &retSocket );
return INVALID_SOCKET;
}
#endif
#ifdef _LINUX
if ( nRet < 0 )
{
return nRet;
}
#endif
return retSocket;
}
//------------------------------------------------------------------------
void UninitSocket()
{
UninitSocketEntry( &gSocketEntry );
#ifdef _WIN
WSACleanup();
#endif
}
//------------------------------------------------------------------------
#ifdef _WIN
DWORD WINAPI SocketRecvThread( LPVOID pPara )
#endif
#ifdef _LINUX
void* SocketRecvThread( void* pPara )
#endif
{
int nRet;
SocketEntry *pEntry = ( SocketEntry* )pPara;
void* pBuffer = malloc( SOCKET_BUFFSIZE );
while ( TRUE )
{
nRet = recv( pEntry->s, ( char * )pBuffer, SOCKET_BUFFSIZE, 0 );
if ( nRet <= 0 )
{
ClearQueue( &pEntry->SendQueue );
if ( pEntry == &gSocketEntry )
{
printf( "Disconnected! Reconnect after 1 minute!\n\n" );
//break;
Reconnect( pEntry );
continue;
}
else
{
break; //connection closed
}
}
ProcessData( pEntry, pBuffer, nRet ); //在该函数中拆分/合并成合法包后再投递到队列中处理
}
UninitSocketEntry( pEntry );
free( pBuffer );
#ifdef _WIN
return 0;
#endif
#ifdef _LINUX
return NULL;
#endif
}
//------------------------------------------------------------------------
void InitSocketQueue( SocketQueue *pQueue )
{
pQueue->pFirstNode = NULL;
MyCriticalInit( &pQueue->cs );
MySemInit( &pQueue->sem, 0 );
}
//------------------------------------------------------------------------
void UninitSocketQueue( SocketQueue *pQueue )
{
PacketQueueNode *pNode = pQueue->pFirstNode;
while ( pNode != NULL )
{
PacketQueueNode *temp = pNode->pNext;
free( pNode->pBuffer );
free( pNode );
pNode = temp;
}
pQueue->pFirstNode = NULL;
MyCriticalDestroy( &pQueue->cs );
MySemDestroy( &pQueue->sem );
}
//------------------------------------------------------------------------
void AddPacketToQueue( SocketQueue *pQueue, SocketEntry *pEntry, void* pPacket, int nLen )
{
PacketQueueNode *pNode;
//这里申请的内存等处理完成后再回收
void *pData = malloc( nLen );
if ( NULL == pData )
{
return;
}
memcpy( pData, pPacket, nLen );
MyCriticalEntry( &pQueue->cs );
if ( pQueue->pFirstNode == NULL )
{
pQueue->pFirstNode = ( PacketQueueNode* )malloc( sizeof( PacketQueueNode ) );
pQueue->pFirstNode->pBuffer = pData;
pQueue->pFirstNode->nLen = nLen;
pQueue->pFirstNode->pEntry = pEntry;
pQueue->pFirstNode->pNext = NULL;
}
else
{
pNode = pQueue->pFirstNode;
while ( pNode->pNext )
{
pNode = pNode->pNext;
}
pNode->pNext = ( PacketQueueNode* )malloc( sizeof( PacketQueueNode ) );
pNode->pNext->pBuffer = pData;
pNode->pNext->nLen = nLen;
pNode->pNext->pEntry = pEntry;
pNode->pNext->pNext = NULL;
}
MySemPost( &pQueue->sem );
MyCriticalLeave( &pQueue->cs );
}
//------------------------------------------------------------------------
void ClearQueue( SocketQueue *pQueue )
{
PacketQueueNode *pNode, *pNext;
MyCriticalEntry( &pQueue->cs );
pNode = pQueue->pFirstNode;
while ( pNode )
{
pNext = pNode->pNext;
free( pNode );
pNode = pNext;
}
pQueue->pFirstNode = NULL;
MyCriticalLeave( &pQueue->cs );
}
//------------------------------------------------------------------------
#ifdef _WIN
DWORD WINAPI SocketSendThread( LPVOID pPara )
#endif
#ifdef _LINUX
void* SocketSendThread( void* pPara )
#endif
{
PacketQueueNode *pSendItem;
SocketEntry *pEntry = ( SocketEntry* )pPara;
int nRet;
while ( TRUE )
{
MySemWait( &pEntry->SendQueue.sem );
pSendItem = GetQueueTopNode( &pEntry->SendQueue );
if ( pSendItem != NULL )
{
nRet = send( pEntry->s, ( char* )pSendItem->pBuffer, pSendItem->nLen, 0 );
free( pSendItem->pBuffer ); //释放在AddToSendQueue中申请的内存
free( pSendItem );
#ifdef _WIN
if ( SOCKET_ERROR == nRet )
#endif
#ifdef _LINUX
if ( nRet < 0 )
#endif
{
ClearQueue( &pEntry->SendQueue );
//Reconnect( pEntry );
}
}
}
#ifdef _WIN
return 0;
#endif
#ifdef _LINUX
return NULL;
#endif
}
//------------------------------------------------------------------------
PacketQueueNode* GetQueueTopNode( SocketQueue *pQueue )
{
PacketQueueNode *pRetNode;
MyCriticalEntry( &pQueue->cs ); //从队列链表中取头结点进行处理
pRetNode = pQueue->pFirstNode;
if ( pQueue->pFirstNode )
{
pQueue->pFirstNode = pQueue->pFirstNode->pNext;
}
MyCriticalLeave( &pQueue->cs );
return pRetNode;
}
//------------------------------------------------------------------------
void Reconnect( SocketEntry *pEntry )
{
pEntry->bConnected = FALSE;
sleep( 60000 ); //等待1分钟
MyCriticalEntry( &pEntry->ReconnectCS );
if ( pEntry->bConnected ) //如果等待完成後發現已經連接( by another thread ), 則直接退出
{
MyCriticalLeave( &pEntry->ReconnectCS );
return;
}
while ( TRUE )
{
pEntry->s = CreateConnection( PHLOGIN_SERVER_PORT );
#ifdef _WIN
if ( INVALID_SOCKET == pEntry->s )
#endif
#ifdef _LINUX
if ( pEntry->s < 0 )
#endif
{
MySleep( 100 );
continue;
}
pEntry->bConnected = TRUE;
break;
}
OnReconnected();
MyCriticalLeave( &pEntry->ReconnectCS );
}
//------------------------------------------------------------------------
int InitSocketEntry( SocketEntry *pEntry )
{
int ret = 0;
pEntry->bConnected = FALSE;
MyCriticalInit( &pEntry->ReconnectCS );
InitSocketQueue( &pEntry->SendQueue );
pEntry->s = CreateConnection( PHLOGIN_SERVER_PORT );
#ifdef _WIN
if ( INVALID_SOCKET == pEntry->s )
{
ret = GetLastError();
}
#endif
#ifdef _LINUX
if ( pEntry->s < 0 )
{
ret = pEntry->s;
}
#endif
else
{
pEntry->bConnected = TRUE;
}
MyThreadCreate( &pEntry->RecvThread, SocketRecvThread, pEntry );
MyThreadCreate( &pEntry->SendThread, SocketSendThread, pEntry );
return ret;
}
//------------------------------------------------------------------------
void UninitSocketEntry( SocketEntry *pEntry )
{
UninitSocketQueue( &pEntry->SendQueue );
if ( pEntry->bConnected )
{
MyCloseSocket( &pEntry->s );
#ifdef _WIN
pEntry->s = INVALID_SOCKET;
#endif
#ifdef _LINUX
pEntry->s = -1;
#endif
pEntry->bConnected = FALSE;
}
MyCriticalDestroy( &pEntry->ReconnectCS );
}
//------------------------------------------------------------------------
#define REQUEST_AUTH_CMD "auth phsrv3\r\n"
#define REQUEST_REG_DOMAIN "regi a %s\r\n"
#define REQUEST_CONFIRM "cnfm\r\n"
#define REQUEST_QUIT "quit\r\n"
#define AUTHREG_LOGIN "Authentication"
#define AUTHREG_DOMAINREG "Register"
#define SRV_CMD_READY 220
#define SRV_CMD_OK 250
#define SRV_CMD_AUTHCODE 334
#define SRV_CMD_AUTHFAIL 535
#define SRV_CMD_UNRECOGENIZE 500
void ProcessData( SocketEntry *pEntry, void* pBuffer, int nLen )
{
int nCmd;
char *pszBuffer = ( char* )malloc( nLen + 1 );
memcpy( pszBuffer, pBuffer, nLen );
pszBuffer[ nLen ] = 0; //null-terminator appended
if ( sscanf( pszBuffer, "%d", &nCmd ) == 0 )
{
printf( "Received error: %s\n", pszBuffer );
free( pszBuffer );
return;
}
printf( "Received: %s\n", pszBuffer );
switch ( nCmd )
{
case SRV_CMD_READY:
{
SendPacket( REQUEST_AUTH_CMD, strlen( REQUEST_AUTH_CMD ) );
break;
}
case SRV_CMD_OK:
{
OnSrvResponseOK( &pszBuffer[ 4 ] );
break;
}
case SRV_CMD_AUTHCODE:
{
OnSrvAuthCode( &pszBuffer[ 4 ] );
break;
}
case SRV_CMD_AUTHFAIL:
{
break;
}
case SRV_CMD_UNRECOGENIZE:
{
break;
}
default:
break;
}
free( pszBuffer );
}
//------------------------------------------------------------------------
void OnReconnected( void )
{
}
//------------------------------------------------------------------------
typedef unsigned long DWORD;
void OnSrvAuthCode( char *pszText )
{
if ( from64tobits( gszAuthCode, pszText ) > 0 )
{
char szEncPwd[ 64 ] = { 0 };
char szLoginData[ 128 ] = { 0 };
char szEncLoginData[ 128 ] = { 0 };
DWORD dwPAdding1;
DWORD dwPAdding2 = 0x10013612;
compute_cram_md5( gszAuthCode, gszPwd, szEncPwd );
dwPAdding1 = *( DWORD* )&gszAuthCode[ 6 ];
dwPAdding1 |= 0xE686F9D6;
strcpy( szLoginData, gszUserName );
strcat( szLoginData, " " );
memcpy( &szLoginData[ strlen( szLoginData ) ], &dwPAdding1, sizeof( DWORD ) );
memcpy( &szLoginData[ strlen( szLoginData ) ], &dwPAdding2, sizeof( DWORD ) );
strcat( &szLoginData[ strlen( szLoginData ) ], szEncPwd );
to64frombits( szEncLoginData, szLoginData, strlen( szLoginData ) );
strcat( szEncLoginData, "\r\n" );
SendPacket( szEncLoginData, strlen( szEncLoginData ) );
}
}
//------------------------------------------------------------------------
void SendDomainReg()
{
//暂时先只处理
char szBuffer[ 64 ] = { 0 };
int i;
for ( i = 0; i < sizeof( gDomainList ) / sizeof( gDomainList[ 0 ] ); i++ )
{
sprintf( szBuffer, REQUEST_REG_DOMAIN, gDomainList[ i ] );
SendPacket( szBuffer, strlen( szBuffer ) );
}
}
//------------------------------------------------------------------------
void OnSrvResponseOK( char *pszCmdText )
{
char *p;
int i = 0;
if ( strncmp( pszCmdText, AUTHREG_DOMAINREG, strlen( AUTHREG_DOMAINREG ) ) == 0 ) //Authentication passed
{
SendPacket( REQUEST_CONFIRM, strlen( REQUEST_CONFIRM ) );
}
else if ( strncmp( pszCmdText, AUTHREG_LOGIN, strlen( AUTHREG_LOGIN ) ) == 0 )
{
p = strtok( pszCmdText, "\r\n" );
while ( p != NULL )
{
p = strtok( NULL, "\r\n" );
if ( *p != '.' )
{
strcpy( gDomainList[ i ], p );
i++;
}
else
{
break;
}
if ( i >= sizeof( gDomainList ) / sizeof( gDomainList[ 0 ] ) )
{
break;
}
}
if ( i > 0 )
{
SendDomainReg();
}
}
else
{
if ( sscanf( pszCmdText, "%d %d", &gnLoginID, &gnSequence ) == 2 )
{
SendPacket( REQUEST_QUIT, strlen( REQUEST_QUIT ) );
//InitUDP(); //这里为初始化UDP的Keepalive相关的,因算法未分析完成,而又非必须,所以暂时取消.
}
}
}
//------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -