1 Star 8 Fork 5

SSZL博客/webSocket_Libevent_ThreadPool

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
ev_websocket.c 41.20 KB
一键复制 编辑 原始数据 按行查看 历史
SSZL 提交于 2019-01-23 10:53 . 修改
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246
/*************************************************************************
# > File Name: ev_websocket.c
# > Author: SSZL
# > Blog: sszlbg.cn
# > Created Time: 2018-09-14 09:54:35
# > Revise Time: 2018-10-29 13:19:36
************************************************************************/
#include "include/ev_websocket.h"
#include "include/debug.h"
#include "include/config.h"
#ifndef RECV_DATA_TIME_OUT
#define RECV_DATA_TIME_OUT 20 //接收数据超时 20 次接收为空
#endif
#ifndef OPENSSL
//================================================== 加密方法 sha1哈希 ==================================================
typedef struct SHA1Context{
unsigned Message_Digest[5];
unsigned Length_Low;
unsigned Length_High;
unsigned char Message_Block[64];
int Message_Block_Index;
int Computed;
int Corrupted;
} SHA1Context;
#define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))
void SHA1ProcessMessageBlock(SHA1Context *context)
{
const unsigned K[] = {0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
int t;
unsigned temp;
unsigned W[80];
unsigned A, B, C, D, E;
for(t = 0; t < 16; t++)
{
W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
}
for(t = 16; t < 80; t++)
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
A = context->Message_Digest[0];
B = context->Message_Digest[1];
C = context->Message_Digest[2];
D = context->Message_Digest[3];
E = context->Message_Digest[4];
for(t = 0; t < 20; t++)
{
temp = SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 20; t < 40; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 40; t < 60; t++)
{
temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 60; t < 80; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
context->Message_Digest[0] = (context->Message_Digest[0] + A) & 0xFFFFFFFF;
context->Message_Digest[1] = (context->Message_Digest[1] + B) & 0xFFFFFFFF;
context->Message_Digest[2] = (context->Message_Digest[2] + C) & 0xFFFFFFFF;
context->Message_Digest[3] = (context->Message_Digest[3] + D) & 0xFFFFFFFF;
context->Message_Digest[4] = (context->Message_Digest[4] + E) & 0xFFFFFFFF;
context->Message_Block_Index = 0;
}
void SHA1Reset(SHA1Context *context)
{
context->Length_Low = 0;
context->Length_High = 0;
context->Message_Block_Index = 0;
context->Message_Digest[0] = 0x67452301;
context->Message_Digest[1] = 0xEFCDAB89;
context->Message_Digest[2] = 0x98BADCFE;
context->Message_Digest[3] = 0x10325476;
context->Message_Digest[4] = 0xC3D2E1F0;
context->Computed = 0;
context->Corrupted = 0;
}
void SHA1PadMessage(SHA1Context *context)
{
if (context->Message_Block_Index > 55)
{
context->Message_Block[context->Message_Block_Index++] = 0x80;
while(context->Message_Block_Index < 64) context->Message_Block[context->Message_Block_Index++] = 0;
SHA1ProcessMessageBlock(context);
while(context->Message_Block_Index < 56) context->Message_Block[context->Message_Block_Index++] = 0;
}
else
{
context->Message_Block[context->Message_Block_Index++] = 0x80;
while(context->Message_Block_Index < 56) context->Message_Block[context->Message_Block_Index++] = 0;
}
context->Message_Block[56] = (context->Length_High >> 24 ) & 0xFF;
context->Message_Block[57] = (context->Length_High >> 16 ) & 0xFF;
context->Message_Block[58] = (context->Length_High >> 8 ) & 0xFF;
context->Message_Block[59] = (context->Length_High) & 0xFF;
context->Message_Block[60] = (context->Length_Low >> 24 ) & 0xFF;
context->Message_Block[61] = (context->Length_Low >> 16 ) & 0xFF;
context->Message_Block[62] = (context->Length_Low >> 8 ) & 0xFF;
context->Message_Block[63] = (context->Length_Low) & 0xFF;
SHA1ProcessMessageBlock(context);
}
int SHA1Result(SHA1Context *context)
{
if (context->Corrupted)
{
return 0;
}
if (!context->Computed)
{
SHA1PadMessage(context);
context->Computed = 1;
}
return 1;
}
void SHA1Input(SHA1Context *context,const char *message_array,unsigned length){
if (!length)
return;
if (context->Computed || context->Corrupted)
{
context->Corrupted = 1;
return;
}
while(length-- && !context->Corrupted)
{
context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF);
context->Length_Low += 8;
context->Length_Low &= 0xFFFFFFFF;
if (context->Length_Low == 0)
{
context->Length_High++;
context->Length_High &= 0xFFFFFFFF;
if (context->Length_High == 0) context->Corrupted = 1;
}
if (context->Message_Block_Index == 64)
{
SHA1ProcessMessageBlock(context);
}
message_array++;
}
}
/*
int sha1_hash(const char *source, char *lrvar){// Main
SHA1Context sha;
char buf[128];
SHA1Reset(&sha);
SHA1Input(&sha, source, strlen(source));
if (!SHA1Result(&sha)){
printf("SHA1 ERROR: Could not compute message digest");
return -1;
} else {
memset(buf,0,sizeof(buf));
sprintf(buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],
sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);
//lr_save_string(buf, lrvar);
return strlen(buf);
}
}
*/
char * sha1_hash1(const char *source){ // Main
SHA1Context sha;
char *buf;//[128];
SHA1Reset(&sha);
SHA1Input(&sha, source, strlen(source));
if (!SHA1Result(&sha))
{
printf("SHA1 ERROR: Could not compute message digest");
return NULL;
}
else
{
buf = (char *)malloc(128);
memset(buf, 0, 128);
sprintf(buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],
sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);
//lr_save_string(buf, lrvar);
//return strlen(buf);
return buf;
}
}
int tolower(int c)
{
if (c >= 'A' && c <= 'Z')
{
return c + 'a' - 'A';
}
else
{
return c;
}
}
int htoi(const char s[], int start, int len)
{
int i, j;
int n = 0;
if (s[0] == '0' && (s[1]=='x' || s[1]=='X')) //判断是否有前导0x或者0X
{
i = 2;
}
else
{
i = 0;
}
i+=start;
j=0;
for (; (s[i] >= '0' && s[i] <= '9')
|| (s[i] >= 'a' && s[i] <= 'f') || (s[i] >='A' && s[i] <= 'F');++i)
{
if(j>=len)
{
break;
}
if (tolower(s[i]) > '9')
{
n = 16 * n + (10 + tolower(s[i]) - 'a');
}
else
{
n = 16 * n + (tolower(s[i]) - '0');
}
j++;
}
return n;
}
char * sha1_hash(const char *source){ // Main
char *sha1DataTemp, *sha1Data;
int n;
int i;
sha1DataTemp = sha1_hash1(source);
n = strlen(sha1DataTemp);
sha1Data = (char *)calloc(1, n / 2 + 1);
memset(sha1Data, 0, n / 2 + 1);
for(i = 0; i < n; i += 2)
sha1Data[ i / 2 ] = htoi(sha1DataTemp, i, 2);
free((void *)sha1DataTemp);
return sha1Data;
}
#else
char * sha1_hash(const char *source)
{
char *out;
out = (char *)malloc( 21);
memset(out,0, 21);
return (char *)SHA1((unsigned char *)source, strlen(source), (unsigned char *)out);
}
#endif
//================================================== 加密方法BASE64 ==================================================
//base64编/解码用的基础字符集
const char base64char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/*******************************************************************************
* 名称: base64_encode
* 功能: ascii编码为base64格式
* 形参: bindata : ascii字符串输入
* base64 : base64字符串输出
* binlength : bindata的长度
* 返回: base64字符串长度
* 说明: 无
******************************************************************************/
int base64_encode( const unsigned char *bindata, char *base64, int binlength)
{
int i, j;
unsigned char current;
for ( i = 0, j = 0 ; i < binlength ; i += 3 )
{
current = (bindata[i] >> 2) ;
current &= (unsigned char)0x3F;
base64[j++] = base64char[(int)current];
current = ( (unsigned char)(bindata[i] << 4 ) ) & ( (unsigned char)0x30 ) ;
if ( i + 1 >= binlength )
{
base64[j++] = base64char[(int)current];
base64[j++] = '=';
base64[j++] = '=';
break;
}
current |= ( (unsigned char)(bindata[i+1] >> 4) ) & ( (unsigned char) 0x0F );
base64[j++] = base64char[(int)current];
current = ( (unsigned char)(bindata[i+1] << 2) ) & ( (unsigned char)0x3C ) ;
if ( i + 2 >= binlength )
{
base64[j++] = base64char[(int)current];
base64[j++] = '=';
break;
}
current |= ( (unsigned char)(bindata[i+2] >> 6) ) & ( (unsigned char) 0x03 );
base64[j++] = base64char[(int)current];
current = ( (unsigned char)bindata[i+2] ) & ( (unsigned char)0x3F ) ;
base64[j++] = base64char[(int)current];
}
base64[j] = '\0';
return j;
}
/*******************************************************************************
* 名称: base64_decode
* 功能: base64格式解码为ascii
* 形参: base64 : base64字符串输入
* bindata : ascii字符串输出
* 返回: 解码出来的ascii字符串长度
* 说明: 无
******************************************************************************/
int base64_decode( const char *base64, unsigned char *bindata)
{
int i, j;
unsigned char k;
unsigned char temp[4];
for ( i = 0, j = 0; base64[i] != '\0' ; i += 4 )
{
memset( temp, 0xFF, sizeof(temp) );
for ( k = 0 ; k < 64 ; k ++ )
{
if ( base64char[k] == base64[i] )
temp[0]= k;
}
for ( k = 0 ; k < 64 ; k ++ )
{
if ( base64char[k] == base64[i+1] )
temp[1]= k;
}
for ( k = 0 ; k < 64 ; k ++ )
{
if ( base64char[k] == base64[i+2] )
temp[2]= k;
}
for ( k = 0 ; k < 64 ; k ++ )
{
if ( base64char[k] == base64[i+3] )
temp[3]= k;
}
bindata[j++] = ((unsigned char)(((unsigned char)(temp[0] << 2))&0xFC)) | \
((unsigned char)((unsigned char)(temp[1]>>4)&0x03));
if ( base64[i+2] == '=' )
break;
bindata[j++] = ((unsigned char)(((unsigned char)(temp[1] << 4))&0xF0)) | \
((unsigned char)((unsigned char)(temp[2]>>2)&0x0F));
if ( base64[i+3] == '=' )
break;
bindata[j++] = ((unsigned char)(((unsigned char)(temp[2] << 6))&0xF0)) | \
((unsigned char)(temp[3]&0x3F));
}
return j;
}
//==============================================================================================================
//================================================== websocket ==================================================
//==============================================================================================================
// 连接服务器
#ifndef REPORT_LOGIN_CONNECT_TIMEOUT
#define REPORT_LOGIN_CONNECT_TIMEOUT 1000 // 登录连接超时设置 1000ms
#endif
#ifndef REPORT_LOGIN_RESPOND_TIMEOUT
#define REPORT_LOGIN_RESPOND_TIMEOUT (1000 + REPORT_LOGIN_CONNECT_TIMEOUT) // 登录等待回应超时设置 1000ms
#endif
// 指令发收
#ifndef REPORT_ANALYSIS_ERR_RESEND_DELAY
#define REPORT_ANALYSIS_ERR_RESEND_DELAY 500 // 接收到回复内容但解析不通过, 延时 一段时间后重发指令 单位ms
#endif
// 生成握手key的长度
#ifndef WEBSOCKET_SHAKE_KEY_LEN
#define WEBSOCKET_SHAKE_KEY_LEN 16
#endif
/*
// websocket根据data[0]判别数据包类型
typedef enum{
WCT_MINDATA = -20, // 0x0:标识一个中间数据包
WCT_TXTDATA = -19, // 0x1:标识一个text类型数据包
WCT_BINDATA = -18, // 0x2:标识一个binary类型数据包
WCT_DISCONN = -17, // 0x8:标识一个断开连接类型数据包
WCT_PING = -16, // 0x8:标识一个断开连接类型数据包
WCT_PONG = -15, // 0xA:表示一个pong类型数据包
WCT_ERR = -2,
WCT_NULL = 0
}Websocket_CommunicationType;*/
/*******************************************************************************
* 名称: webSocket_getRandomString
* 功能: 生成随机字符串
* 形参: *buf:随机字符串存储到
* len : 生成随机字符串长度
* 返回: 无
* 说明: 无
******************************************************************************/
void webSocket_getRandomString(unsigned char *buf, unsigned int len)
{
unsigned int i;
unsigned char temp;
srand((int)time(0));
for(i = 0; i < len; i++)
{
temp = (unsigned char)(rand()%256);
if(temp == 0) // 随机数不要0, 0 会干扰对字符串长度的判断
temp = 128;
buf[i] = temp;
}
}
/*******************************************************************************
* 名称: webSocket_buildShakeKey
* 功能: client端使用随机数构建握手用的key
* 形参: *key:随机生成的握手key
* 返回: key的长度
* 说明: 无
******************************************************************************/
int webSocket_buildShakeKey(unsigned char *key)
{
unsigned char tempKey[WEBSOCKET_SHAKE_KEY_LEN] = {0};
webSocket_getRandomString(tempKey, WEBSOCKET_SHAKE_KEY_LEN);
return base64_encode((const unsigned char *)tempKey, (char *)key, WEBSOCKET_SHAKE_KEY_LEN);
}
/*******************************************************************************
* 名称: webSocket_buildRespondShakeKey
* 功能: server端在接收client端的key后,构建回应用的key
* 形参: *acceptKey:来自客户端的key字符串
* acceptKeyLen : 长度
* *respondKey : 在 acceptKey 之后加上 GUID, 再sha1哈希, 再转成base64得到 respondKey
* 返回: respondKey的长度(肯定比acceptKey要长)
* 说明: 无
******************************************************************************/
int webSocket_buildRespondShakeKey(unsigned char *acceptKey, unsigned int acceptKeyLen, unsigned char *respondKey)
{
char *clientKey;
char *sha1Data;
int n;
const char GUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
unsigned int GUIDLEN;
if(acceptKey == NULL)
return 0;
GUIDLEN = sizeof(GUID);
clientKey = (char *)calloc(1, sizeof(char)*(acceptKeyLen + GUIDLEN + 10));
memset(clientKey, 0, (acceptKeyLen + GUIDLEN + 10));
//
memcpy(clientKey, acceptKey, acceptKeyLen);
memcpy(&clientKey[acceptKeyLen], GUID, GUIDLEN);
clientKey[acceptKeyLen + GUIDLEN] = '\0';
//
sha1Data = sha1_hash(clientKey);
n = strlen(sha1Data);
//
n = base64_encode((const unsigned char *)sha1Data, (char *)respondKey, n);
//
free(sha1Data);
free(clientKey);
return n;
}
/*******************************************************************************
* 名称: webSocket_matchShakeKey
* 功能: client端收到来自服务器回应的key后进行匹配,以验证握手成功
* 形参: *myKey:client端请求握手时发给服务器的key
* myKeyLen : 长度
* *acceptKey : 服务器回应的key
* acceptKeyLen : 长度
* 返回: 0 成功 -1 失败
* 说明: 无
******************************************************************************/
int webSocket_matchShakeKey(unsigned char *myKey, unsigned int myKeyLen, unsigned char *acceptKey, unsigned int acceptKeyLen)
{
unsigned int retLen;
unsigned char tempKey[256] = {0};
//
retLen = webSocket_buildRespondShakeKey(myKey, myKeyLen, tempKey);
//printf("webSocket_matchShakeKey :\r\n%d : %s\r\n%d : %s\r\n", acceptKeyLen, acceptKey, retLen, tempKey);
//
if(retLen != acceptKeyLen)
{
De_printf("webSocket_matchShakeKey : len err\r\n%s\r\n%s\r\n%s\r\n", myKey, tempKey, acceptKey);
return -1;
}
else if(strcmp((const char *)tempKey, (const char *)acceptKey) != 0)
{
De_printf("webSocket_matchShakeKey : str err\r\n%s\r\n%s\r\n", tempKey, acceptKey);
return -1;
}
return 0;
}
/*******************************************************************************
* 名称: webSocket_buildHttpHead
* 功能: 构建client端连接服务器时的http协议头, 注意websocket是GET形式的
* 形参: *ip:要连接的服务器ip字符串
* port : 服务器端口
* *interfacePath : 要连接的端口地址
* *shakeKey : 握手key, 可以由任意的16位字符串打包成base64后得到
* *package : 存储最后打包好的内容
* 返回: 无
* 说明: 无
******************************************************************************/
void webSocket_buildHttpHead(char *ip, int port, char *interfacePath, unsigned char *shakeKey, char *package)
{
const char httpDemo[] = "GET %s HTTP/1.1\r\n"
"Connection: Upgrade\r\n"
"Host: %s:%d\r\n"
"Sec-WebSocket-Key: %s\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Upgrade: websocket\r\n\r\n";
sprintf(package, httpDemo, interfacePath, ip, port, shakeKey);
}
/*******************************************************************************
* 名称: webSocket_buildHttpRespond
* 功能: 构建server端回复client连接请求的http协议
* 形参: *acceptKey:来自client的握手key
* acceptKeyLen : 长度
* *package : 存储
* 返回: 无
* 说明: 无
******************************************************************************/
void webSocket_buildHttpRespond(unsigned char *acceptKey, unsigned int acceptKeyLen, char *package)
{
const char httpDemo[] = "HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Server: Microsoft-HTTPAPI/2.0\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: %s\r\n"
"%s\r\n\r\n"; // 时间打包待续 // 格式如 "Date: Tue, 20 Jun 2017 08:50:41 CST\r\n"
time_t now;
struct tm *tm_now;
char timeStr[256] = {0};
unsigned char respondShakeKey[256] = {0};
// 构建回应的握手key
webSocket_buildRespondShakeKey(acceptKey, acceptKeyLen, respondShakeKey);
// 构建回应时间字符串
time(&now);
tm_now = localtime(&now);
strftime(timeStr, sizeof(timeStr), "Date: %a, %d %b %Y %T %Z", tm_now);
// 组成回复信息
sprintf(package, httpDemo, respondShakeKey, timeStr);
}
/*******************************************************************************
* 名称: webSocket_enPackage
* 功能: websocket数据收发阶段的数据打包, 通常client发server的数据都要isMask(掩码)处理, 反之server到client却不用
* 形参: *data:准备发出的数据
* dataLen : 长度
* *package : 打包后存储地址
* packageMaxLen : 存储地址可用长度
* isMask : 是否使用掩码 1要 0 不要
* type : 数据类型, 由打包后第一个字节决定, 这里默认是数据传输, 即0x81
* 返回: 打包后的长度(会比原数据长2~16个字节不等) <=0 打包失败
* 说明: 无
******************************************************************************/
int webSocket_enPackage(unsigned char *data, unsigned int dataLen, unsigned char *package, unsigned int packageMaxLen, bool isMask, Websocket_CommunicationType type)
{
unsigned char maskKey[4] = {0}; // 掩码
unsigned char temp1, temp2;
int count;
unsigned int i, len = 0;
if(packageMaxLen < 2)
return -1;
if(type == WCT_MINDATA)
*package++ = 0x00;
else if(type == WCT_TXTDATA)
*package++ = 0x81;
else if(type == WCT_BINDATA)
*package++ = 0x82;
else if(type == WCT_DISCONN)
*package++ = 0x88;
else if(type == WCT_PING)
*package++ = 0x89;
else if(type == WCT_PONG)
*package++ = 0x8A;
else
return -1;
//
if(isMask)
*package = 0x80;
len += 1;
//
if(dataLen < 126)
{
*package++ |= (dataLen&0x7F);
len += 1;
}
else if(dataLen < 65536)
{
if(packageMaxLen < 4)
return -1;
*package++ |= 0x7E;
*package++ = (char)((dataLen >> 8) & 0xFF);
*package++ = (unsigned char)((dataLen >> 0) & 0xFF);
len += 3;
}
else if(dataLen < 0xFFFFFFFF)
{
if(packageMaxLen < 10)
return -1;
*package++ |= 0x7F;
*package++ = 0; //(char)((dataLen >> 56) & 0xFF); // 数据长度变量是 unsigned int dataLen, 暂时没有那么多数据
*package++ = 0; //(char)((dataLen >> 48) & 0xFF);
*package++ = 0; //(char)((dataLen >> 40) & 0xFF);
*package++ = 0; //(char)((dataLen >> 32) & 0xFF);
*package++ = (char)((dataLen >> 24) & 0xFF); // 到这里就够传4GB数据了
*package++ = (char)((dataLen >> 16) & 0xFF);
*package++ = (char)((dataLen >> 8) & 0xFF);
*package++ = (char)((dataLen >> 0) & 0xFF);
len += 9;
}
//
if(isMask) // 数据使用掩码时, 使用异或解码, maskKey[4]依次和数据异或运算, 逻辑如下
{
if(packageMaxLen < len + dataLen + 4)
return -1;
webSocket_getRandomString(maskKey, sizeof(maskKey)); // 随机生成掩码
*package++ = maskKey[0];
*package++ = maskKey[1];
*package++ = maskKey[2];
*package++ = maskKey[3];
len += 4;
for(i = 0, count = 0; i < dataLen; i++)
{
temp1 = maskKey[count];
temp2 = data[i];
*package++ = (char)(((~temp1)&temp2) | (temp1&(~temp2))); // 异或运算后得到数据
count += 1;
if((unsigned)count >= sizeof(maskKey)) // maskKey[4]循环使用
count = 0;
}
len += i;
*package = '\0';
}
else // 数据没使用掩码, 直接复制数据段
{
if(packageMaxLen < len + dataLen)
return -1;
memcpy(package, data, dataLen);
package[dataLen] = '\0';
len += dataLen;
}
//
return len;
}
int webSocket_getInType(unsigned char *data)
{
char type;
int ret;
type = data[0]&0x0F;
if((data[0]&0x80) == 0x80)
{
if(type == 0x01)
ret = WCT_TXTDATA;
else if(type == 0x02)
ret = WCT_BINDATA;
else if(type == 0x08)
ret = WCT_DISCONN;
else if(type == 0x09)
ret = WCT_PING;
else if(type == 0x0A)
ret = WCT_PONG;
else
return WCT_ERR;
}
else if(type == 0x00)
ret = WCT_MINDATA;
else
return WCT_ERR;
return ret;
}
int webSocket_getInLen(unsigned char *data, unsigned int dataLen)
{
char Mask = 0;
int ret = 0;
unsigned int len = 0, dataStart = 2;
if(dataLen < 2)
return WCT_ERR;
ret = webSocket_getInType(data);
if(ret == WCT_ERR)
return WCT_ERR;
//
if((data[1] & 0x80) == 0x80)
{
Mask = 1;
}
else
{
Mask = 0;
}
//
len = data[1] & 0x7F;
//
if(len == 126)
{
if(dataLen < 4)
return WCT_ERR;
len = data[2];
len = (len << 8) + data[3];
if(Mask)
{
dataStart = 8;
}
else
dataStart = 4;
}
else if(len == 127)
{
if(dataLen < 10)
return WCT_ERR;
if(data[2] != 0 || data[3] != 0 || data[4] != 0 || data[5] != 0) // 使用8个字节存储长度时, 前4位必须为0, 装不下那么多数据...
return WCT_ERR;
len = data[6];
len = (len << 8) + data[7];
len = (len << 8) + data[8];
len = (len << 8) + data[9];
if(Mask)
{
dataStart = 14;
}
else
dataStart = 10;
}
else
{
if(Mask)
{
dataStart = 6;
}
else
dataStart = 2;
}
return len + dataStart;
}
/*******************************************************************************
* 名称: webSocket_dePackage
* 功能: websocket数据收发阶段的数据解包, 通常client发server的数据都要isMask(掩码)处理, 反之server到client却不用
* 形参: *data:解包的数据
* dataLen : 长度
* *package : 解包后存储地址
* packageMaxLen : 存储地址可用长度
* *packageLen : 解包所得长度
* 返回: 解包识别的数据类型 如 : txt数据, bin数据, ping, pong等
* 说明: 无
******************************************************************************/
int webSocket_dePackage(unsigned char *data, unsigned int dataLen, unsigned char *package, unsigned int packageMaxLen, unsigned int *packageLen)
{
unsigned char maskKey[4] = {0}; // 掩码
unsigned char temp1, temp2;
char Mask = 0;
int count, ret;
unsigned int i, len = 0, dataStart = 2;
if(dataLen < 2)
return WCT_ERR;
ret = webSocket_getInType(data);
if(ret == WCT_ERR)
return WCT_ERR;
//
if((data[1] & 0x80) == 0x80)
{
Mask = 1;
count = 4;
}
else
{
Mask = 0;
count = 0;
}
//
len = data[1] & 0x7F;
//
if(len == 126)
{
if(dataLen < 4)
return WCT_ERR;
len = data[2];
len = (len << 8) + data[3];
if(dataLen < len + 4 + count)
return WCT_ERR;
if(Mask)
{
maskKey[0] = data[4];
maskKey[1] = data[5];
maskKey[2] = data[6];
maskKey[3] = data[7];
dataStart = 8;
}
else
dataStart = 4;
}
else if(len == 127)
{
if(dataLen < 10)
return WCT_ERR;
if(data[2] != 0 || data[3] != 0 || data[4] != 0 || data[5] != 0) // 使用8个字节存储长度时, 前4位必须为0, 装不下那么多数据...
return WCT_ERR;
len = data[6];
len = (len << 8) + data[7];
len = (len << 8) + data[8];
len = (len << 8) + data[9];
if(dataLen < len + 10 + count)
return WCT_ERR;
if(Mask)
{
maskKey[0] = data[10];
maskKey[1] = data[11];
maskKey[2] = data[12];
maskKey[3] = data[13];
dataStart = 14;
}
else
dataStart = 10;
}
else
{
if(dataLen < len + 2 + count)
return WCT_ERR;
if(Mask)
{
maskKey[0] = data[2];
maskKey[1] = data[3];
maskKey[2] = data[4];
maskKey[3] = data[5];
dataStart = 6;
}
else
dataStart = 2;
}
//
if(dataLen < len + dataStart)
return WCT_ERR;
//
if(packageMaxLen < len + 1)
return WCT_ERR;
//
if(Mask) // 解包数据使用掩码时, 使用异或解码, maskKey[4]依次和数据异或运算, 逻辑如下
{
//printf("depackage : len/%d\r\n", len);
for(i = 0, count = 0; i < len; i++)
{
temp1 = maskKey[count];
temp2 = data[i + dataStart];
*package++ = (char)(((~temp1)&temp2) | (temp1&(~temp2))); // 异或运算后得到数据
count += 1;
if((unsigned)count >= sizeof(maskKey)) // maskKey[4]循环使用
count = 0;
//printf("%.2X|%.2X|%.2X, ", temp1, temp2, *(package-1));
}
*package = '\0';
}
else // 解包数据没使用掩码, 直接复制数据段
{
memcpy(package, &data[dataStart], len);
package[len] = '\0';
}
*packageLen = len;
//
return ret;
}
struct bufferevent * ev_webSocket_clientLinkToServer(struct event_base * base ,char *ip, int port, char *interface_path, bufferevent_data_cb read_cb, bufferevent_data_cb write_cb, bufferevent_event_cb event_cb, void * arg)
{
int ret, fd , timeOut;
struct evutil_addrinfo hints;
struct evutil_addrinfo *addr_out = NULL;
//int i;
unsigned char loginBuf[512] = {0}, recBuf[512] = {0}, shakeKey[128] = {0}, *p;
memset(&hints,0 , sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = EVUTIL_AI_ADDRCONFIG;
int err = evutil_getaddrinfo(ip, NULL, &hints, &addr_out);
if(err != 0)
{
De_printf("ev_webSocket_clientLinkToServer:你输入的'%s'无效或者无法解析!/r/n", ip);
De_fprintf(stderr, "ev_webSocket_clientLinkToServer:Error while resoliving '%s':%s",
ip, evutil_gai_strerror(err));
return NULL;
}
assert(addr_out);
// zhd服务器端网络地址结构体
struct sockaddr_in report_addr;
memset(&report_addr,0,sizeof(report_addr)); // 数据初始化--清零
report_addr.sin_family = AF_INET; // 设置为IP通信
report_addr.sin_addr.s_addr = ((struct sockaddr_in *)addr_out->ai_addr)->sin_addr.s_addr;
//report_addr.sin_addr.s_addr = inet_addr(ip); // 服务器IP地址
report_addr.sin_port = htons(port); // 服务器端口号
evutil_freeaddrinfo(addr_out);
if(port<=0)
{
De_printf("ev_webSocket_clientLinkToServer:端口输入错误");
}
//create unix socket
if((fd = socket(AF_INET,SOCK_STREAM, 0)) < 0)
{
De_printf("webSocket_login : cannot create socket\r\n");
return NULL;
}
/*
// 测试 ----- 创建握手key 和 匹配返回key
webSocket_buildShakeKey(shakeKey);
printf("key1:%s\r\n", shakeKey);
webSocket_buildRespondShakeKey(shakeKey, strlen(shakeKey), shakeKey);
printf("key2:%s\r\n", shakeKey);
*/
//非阻塞
ret = fcntl(fd , F_GETFL , 0);
fcntl(fd , F_SETFL , ret | O_NONBLOCK);
//connect
timeOut = 0;
while(connect(fd , (struct sockaddr *)&report_addr,sizeof(struct sockaddr)) == -1)
{
if(++timeOut > REPORT_LOGIN_CONNECT_TIMEOUT)
{
printf("webSocket_login : %s:%d cannot connect ! %d\r\n" , ip, port, timeOut);
//
sprintf((char *)loginBuf, "webSocket_login : %s:%d cannot connect ! %d" , ip, port, timeOut);
close(fd);
return NULL;
}
delayms(1); //1ms
}
//发送http协议头
memset(shakeKey, 0, sizeof(shakeKey));
webSocket_buildShakeKey(shakeKey); // 创建握手key
memset(loginBuf, 0, sizeof(loginBuf)); // 创建协议包
webSocket_buildHttpHead(ip, port, interface_path, shakeKey, (char *)loginBuf);
// 发出协议包
ret = send(fd , loginBuf , strlen((const char*)loginBuf) , MSG_NOSIGNAL);
//
//printf("\r\nconnect time : %d\r\nsend:\n%s\r\n" , timeOut, loginBuf);
while(1)
{
memset(recBuf , 0 , sizeof(recBuf));
ret = recv(fd , recBuf , sizeof(recBuf) , MSG_NOSIGNAL);
if(ret > 0)
{
if(strncmp((const char *)recBuf, (const char *)"HTTP", strlen((const char *)"HTTP")) == 0) // 返回的是http回应信息
{
//printf("\r\nlogin_recv : %d / %d\r\n%s\r\n" , ret, timeOut, recBuf);
if((p = (unsigned char *)strstr((const char *)recBuf, (const char *)"Sec-WebSocket-Accept: ")) != NULL) // 检查握手信号
{
p += strlen((const char *)"Sec-WebSocket-Accept: ");
sscanf((const char *)p, "%s\r\n", p);
if(webSocket_matchShakeKey(shakeKey, strlen((const char *)shakeKey), p, strlen((const char *)p)) == 0) // 握手成功, 发送登录数据包
{
//创建bufferevnt
struct bufferevent * bufferev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bufferev, read_cb, write_cb, event_cb, arg);
bufferevent_enable(bufferev, EV_READ| EV_WRITE);
return bufferev;
}
else // 握手信号不对, 重发协议包
{
ret = send(fd , loginBuf , strlen((const char*)loginBuf) , MSG_NOSIGNAL); // 重发协议包
}
}
else
{
ret = send(fd , loginBuf , strlen((const char*)loginBuf) , MSG_NOSIGNAL); // 重发协议包
}
}/*
else
{
// 显示数据
if(recBuf[0] >= ' ' && recBuf[0] <= '~')
{
printf("\r\nlogin_recv : %d\r\n%s\r\n" , ret, recBuf);
}
else
{
printf("\r\nlogin_recv : %d\r\n" , ret); for(i = 0; i < ret; i++) printf("%.2X ", recBuf[i]); printf("\r\n");
}
}*/
}
else if(ret <= 0)
{
;
}
if(++timeOut > REPORT_LOGIN_RESPOND_TIMEOUT)
{
close(fd);
return NULL;
}
delayms(1); //1ms
}
//
close(fd);
return NULL;
}
int ev_webSocket_serverLinkToClient(struct bufferevent * client, char *recvBuf, unsigned int bufLen)
{
char *p;
int ret;
char recvShakeKey[512], respondPackage[1024];
if(bufLen==0)
return -1;
if((p = strstr(recvBuf, "Sec-WebSocket-Key: ")) == NULL)
return -1;
p += strlen("Sec-WebSocket-Key: ");
//
memset(recvShakeKey, 0, sizeof(recvShakeKey));
sscanf(p, "%s", recvShakeKey); // 取得握手key
ret = strlen(recvShakeKey);
if(ret < 1)
return -1;
//
memset(respondPackage, 0, sizeof(respondPackage));
webSocket_buildHttpRespond((unsigned char*)recvShakeKey,(unsigned int)ret, ( char *)respondPackage);
//
return bufferevent_write(client,respondPackage, strlen(respondPackage));
}
int ev_webSocket_send(struct bufferevent * bufferev, unsigned char *data, unsigned int dataLen, bool mod, Websocket_CommunicationType type)
{
unsigned char *webSocketPackage;
unsigned int retLen, ret;
/* unsigned int i; */
/* printf("webSocket_send : %d\r\n", dataLen); */
//---------- websocket数据打包 ----------
webSocketPackage = (unsigned char *)calloc(1, sizeof(char)*(dataLen + 128)); memset(webSocketPackage, 0, (dataLen + 128));
retLen = webSocket_enPackage(data, dataLen, webSocketPackage, (dataLen + 128), mod, type);
/* printf("webSocket_send : %d\r\n" , retLen); */
/* for(i = 0; i < retLen; i ++) printf("%.2X ", webSocketPackage[i]); */
/* printf("\r\n"); */
ret = bufferevent_write(bufferev, webSocketPackage, retLen);
free(webSocketPackage);
return ret;
}
int ev_webSocket_recv(struct bufferevent * bufferev, unsigned char **data, unsigned int *dataLen, Websocket_CommunicationType *type)
{
unsigned char *webSocketPackage, *recvBuf, *temp, *temp3;
int ret=0, ret2 = 0, len=0, temp2 = 0, i, in_len = 0, buff_len = 0;
unsigned int retLen = 0, start_inedx = 0, timer_out = 0;
//int i;
buff_len = 1024;
recvBuf = (unsigned char *)calloc(1, sizeof(char)*1024); memset(recvBuf, 0, 1024);
temp3 = temp = recvBuf;
bufferevent_disable(bufferev, EV_READ);
while(in_len == 0 || len < in_len)
{
ret = bufferevent_read(bufferev, temp, 1024);
if(ret>=0)
len += ret;
else
{
De_printf("webSocket read Data error!\r\n");
free(recvBuf);
bufferevent_enable(bufferev, EV_READ);
return WCT_ERR_EVB;
}
if(!temp2)
{
for(i=0;i<ret;i++)
{
if(webSocket_getInType(temp3) != WCT_ERR)
{
temp2 = 1;
break;
}
temp3++;
len--;
start_inedx++;
}
}
if(in_len == 0 && temp2 != 0 && len >= 3)
{
in_len = webSocket_getInLen(temp3, len);
if(in_len <= 0)
{
De_printf("webSocket Data error!\r\n");
free(recvBuf);
bufferevent_enable(bufferev, EV_READ);
return WCT_ERR_DATA;
}
}
if(ret == 1024)
{
buff_len += 1024;
recvBuf = (unsigned char *) realloc(recvBuf, buff_len);
temp = recvBuf + len + start_inedx;
temp3 = recvBuf + start_inedx;
}
else
temp += ret;
if(ret == 0)
{
timer_out++;
if(timer_out >= RECV_DATA_TIME_OUT)
{
De_printf("webSocket read data time out!\r\n");
free(recvBuf);
bufferevent_enable(bufferev, EV_READ);
return WCT_ERR_DATA_TIMEOUT;
}
}
else
timer_out = 0;
}
bufferevent_enable(bufferev, EV_READ);
if(len > 0)
{
//---------- websocket数据打包 ----------
webSocketPackage = (unsigned char *)calloc(1, sizeof(char)*(len + 128)); memset(webSocketPackage, 0, (len + 128));
ret2 = webSocket_dePackage(temp3, ret, webSocketPackage, (len + 128), &retLen);
if(ret2 == WCT_PING && retLen > 0) // 解析为ping包, 自动回pong
{
ev_webSocket_send(bufferev, webSocketPackage, retLen, true, WCT_PONG);
// 显示数据
De_printf("webSocket_recv : PING %d\r\n%s\r\n" , retLen, webSocketPackage);
free(recvBuf);
free(webSocketPackage);
return WCT_NULL;
}
else if(retLen > 0 && (ret2 == WCT_TXTDATA || ret2 == WCT_BINDATA || ret2 == WCT_MINDATA)) // 解析为数据包
{
*data= (unsigned char*)malloc(retLen);
if(*data == NULL)
{
free(recvBuf);
free(webSocketPackage);
return WCT_ERR_MEM;
}
memcpy(*data, webSocketPackage, retLen); // 把解析得到的数据复制出去
/*
// 显示数据
if(webSocketPackage[0] >= ' ' && webSocketPackage[0] <= '~')
{
printf("\r\nwebSocket_recv : New Package StrFile ret2:%d/retLen:%d\r\n%s\r\n" , ret2, retLen, webSocketPackage);
}
else
{
printf("\r\nwebSocket_recv : New Package BinFile ret2:%d/retLen:%d\r\n" , ret2, retLen);
for(i = 0; i < retLen; i++) printf("%.2X ", webSocketPackage[i]); printf("\r\n");
}*/
free(recvBuf);
free(webSocketPackage);
*dataLen = retLen;
*type = (Websocket_CommunicationType)ret2;
return retLen;
}
else if(retLen > 0 && (ret2 == WCT_DISCONN))
{
free(recvBuf);
free(webSocketPackage);
*type = (Websocket_CommunicationType)WCT_DISCONN;
return WCT_DISCONN;
} /*
else
{
// 显示数据
if(recvBuf[0] >= ' ' && recvBuf[0] <= '~')
printf("\r\nwebSocket_recv : ret:%d/ret2:%d/retLen:%d\r\n%s\r\n" , ret, ret2, retLen, recvBuf);
else
{
printf("\r\nwebSocket_recv : ret:%d/ret2:%d/retLen:%d\r\n%s\r\n" , ret, ret2, retLen, recvBuf);
for(i = 0; i < ret; i++) printf("%.2X ", recvBuf[i]); printf("\r\n");
}
}*/
free(recvBuf);
free(webSocketPackage);
return ret2;
}
else
{
free(recvBuf);
return WCT_ERR_EVB;
}
}
void delayms(unsigned int ms)
{
struct timeval tim;
tim.tv_sec = ms/1000;
tim.tv_usec = (ms%1000)*1000;
select(0, NULL, NULL, NULL, &tim);
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/sszl_blog/webSocket_Libevent_ThreadPool.git
[email protected]:sszl_blog/webSocket_Libevent_ThreadPool.git
sszl_blog
webSocket_Libevent_ThreadPool
webSocket_Libevent_ThreadPool
master

搜索帮助