#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <time.h>
#include <stdint.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "websocket.h"
#include "http_server_module.h"
#define WEBSOCKET_GET_CHAR_FOR_HEADER_1()\
do {\
if (i < pSession->websocket_header_len)\
{\
temp_char = pSession->websocket_header[i];\
i++;\
}\
else if (j < left_len)\
{\
temp_char = ws_proto[j + index];\
j++;\
}\
else\
{\
if ((pSession->websocket_header_len + left_len) > 14)\
{\
printf("websocket parse error websocket_len is longer than 14 (%d)\n", (pSession->websocket_header_len + i));\
return -1;\
}\
else\
{\
memcpy(pSession->websocket_header + pSession->websocket_header_len, ws_proto + index, left_len);\
pSession->websocket_header_len += left_len;\
return 0;\
}\
}\
}while (0)
#define WEBSOCKET_GET_CHAR_FOR_HEADER_2() \
do {\
if (j < left_len)\
{\
temp_char = ws_proto[j + index];\
j++;\
}\
else\
{\
if (left_len > 14)\
{\
printf("websocket parse error websocket_len is longer than 14 (%d)\n", left_len);\
return -1;\
}\
else\
{\
memcpy(pSession->websocket_header, ws_proto + index, left_len);\
pSession->websocket_header_len = left_len;\
return 0;\
}\
}\
}while (0)
//static char s_encode[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
#define char_isnum(c) ('0'<=(c) && '9'>=(c))
#define char_isalpha(c) (('a'<=(c) && 'z'>=(c)) || ('A'<=(c) && 'Z'>=(c)))
#define char_isalnum(c) (char_isnum(c) || char_isalpha(c))
#define char_ishex(c) (char_isnum(c) || ('a'<=(c)&&'f'>=(c)) || ('A'<=(c) && 'F'>=(c)))
static inline char HEX(char c)
{
return char_isnum(c) ? c-'0' : (char)tolower(c)-'a'+10;
}
S32 websocket_decode(TPHTTPSERVERSESSION *pSession, U8 *ws_proto, S32 len)
{
U8 payload_len = 0;
U8 mask[5] = {0};
U8 protocol[4096] = {0};
S32 protocol_len = 0;
S32 i = 0;
S32 j = 0;
S32 read_len = 0;
S32 parse_len = 0;
U8 temp_char;
S32 index = 0;
S32 left_len = len;
//U8 fn;
S32 fm_type;
U8 mask_flag = 0;
U8 *write_pos = ws_proto;
if (!ws_proto || len < 0)
{
HTTP_ERROR("invalid params");
return -1;
}
if (!pSession->is_web_upgrade)
{
HTTP_ERROR("web did not upgrade, no need to decode");
return len;
}
if (pSession->websocket_frame_left > 0)
{
read_len = len > pSession->websocket_frame_left ? pSession->websocket_frame_left:len;
parse_len = read_len;
do
{
for(i = 0, j = pSession->websocket_mask_index; i < parse_len && i < 4096; i++, j++)
{
protocol[i] = ws_proto[index + i] ^ pSession->websocket_mask[j % 4];
}
protocol[i] = '\0';
// printf("\n%s(%d):change recv:%s\n", __FUNCTION__, __LINE__, protocol);
memcpy(write_pos, protocol, i);
write_pos += i;
pSession->websocket_mask_index = j;
parse_len -= i;
index += i;
} while (parse_len > 0);
pSession->websocket_frame_left -= read_len;
left_len -= read_len;
}
if (left_len <= 0)
{
memset(write_pos, 0, len -(write_pos - ws_proto));
return write_pos - ws_proto;
}
while (left_len > 0)
{
if(pSession->websocket_header_len > 0)
{
i = 0;
j = 0;
WEBSOCKET_GET_CHAR_FOR_HEADER_1();
//fn = (temp_char & 0x80) >> 7;
fm_type = temp_char & 0x0f;
WEBSOCKET_GET_CHAR_FOR_HEADER_1();
mask_flag = (temp_char & 0x80) >> 7;
payload_len = temp_char & 0x7f;
if (payload_len <= 125)
{
protocol_len = payload_len;
}
else if (payload_len == 126)
{
WEBSOCKET_GET_CHAR_FOR_HEADER_1();
protocol_len = temp_char;
WEBSOCKET_GET_CHAR_FOR_HEADER_1();
protocol_len = (protocol_len << 8) | temp_char;
}
else
{
////payloadÌ«³¤,µ±Ç°ÐÒéÖв»Ó¦³öÏÖ
HTTP_ERROR("websocket payload len is more than 65535");
return -1;
}
if (mask_flag)
{
WEBSOCKET_GET_CHAR_FOR_HEADER_1();
mask[0] = temp_char;
WEBSOCKET_GET_CHAR_FOR_HEADER_1();
mask[1] = temp_char;
WEBSOCKET_GET_CHAR_FOR_HEADER_1();
mask[2] = temp_char;
WEBSOCKET_GET_CHAR_FOR_HEADER_1();
mask[3] = temp_char;
}
index += j;
left_len -= j;
pSession->websocket_header_len = 0;
// printf("\n%s(%d):fin:%d, type:%d, mask:%d, payload_len:%d, protocol_len:%d\n", __FUNCTION__, __LINE__, fn, fm_type, mask_flag,payload_len, protocol_len);
}
else
{
j = 0;
WEBSOCKET_GET_CHAR_FOR_HEADER_2();
//fn = (temp_char & 0x80) >> 7;
fm_type = temp_char & 0x0f;
WEBSOCKET_GET_CHAR_FOR_HEADER_2();
mask_flag = (temp_char & 0x80) >> 7;
payload_len = temp_char & 0x7f;
if (payload_len <= 125)
{
protocol_len = payload_len;
}
else if (payload_len == 126)
{
WEBSOCKET_GET_CHAR_FOR_HEADER_2();
protocol_len = temp_char;
WEBSOCKET_GET_CHAR_FOR_HEADER_2();
protocol_len = (protocol_len << 8) | temp_char;
}
else
{
//payloadÌ«³¤,µ±Ç°ÐÒéÖв»Ó¦³öÏÖ
HTTP_ERROR("websocket payload len is more than 65535");
return -1;
}
if (mask_flag)
{
WEBSOCKET_GET_CHAR_FOR_HEADER_2();
mask[0] = temp_char;
WEBSOCKET_GET_CHAR_FOR_HEADER_2();
mask[1] = temp_char;
WEBSOCKET_GET_CHAR_FOR_HEADER_2();
mask[2] = temp_char;
WEBSOCKET_GET_CHAR_FOR_HEADER_2();
mask[3] = temp_char;
}
else
{
memset(mask, 0 , 4);
}
index += j;
left_len -= j;
pSession->websocket_header_len = 0;
// printf("\n%s(%d):fin:%d, type:%d, mask:%d, payload_len:%d, protocol_len:%d\n", __FUNCTION__, __LINE__, fn, fm_type, mask_flag,payload_len, protocol_len);
}
if (fm_type == WEBSOCKET_CLOSE_FRAME)
{
HTTP_ERROR("receive stop frame");
return TP_TCP_EC_SOCKET_CLOSE;
}
read_len = left_len > protocol_len ? protocol_len : left_len;
parse_len = read_len;
do
{
for (i = 0; i < parse_len && i < 4096; i++)
{
protocol[i] = ws_proto[i + index] ^ mask[i % 4];
}
protocol[i] = '\0';
// printf("\n%s(%d):change recv:%s\n", __FUNCTION__, __LINE__, protocol);
memcpy(write_pos, protocol, i);
write_pos += i;
index += i;
parse_len -= i;
} while (parse_len > 0);
left_len -= read_len;
}
if (read_len < protocol_len)
{
pSession->websocket_frame_left = protocol_len - read_len;
memcpy(pSession->websocket_mask, mask, 4);
pSession->websocket_mask_index = i % 4;
}
memset(write_pos, 0, len -(write_pos - ws_proto));
return write_pos - ws_proto;
}
int websocket_server_header_add(unsigned char *buf, int data_len, int data_type)
{
U8 websocket_header[WEBSOCKET_SERVER_HEADER_MAX_LEN] = {0};
int head_len = 0;
if (!buf || data_len < 0)
{
HTTP_ERROR( "param error");
return -1;
}
websocket_header[0] = 0x80 | data_type;
if (data_len < 126)
{
websocket_header[1] = (data_len & 0xFF);
head_len = 2;
}
else if (data_len < 0xFFFF)
{
websocket_header[1] = 126;
websocket_header[2] = (data_len >> 8 & 0xFF);
websocket_header[3] = (data_len & 0xFF);
head_len = 4;
}
else
{
websocket_header[1] = 127;
//int×î´óËÄ×Ö½Ú
websocket_header[6] = (data_len >> 24) & 0xff;
websocket_header[7] = (data_len >> 16) & 0xff;
websocket_header[8] = (data_len >> 8 & 0xFF);
websocket_header[9] = data_len & 0xff;
head_len = 10;
}
memcpy(buf, websocket_header, head_len);
return head_len;
}
#define WEBSOCKET_RESPONSE "{\"type\":\"response\",\"seq\":%d,\"params\":{\"error_code\":%d}}"
int websocket_reply_error_code(TPHTTPSERVERSESSION *pSession, int error_code)
{
MBUFFERByteArrayReset(&pSession->TXBuffer);
MBUFFERByteArrayPrintf(&pSession->TXBuffer, WEBSOCKET_RESPONSE, pSession->iSessionSeq, error_code);
MBUFFERByteConvert2ReadBuff(&pSession->TXBuffer);
HTTPSessionSend(pSession, &pSession->TXBuffer);
return error_code;
}
int websocket_digest_auth_check(TPHTTPSERVERSESSION *pSession)
{
char cAuthBuf[HTTP_USERNAME_LENGTH] = {0};
char pcContentType[HTTP_SETUP_TRANSPORT_LENGTH];
int iAuthSize = 0;
int iAuthResult = TPHTTP_AUTHENTICATION_FAILURE;
int reply_code = TPHTTP_AUTHENTICATION_OK;
int iHttpMsgHead, iHttpMsgTail, iBufLen;
MBUFFERByteConvert2ReadBuff(&pSession->RXBuffer);
iHttpMsgHead = pSession->RXBuffer.iCurPos;
iHttpMsgTail = MBUFFERByteArrayPeekByte((char *)"}", strlen("}"), &pSession->RXBuffer);
if (iHttpMsgTail == MBUFFER_EC_FAIL)
{
MBUFFERByteConvertBack2WriteBuff(&pSession->RXBuffer);
return HTTP_EC_NEED_MORE_DATA;
}
pSession->RXBuffer.iCurPos = iHttpMsgHead;
if (MBUFFERByteArrayFindString("Content-Type:", &pSession->RXBuffer) != MBUFFER_EC_OK)
{
HTTP_ERROR( "NO Content-Type in http request");
reply_code = TPHTTP_AUTHENTICATION_FAILURE;
goto out;
}
else
{
MBUFFERByteArrayGetStringBySeparator(pcContentType, HTTP_SETUP_TRANSPORT_LENGTH, '\r', &pSession->RXBuffer);
}
if (strncmp(pcContentType, "application/json", strlen("application/json")))
{
HTTP_ERROR("not json content, auth failed");
reply_code = TPHTTP_AUTHENTICATION_FAILURE;
goto out;
}
if (MBUFFERByteArrayFindString((char *)"Authorization:", &pSession->RXBuffer) != MBUFFER_EC_OK)
{
HTTP_ERROR( "NO authorization in request");
reply_code = TPHTTP_AUTHENTICATION_FAILURE;
goto out;
}
if (IsClientAuthDenied(pSession->httpAuthManeger, pSession->pcClientIP) == UNDENIED)
{
HTTP_DEBUG("IP %s is undenied", pSession->pcClientIP);
MBUFFERByteArrayGetStringBySeparator(cAuthBuf, HTTP_USERNAME_LENGTH, '}', &pSession->RXBuffer);
/*收到认证请求将方法置为POST*/
pSession->Method.iMethod = HTTP_POST;
iAuthSize = strlen(cAuthBuf);
#ifdef ACCOUNT_CATAGORY_SUPPORT
iAuthResult = http_do_authentication(cAuthBuf, iAuthSize, pSession->Method.iMethod, pSession->pcHTTPNonce, pSession);
#else
iAuthResult = http_do_authentication(cAuthBuf, iAuthSize, pSession->Method.iMethod, pSession->pcHTTPNonce);
#endif
if (iAuthResult == TPHTTP_AUTHENTICATION_OK)
{
pSession->iNeedAuthentication = 0;
pSession->iSessionState = TPHTTP_SESSION_STATE_INIT;
ProcessValidClientAuth(pSession->httpAuthManeger, pSession->pcClientIP);
HTTP_INFO_LOG("Authentication pass");
}
else
{
pSession->iNeedAuthentication = 1;
ProcessInvalidClientAuth(pSession->httpAuthManeger, pSession->pcClientIP);
HTTP_INFO_LOG("Password is incorrect");
reply_code = TPHTTP_AUTHENTICATION_FAILURE;
}
}
else
{
HTTP_ERROR("IP %s is locked", pSession->pcClientIP);
pSession->iNeedAuthentication = 1;
}
out:
MBUFFERByteArraySeek(0, &pSession->RXBuffer);
iBufLen = MBUFFERByteArrayLength(&pSession->RXBuffer);
MBUFFERByteArrayPutPlaceHolder(0, iBufLen, &pSession->RXBuffer);;
MBUFFERByteArrayReset(&pSession->RXBuffer);
return websocket_reply_error_code(pSession, reply_code);
}
//#define WEBSOCKET_AUTH_NOTIFICATION "{\"type\":\"notification\", \"params\":{\"event_type\":\"websocket_authenticate\", \"realm\":\"%s\", \"algorithm\":\"MD5\", \"qop\":\"auth\", \"nonce\":\"%s\", \"opaque\":\"%s\"}}"
#define WEBSOCKET_AUTH_NOTIFICATION_HTML "Digest realm=\"%s\",algorithm=\"MD5\",encrypt_type=\"3\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\""
int websocket_send_notification_auth(TPHTTPSERVERSESSION *pSession)
{
int iRet, i = 0;
struct timespec CurTimeSpec = {0, 0};
clock_gettime(CLOCK_MONOTONIC, &CurTimeSpec);
srand((unsigned)CurTimeSpec.tv_nsec);
for (i = 0; i < HTTP_AUTH_NOUCE_LENGTH; i++)
{
iRet = rand() % 16;
pSession->pcHTTPNonce[i] = iRet < 10 ? ('0' + iRet) : ('a' + iRet - 10);
}
MBUFFERByteArrayReset(&pSession->TXBuffer);
MBUFFERByteArrayPrintf(&pSession->TXBuffer, WEBSOCKET_AUTH_NOTIFICATION_HTML, gpucHTTPRealm, pSession->pcHTTPNonce, "64943214654649846565646421");
MBUFFERByteConvert2ReadBuff(&pSession->TXBuffer);
HTTPSessionSend(pSession, &pSession->TXBuffer);
return HTTP_EC_OK;
}
LOCAL S32 websocket_geneate_sec_accept(const U8 *sec_key, U32 key_len, U8 *sec_accept, U32 *accept_len)
{
unsigned char sha1_src[WEBSOCKET_SEC_WEBSOCKET_KEY_LEN + WEBSOCKET_HANDSHAKE_GUID_LEN] = {0};
unsigned char sha1_digest[WEBSOCKET_SHA1_DIGEST] = {0};
Sha sha;
memcpy(sha1_src, sec_key, WEBSOCKET_SEC_WEBSOCKET_KEY_LEN);
memcpy(sha1_src + WEBSOCKET_SEC_WEBSOCKET_KEY_LEN, WEBSOCKET_HANDSHAKE_GUID, WEBSOCKET_HANDSHAKE_GUID_LEN);
//sha256
tpssl_InitSha(&sha);
tpssl_ShaUpdate(&sha, (unsigned char *)sha1_src, sizeof(sha1_src));
tpssl_ShaFinal(&sha, (unsigned char *)sha1_digest);
if (tpssl_Base64_Encode(sha1_digest, WEBSOCKET_SHA1_DIGEST, sec_accept, accept_len) == ERROR)
{
HTTP_ERROR("base64 encode error.\n");
return ERROR;
}
return OK;
}
int websocket_handshake(TPHTTPSERVERSESSION *pSession)
{
char key[WEBSOCKET_SEC_WEBSOCKET_KEY_LEN + 1] = {0};
char expectkey[WEBSOCKET_SEC_WEBSOCKET_ACCEPT_LEN + 1] = {0};
U32 expectlen = WEBSOCKET_SEC_WEBSOCKET_ACCEPT_LEN;
if (MBUFFERByteArrayFindString("Sec-WebSocket-Version: 13", &pSession->RXBuffer) != MBUFFER_EC_OK)
{
HTTP_ERROR( "NO Sec-WebSocket-Version in http request");
return HTTP_EC_FAILURE;
}
if (MBUFFERByteArrayFindString((char *)"Sec-WebSocket-Key:", &pSession->RXBuffer) == MBUFFER_EC_OK)
{
MBUFFERByteArrayGetStringBySeparator(key, WEBSOCKET_SEC_WEBSOCKET_KEY_LEN + 1, '\r', &pSession->RXBuffer);
}
else
{
HTTP_ERROR( "NO Sec-WebSocket-Key in http request");
return HTTP_EC_FAILURE;
}
websocket_geneate_sec_accept((U8 *)key, strlen(key), (U8 *)expectkey, &expectlen);
if (expectkey[strlen(expectkey) - 1] == '\n')
{
expectkey[strlen(expectkey) - 1] = '\0';
}
MBUFFERByteArrayReset(&pSession->TXBuffer);
MBUFFERByteArrayPrintf(&pSession->TXBuffer,
"HTTP/1.1 101 Switching Protocols\r\n"
"Server: Streamd\r\n"
"Date: %s\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: %s\r\n"
"Sec-WebSocket-Version: 13\r\n"
"\r\n",
HTTPSessionGetCurTimeInString(pSession),
expectkey
);
MBUFFERByteConvert2ReadBuff(&pSession->TXBuffer);
HTTPSessionSend(pSession, &pSession->TXBuffer);
memset(pSession->pcBoundaryType, 0, HTTP_SETUP_TRANSPORT_LENGTH);
memcpy(pSession->pcBoundaryType, MULTIPART_BOUNDARY, strlen(MULTIPART_BOUNDARY));
pSession->is_web_upgrade = 1;
return websocket_send_notification_auth(pSession);
}解释代码