tcp_session_manager.c代码分析中篇

本篇主要分析tcp_session_manager.c中出现的函数

一、相关链接

和本篇代码相关的一些背景知识和该文件的上一部分代码详解:

tcp_socket机制详解

互斥锁和消息队列详解

tcp_session详解

tcp_session_manager.c代码分析上篇

二、代码分析

static bool AssignValue2Session(TcpSession *session, cJSON *receiveObj)
//标记值转换到session
{
    if (receiveObj == NULL) {
        return false;
        //检查参数
    }

    char *recvBus = GetJsonString(receiveObj, "BUS_NAME");
    //通过参数获取jsonstring
    if (recvBus == NULL) {
        return false;
        //检查上一步是否成功获取
    }
    if (strncpy_s(session->sessionName, NAME_LENGTH, recvBus, strlen(recvBus)) != 0) {
        return false;
    }

    char *sessionKeyEncoded = GetJsonString(receiveObj, "SESSION_KEY");
    //获取sessionkey的json.string值
    if (sessionKeyEncoded == NULL) {
        return false;//检查是否获取成功
    }
    size_t olen = 0;
    int ret = mbedtls_base64_decode((unsigned char *)session->sessionKey, SESSION_KEY_LENGTH,
        &olen, (unsigned char *)sessionKeyEncoded, strlen(sessionKeyEncoded));
    //基于base64进行编码
    if (ret != 0) {
        SOFTBUS_PRINT("[TRANS] AssignValue2Session mbedtls_base64_decode error: %d\n", ret);
        return false;
        //用来检查是否编码成功
    }

    SOFTBUS_PRINT("[TRANS] AssignValue2Session busname=%s, fd=%d\n", session->sessionName, session->fd);
    return true;
}

static bool ResponseToClient(TcpSession *session)//客户端响应函数
{
    cJSON *jsonObj = cJSON_CreateObject();
    if (jsonObj == NULL) {
        return false;
    }

    GetReplyMsg(jsonObj, session);//接受回复的消息
    char *msg = cJSON_PrintUnformatted(jsonObj);
    //将jsonObj转换为字符串数据
    if (msg == NULL) {
        cJSON_Delete(jsonObj);
        return false;、
        //检查是否转换成功
    }

    int bufLen = 0;
    unsigned char *buf = PackBytes(msg, &bufLen);
    //打包数据
    if (buf == NULL) {
        SOFTBUS_PRINT("[TRANS] ResponseToClient PackBytes fail\n");

        free(msg);
        cJSON_Delete(jsonObj);
        return false;
    }

    int dataLen = TcpSendData(session->fd, (char*)buf, bufLen, 0);
    //发送数据到tcp连接的另一端,datalen的值为发送的数据大小
    free(msg);
    cJSON_Delete(jsonObj);
    free(buf);
    if (dataLen <= 0) {
        SOFTBUS_PRINT("[TRANS] ResponseToClient TcpSendData fail\n");
        return false;
        //检查数据是否发送到tcp另一端
    }
    return true;
}

static bool HandleRequestMsg(TcpSession *session)
//用来处理用户请求消息
{
    char data[RECIVED_BUFF_SIZE] = { 0 };//初始化数组
    int size = TcpRecvData(session->fd, data, AUTH_PACKET_HEAD_SIZE, 0);
    //size为接收信息的数据大小
	if (size != AUTH_PACKET_HEAD_SIZE) {
		return false;
        //检查接受的数据大小是否和用户数据包大小相同
	}
    int identifier = GetIntFromBuf(data, 0); 用来将data中内容以offset=0的偏置进行复制信息

    if ((unsigned int)identifier != PKG_HEADER_IDENTIFIER) {
        return false;
        //检查是否复制成功
    }
	int dataLen = GetIntFromBuf(data, AUTH_PACKET_HEAD_SIZE - sizeof(int));
	if (dataLen + AUTH_PACKET_HEAD_SIZE >= RECIVED_BUFF_SIZE) {
		return false;
	}
	int total = size;
	int remain = dataLen;
	while (remain > 0) {
		size = TcpRecvData(session->fd, data + total, remain, 0);
		remain -= size;
		total += size;
	}
    //如果有接收到数据,就将用户发送的信息不断接收到data当中(位置为data首地址+total)
    cJSON *receiveObj = TransFirstPkg2Json(data, dataLen + AUTH_PACKET_HEAD_SIZE);
    if (receiveObj == NULL) {
        return false;
    }
    int ret = AssignValue2Session(session, receiveObj);
    cJSON_Delete(receiveObj);
    if (ret != true) {
        return false;
    }
    //以上为两种数据的类型转换
    SessionListenerMap *sessionListener = GetSessionListenerByName(session->sessionName, strlen(session->sessionName));
    //通过name来启动监听
    if (sessionListener == NULL) {
        return false;
    }
    if (!ResponseToClient(session)) {
        SOFTBUS_PRINT("[TRANS] HandleRequestMsg ResponseToClient fail\n");
        return false;
        //响应到客户端
    }
    if (sessionListener->listener == NULL) {
        return false;
    }
    if (sessionListener->listener->onSessionOpened == NULL) {
        return false;
    }
    if (sessionListener->listener->onSessionOpened(session->fd) != 0) {
        return false;
    }
    //检测会话监听和相关session是否打开
    return true;
}

