/* socket收包缓存; by dzj, 09.06.16 */ #include "rcvbuf.h" #include "apppoolobjs.h" ///每次收包后调用,以向应用递送收到的完整包,返回值:表明解析包是否成功,如果解析失败,则需要断开连接(没有收到完整包的情形算解析成功); #ifdef USE_CRYPT bool CRcvBuf::SubmitValidPkg( DsCryptBF& cryptIns, LSOCKET_QUEUE* rcvAppQueue/*用于向应用递送消息的队列*/, bool& isAppNeedNoti ) #else //USE_CRYPT bool CRcvBuf::SubmitValidPkg( LSOCKET_QUEUE* rcvAppQueue/*用于向应用递送消息的队列*/, bool& isAppNeedNoti ) #endif //USE_CRYPT { //1、检查所有收到的完整包 //2、剩余的非完整收包移至缓存开头 if ( NULL == rcvAppQueue ) { NewLog( LOG_LEV_ERROR, "SubmitValidPkg,收包队列空" ); return false;//收包队列空,不可能事件; } m_curReadPos = 0;//新收包总是从头开始读; unsigned short pkgLen = 0;//已收完整包长度,消息中此长度为两字节short; bool isParseErr = false; while ( IsPkgValid( pkgLen, isParseErr ) ) { if ( pkgLen > ( m_curTail-m_curReadPos ) ) { NewLog( LOG_LEV_DEBUG, "SubmitValidPkg,解包长度失败!" ); return false; } #ifdef USE_CRYPT //加密标志检测; bool isNeedStCrypt = false; if ( sizeof(StEncDec) == pkgLen ) { if ( !(cryptIns.IsStRcvCrypt()) ) { //尚未开始接收解密,检测是否为开启接收解密指示; StEncDec* tmpRcv = (StEncDec*)&(m_InnerRcvBuf[m_curReadPos]); if ( tmpRcv->IsValidStEncDec() ) { //NewLog( LOG_LEV_DEBUG, "收到接收加密开始标记,长度%d", pkgLen ); //往后收包为加密包,将设置接收加密开始; isNeedStCrypt = true; } } } if ( !isNeedStCrypt ) { //如果有除解密开始消息之外的完整收包,则向应用递送; //解密输出outPkg为包类型+命令字+pContent; //包内容(命令字+pContent)上递; NewMsgToPut* newMsg = g_MsgToPutPool->DsRetrieve( MsgToPutNO ); if ( NULL == newMsg ) { NewLog( LOG_LEV_ERROR, "SubmitValidPkg,NewMsgToPut内存分配失败!" ); return false; } //NewLog( LOG_LEV_DEBUG, "SubmitValidPkg,取NewMsgToPut成功" ); unsigned char decbuf[1024]; unsigned int decbuflen = sizeof(decbuf); char* decedPkg = NULL; unsigned int decedLen = 0; unsigned int timeinfo = 0; bool isDecOK = cryptIns.DecryptRcvPkg( (const unsigned char*)&(m_InnerRcvBuf[m_curReadPos+sizeof(short)/*加密包长字段*/]) , pkgLen-sizeof(short), decbuf, decbuflen, (unsigned char*&)decedPkg, decedLen , timeinfo, true ); if ( !isDecOK ) { NewLog( LOG_LEV_DEBUG, "SubmitValidPkg,解密消息失败!" ); g_MsgToPutPool->DsRelease( MsgToPutNO, newMsg ); return false;//包解密失败; } //if ( cryptIns.IsStRcvCrypt() ) //{ // NewLog( LOG_LEV_DEBUG, "收到加密包,长度%d:%d", pkgLen, decedLen ); //} else { // NewLog( LOG_LEV_DEBUG, "收到明文包,长度%d:%d", pkgLen, decedLen ); //} if ( ( NULL == decedPkg ) || ( decedLen <= 0 ) || ( decedLen > sizeof(newMsg->msgBuf) ) ) { NewLog( LOG_LEV_DEBUG, "SubmitValidPkg,解密后消息长度校验失败!" ); g_MsgToPutPool->DsRelease( MsgToPutNO, newMsg ); return false; } unsigned short wCmd = *( (unsigned short*) (&(decedPkg[1])/*跳过包类型*/) ); MUX_PROTO::CliProtocol* tmpPro = GET_TLS_CLIPRO(); if ( NULL == tmpPro ) { printf( "CRcvBuf::SubmitValidPkg, NULL == tmpPro, with USE_CRYPT\n" );//由于此时tlsLog也可能无效,故用printf; return false; } newMsg->msgLen = (int) ( tmpPro->DeCode( wCmd/*命令字*/, newMsg->msgBuf/*输出缓存*/ , sizeof(newMsg->msgBuf)/*输出缓存大小*/, &(decedPkg[3])/*输入缓存,不包括头上的包类型与命令字*/, decedLen-3/*输入缓存大小*/ ) ); if ( newMsg->msgLen < 0 ) { NewLog( LOG_LEV_DEBUG, "SubmitValidPkg,向应用递送消息%x,解包失败!", wCmd ); g_MsgToPutPool->DsRelease( MsgToPutNO, newMsg ); return false; } newMsg->msgCmd = wCmd;//准备向应用递送,本次消息命令字; newMsg->timeInfo = timeinfo;//准备向应用递送,本次消息时间信息; bool ispushok = false; int trynum = 0; do { ++trynum; ispushok = rcvAppQueue->PushEle( &newMsg, 1 ); if ( trynum > 500 ) { NewLog( LOG_LEV_DEBUG, "SubmitValidPkg,向应用递送消息%x,连续压队列失败!", wCmd ); //delete newMsg; g_MsgToPutPool->DsRelease( MsgToPutNO, newMsg ); newMsg = NULL; return false; } } while ( !ispushok ); isAppNeedNoti = true;//需要通知应用有新的收包; } else { //收包解密开始标志; cryptIns.StRcvCrypt(); } m_curReadPos += pkgLen;//读指针前移; #else //USE_CRYPT //如果有完整收包,则向应用递送; NewMsgToPut* newMsg = g_MsgToPutPool->DsRetrieve( MsgToPutNO ); if ( NULL == newMsg ) { NewLog( LOG_LEV_ERROR, "SubmitValidPkg,NewMsgToPut内存分配失败!" ); return false; } //NewLog( LOG_LEV_DEBUG, "SubmitValidPkg,取NewMsgToPut成功" ); //包内容(命令字+pContent)上递; unsigned short wCmd = *( (unsigned short*) (&(m_InnerRcvBuf[m_curReadPos+3])) ); MUX_PROTO::CliProtocol* tmpPro = GET_TLS_CLIPRO(); if ( NULL == tmpPro ) { printf( "CRcvBuf::SubmitValidPkg, NULL == tmpPro, without USE_CRYPT\n" );//由于此时tlsLog也可能无效,故用printf; return false; } newMsg->msgLen = (int) ( tmpPro->DeCode( wCmd/*命令字*/, newMsg->msgBuf/*输出缓存*/ , sizeof(newMsg->msgBuf)/*输出缓存大小*/, &(m_InnerRcvBuf[m_curReadPos+5])/*输入缓存,不包括头上的命令字*/, pkgLen-5/*输入缓存大小*/ ) ); if ( newMsg->msgLen < 0 ) { NewLog( LOG_LEV_DEBUG, "SubmitValidPkg,向应用递送消息%x,解包失败!", wCmd ); g_MsgToPutPool->DsRelease( MsgToPutNO, newMsg ); return false; } newMsg->msgCmd = wCmd;//消息命令字; newMsg->timeInfo = 0;//非加密通信中不传递时间信息; //newMsg->msgLen = pkgLen - 3;//去掉byPkgType //memcpy( newMsg->msgBuf, &(m_InnerRcvBuf[m_curReadPos+3]), pkgLen-3 );//包内容(命令字+pContent)上递; bool ispushok = false; int trynum = 0; do { ++trynum; ispushok = rcvAppQueue->PushEle( &newMsg, 1 ); if ( trynum > 500 ) { NewLog( LOG_LEV_DEBUG, "SubmitValidPkg,向应用递送消息%x,连续压队列失败!", wCmd ); //delete newMsg; g_MsgToPutPool->DsRelease( MsgToPutNO, newMsg ); newMsg = NULL; return false; } } while ( !ispushok ); isAppNeedNoti = true;//需要通知应用有新的收包; m_curReadPos += pkgLen;//读指针前移; #endif //USE_CRYPT } if ( isParseErr ) { //解析错误; Reset(); return false; } unsigned int partPkgLen = m_curTail-m_curReadPos; if ( m_curReadPos != 0 )//头部是否有移动过,如果移动过,说明处理过收包,否则,如果没有处理过收包,则尾部也不需要动; { if ( partPkgLen > 0 ) { //有未收完的包,将其移至缓存区首; memmove( m_InnerRcvBuf, &(m_InnerRcvBuf[m_curReadPos]), m_curTail-m_curReadPos ); m_curTail = partPkgLen;//新的尾部 } else { m_curTail = 0;//新的尾部; } m_curReadPos = 0; } return true;//无解析错; }