static void FreeSessionRecvMem(char* recvDataBuf, TcpSession* session)//释放会话接收成员
{
    if (recvDataBuf != NULL) {
        free(recvDataBuf);
        //检查如果传入的数组recvDataBuf不为空,就释放空间。
    }
    if (session == NULL) {
        return;
    }

    CloseSession(session->fd);//根据传入的session,获取套接字关闭相应文件设备
}

static int32_t TcpSessionRecv(TcpSession *session, const char* buf, uint32_t size, int timeout)
{
    if (buf == NULL || session == NULL || session->fd < 0 || size <= 0 || timeout < 0) {
        return TRANS_FAILED;
        //参数检查
    }

    char *recvDataBuf = calloc(1, size + OVERHEAD_LEN);
    //calloc函数申请一个size+OVERHEAD_LEN大小的
    if (recvDataBuf == NULL) {
        return TRANS_FAILED;
        //接收数据的缓冲区为空的话函数返回
    }
    int recvSize = TcpRecvData(session->fd, recvDataBuf, size + OVERHEAD_LEN, 0);
    //从tcp的另一端接收数据,返回接受数据的大小
    if (recvSize < TRANS_PACKET_HEAD_SIZE) {
        FreeSessionRecvMem(recvDataBuf, session);
        return TRANS_FAILED;
        //接受的数据小于传输数据,就释放session会话成员
    }

    long long seq = 0;
    AesGcmCipherKey cipherKey = {0};
    cipherKey.keybits = GCM_KEY_BITS_LEN_256;
    int ret = memcpy_s(&seq, SIZE_OF_LONG_LONG, recvDataBuf + TRANS_SEQ_NUM_OFFSET, SIZE_OF_LONG_LONG);//复制recvDataBuf + TRANS_SEQ_NUM_OFFSET开始的内容到seq
    ret += memcpy_s(cipherKey.key, SESSION_KEY_LENGTH, session->sessionKey, SESSION_KEY_LENGTH);
    ret += memcpy_s(cipherKey.iv, IV_LEN, recvDataBuf + TRANS_PACKET_HEAD_SIZE, IV_LEN);
    //将接受的数据赋值进seq和cipherKey.iv,将对应session的键值复制进cipherKey.key
    if (ret != 0) {
        FreeSessionRecvMem(recvDataBuf, session);
        return TRANS_FAILED;
        //同来检查前面的复制是否存在失败,只要存在失败便ret<0
    }

    SessionSeqNumNode* node = calloc(1, sizeof(SessionSeqNumNode));//申请一个sizeof(SessionSeqNumNode)大小的数组
    if (node == NULL) {
        FreeSessionRecvMem(recvDataBuf, session);
        return TRANS_FAILED;
    }
    node->seqNum = seq;
    ListInsertTail(session->seqNumList, &(node->head));//将&(node->head)插入链表session->seqNumList

    int plainLen = DecryptTransData(&cipherKey, (unsigned char*)(recvDataBuf + TRANS_PACKET_HEAD_SIZE),
        recvSize - TRANS_PACKET_HEAD_SIZE, (unsigned char*)buf, size);
        //对cipherKey密钥进行加密
    free(recvDataBuf);//释放数据缓冲
    if (plainLen <= 0) {
        return TRANS_FAILED;
    }

    return plainLen;
}

static bool OnProcessDataAvailable(TcpSession *session)
{
    if (session == NULL) {
        return false;
    }

    if (strcmp(session->sessionName, "softbus_Lite_unknown") == 0) {
        //比较会话名和softbus_Lite_unknown是否相同
        bool isSuccess = HandleRequestMsg(session);
        if (!isSuccess) {
            //如果处理请求信息不成功就关闭session—>fd套接字对应设备
            CloseSession(session->fd);
        }
        return isSuccess;
    } else {//如果
        unsigned char* buf = calloc(1, RECIVED_BUFF_SIZE);
        if (buf == NULL) {
            return false;
        }
        SOFTBUS_PRINT("[TRANS] OnProcessDataAvailable sessionName: %s, fd: %d\n", session->sessionName, session->fd);
        SessionListenerMap *sessionListener = GetSessionListenerByName(session->sessionName,
            strlen(session->sessionName));
        if (sessionListener != NULL && sessionListener->listener != NULL) {
            int recvLen = TcpSessionRecv(session, (char *)buf, RECIVED_BUFF_SIZE, 0);
            if (recvLen < 0) {
                free(buf);
                return false;
            }
            sessionListener->listener->onBytesReceived(session->fd, buf, recvLen);
            free(buf);
            return true;
        }
        free(buf);
    }

    return false;
}

static void ProcessSesssionData(const TcpSessionMgr *tsm, const fd_set *rfds)
{
    for (int i = 0; i < MAX_SESSION_SUM_NUM; i++) {
        if (tsm->sessionMap_[i] != NULL && tsm->sessionMap_[i]->fd != -1 &&
            FD_ISSET(tsm->sessionMap_[i]->fd, rfds) > 0) {
            if (!OnProcessDataAvailable(tsm->sessionMap_[i])) {
                return;
            }
        }
    }
}

static void ProcessData(TcpSessionMgr *tsm, fd_set *rfds)//来检查tsm变量的监听套接字是否在集合rfds中,在的话根据套接字连接监听的进程
{
    if (tsm == NULL || tsm->listenFd == -1) {
        return;
    }

    if (FD_ISSET(tsm->listenFd, rfds)) {
        ProcessConnection(tsm);
        return;
    }

    ProcessSesssionData(tsm, rfds);
}

static void FreeSessionMgr(void)//释放会话管理  
{
    free(g_sessionMgr);
    g_sessionMgr = NULL;
}