鸿蒙源码分析(十)

tcp_session_manager.c代码分析上篇

本篇主要分析tcp_session_manager.h和部分tcp_session_manager.c代码

一、背景知识

传送门(点击查看对应理论知识)

二、代码分析

1.头文件tcp_session_manager.h

#ifndef TCP_SESSION_MANAGER_H
#define TCP_SESSION_MANAGER_H
//条件编译避免重复编译
#include "comm_defs.h"

int CreateTcpSessionMgr(bool asServer, const char* localIp);
int RemoveTcpSessionMgr(void);
//声明函数
#endif  // TCP_SESSION_MANAGER_H

2.头文件comm_defs.h

#ifndef COMM_DEFS_H
#define COMM_DEFS_H

#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "securec.h"
#include <unistd.h>

#define COMM_UNUSED __attribute__((unused))
//表示可能没有使用,告诉编译器在编译此类型函数或变量时不需报警告。
#define COMM_EXPORT __attribute__((visibility("default")))
//用来避免编译时的外部链接混乱,忽视警告

#endif // COMM_DEFS_H

3.源文件tcp_session_manager.c

1.头文件引用和宏定义

#include "tcp_session_manager.h"

#include <arpa/inet.h>
#if defined(__LITEOS_M__) || defined(__LITEOS_RISCV__)
#include <cmsis_os.h>
#else
#include <pthread.h>
#include "pms_interface.h"
#include "pms_types.h"
#endif
#include <malloc.h>
#include <mbedtls/base64.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>

#include "aes_gcm.h"
#include "auth_conn.h"
#include "auth_interface.h"
#include "bus_manager.h"
#include "cJSON.h"
#include "message.h"
#include "os_adapter.h"
#include "session.h"
#include "tcp_session.h"
#include "tcp_socket.h"
#include "trans_lock.h"
#include "wifi_auth_manager.h"

#define MAX_SESSION_NUM 3 //会话最大值
#define MAX_SESSION_SERVER_NUM 8  //会话服务器的最大数量
#define MAX_SESSION_SUM_NUM (MAX_SESSION_NUM * MAX_SESSION_SERVER_NUM)

#define MODULE_SESSION 6
#define AUTH_PACKET_HEAD_SIZE 24
#define TRANS_PACKET_HEAD_SIZE 16
#define TRANS_SEQ_NUM_OFFSET 8
#define RECIVED_BUFF_SIZE (4 * 1024)
#define LISTEN_BACKLOG 4
#define DEFAULT_SEQNUM 100
#define DEFAULT_TV_SEC 10
#define DEFAULT_TRANS_PORT 0
#define DEFAULT_API_VERSION 2
#define DEFAULT_LONG_LEN 8

#define SESSION_KEY_INDEX_SIZE 4
#define TRANS_FAILED    (-1)

#define DEFAULT_TIMEOUT 200
#define ONE_SEC 1000

#define SIZE_OF_INT         sizeof(int)
#define SIZE_OF_LONG_LONG   sizeof(long long)

#define SEND_BUFF_MAX_SIZE  (RECIVED_BUFF_SIZE - SESSION_KEY_INDEX_SIZE - TRANS_PACKET_HEAD_SIZE - OVERHEAD_LEN)

#define SOFTBUS_PERMISSION_NAME  "ohos.permission.DISTRIBUTED_DATASYNC"

2. 结构体的定义

typedef struct {
    char moduleName[NAME_LENGTH];//模块名
    char sessionName[NAME_LENGTH];//会话名
    struct ISessionListener *listener;//绘画监听
} SessionListenerMap;
//绘画监听结构体

typedef struct {
    bool asServer;
    int listenFd; //监听描述符(套接字)
    bool isSelectLoopRunning;
    struct ISessionListener *callback_; //回调变量
    TcpSession* sessionMap_[MAX_SESSION_SUM_NUM];//会话数组
    SessionListenerMap* serverListenerMap[MAX_SESSION_SERVER_NUM];//服务器监听数组
} TcpSessionMgr;
//定义tcp会话管理

3.函数定义
下面两个函数通过sessionid来获取session,以及通过名字来获取会话的监听listener

TcpSessionMgr* g_sessionMgr;

static TcpSession *GetSessionById(int sessionId)//获取会话
{
    if (g_sessionMgr == NULL) {
        return NULL;
    }
    for (int i = 0; i < MAX_SESSION_SUM_NUM; i++) {
        if ((g_sessionMgr->sessionMap_[i] != NULL) && (g_sessionMgr->sessionMap_[i]->fd == sessionId)) {
            //g_sessionMgr->sessionMap_[i]不为空并且该元素的套接字描述符不为空,就返回g_sessionMgr->sessionMap_[i]
            return g_sessionMgr->sessionMap_[i];
        }
    }
    return NULL;
}//该函数通过会话id来获取会话

static SessionListenerMap *GetSessionListenerByName(const char *sessionName, int nameSize)
//该函数通过名字来获取会话的监听
{
    if (nameSize <= 0 || nameSize >= NAME_LENGTH) {
        SOFTBUS_PRINT("[TRANS] GetSessionListenerByName invalid para\n");
        return NULL;
        //检查传入参数问题
    }
    if (g_sessionMgr == NULL) {
        return NULL;
    }//检查g_sessionMgr是否空值

    SessionListenerMap* sessionListener = NULL;
    for (int i = 0; i < MAX_SESSION_SERVER_NUM; i++) {
        if (g_sessionMgr->serverListenerMap[i] != NULL &&
            strcmp(g_sessionMgr->serverListenerMap[i]->sessionName, sessionName) == 0) {
            sessionListener = g_sessionMgr->serverListenerMap[i];
            //g_sessionMgr->serverListenerMap[i]不为空并且该结构体中sessionName和传入参数相同的话,
            //就获取对应的会话监听结构体
            break;
        }
    }

    return sessionListener;
}

初始化所选择的列表,将会话结构体数组中fd不断更新到所传入的两个套接字集合当中

static int InitSelectList(const TcpSessionMgr *tsm, fd_set *rfds, fd_set *exceptfds)
//参数为一个tcp会话管理,两套套接字描述符
{
    if (tsm == NULL || tsm->listenFd == -1 || rfds == NULL) {
        return TRANS_FAILED;
        //检查函数传入参数
    }

    int maxFd = tsm->listenFd;
    FD_ZERO(rfds);
    FD_ZERO(exceptfds);
    //清空,初始化两个套接字集合
    FD_SET(tsm->listenFd, rfds);//用于在文件描述符集合中增加一个新的文件描述符
    if (GetTcpMgrLock() != 0) {
        return TRANS_FAILED;
        //创建/获取一个互斥锁
    }
    //对数据进行访问等操作时,申请互斥锁。操作完后释放互斥锁
    for (int i = 0; i < MAX_SESSION_SUM_NUM; i++) {
        if ((tsm->sessionMap_[i]) == NULL) {
            continue;
        }

        int fd = tsm->sessionMap_[i]->fd;
        if (fd >= 0) {
            FD_SET(fd, rfds);
            FD_SET(fd, exceptfds);
            maxFd = (maxFd > fd) ? maxFd : fd;//用来更新最大fd
        }
    }//遍历(tsm->sessionMap结构体中所有元素,将各个符合条件的套接字添加进rfds和exceptfds
    if (ReleaseTcpMgrLock() != 0) {
        return TRANS_FAILED;
        //释放互斥锁
    }
    return maxFd;
}

初始化会话管理,申请空间并将所有的会话数组遍历置空

static int InitGSessionMgr(void)
{
    if (g_sessionMgr != NULL) {
        return 0;
    }

    g_sessionMgr = malloc(sizeof(TcpSessionMgr));//申请空间
    if (g_sessionMgr == NULL) {
        return TRANS_FAILED;
    }

    (void)memset_s(g_sessionMgr, sizeof(TcpSessionMgr), 0, sizeof(TcpSessionMgr));
    //将(g_sessionMgr相关指定空间内的元素置为0

    g_sessionMgr->listenFd = -1;
    g_sessionMgr->isSelectLoopRunning = false;

    for (int i = 0; i < MAX_SESSION_SUM_NUM; i++) {
        g_sessionMgr->sessionMap_[i] = NULL;
    }
    //将所有会话置为空
    for (int i = 0; i < MAX_SESSION_SERVER_NUM; i++) {
        g_sessionMgr->serverListenerMap[i] = NULL;
    }
    //将所有服务器的监听元素也置为空
    return 0;
}

RemoveSession函数用来删除指定会话,释放该会话相关的所有空间,实现删除的目的

static bool RemoveSession(TcpSessionMgr *tsm, int sessionId)//删除会话
{
    if (tsm == NULL || sessionId < 0) {
        SOFTBUS_PRINT("[TRANS] RemoveSession invalid para\n");
        return false;
        //检查函数传入参数
    }

    SessionSeqNumNode* node = NULL;
    List* pos = NULL;
    List* tmp = NULL;
    for (int i = 0; i < MAX_SESSION_SUM_NUM; i++) {
        if (tsm->sessionMap_[i] != NULL && tsm->sessionMap_[i]->fd == sessionId) {
            LIST_FOR_EACH_SAFE(pos, tmp, tsm->sessionMap_[i]->seqNumList) {
                node = (SessionSeqNumNode*)pos;
               //遍历整个链表
                if (node == NULL) {
                    continue;
                }
                free(node);
                //释放node空间
            }
            free(tsm->sessionMap_[i]->seqNumList);
            free(tsm->sessionMap_[i]);
            //-释放申请的空间
            tsm->sessionMap_[i] = NULL;
            return true;
        }
    }
    //该函数通过释放空间来达到删除会话的作用
    return false;
}

CloseTransSession函数用来关闭数据传输session会话

static void CloseTransSession(int sessionId)//关闭trans传输会话
{
    CloseFd(sessionId);//根据sessionid来关闭会话
    TcpSession *session = GetSessionById(sessionId);//通过id来获取会话
    if (session == NULL) {
        SOFTBUS_PRINT("[TRANS] CloseTransSession GetSessionById fail\n");
        return;
        //检查会话是否为空
    }
    SessionListenerMap *serverListener = GetSessionListenerByName(session->sessionName, strlen(session->sessionName));
    //通过session名字来获取服务器监听
    if (serverListener == NULL) {
        return;
    }
    serverListener->listener->onSessionClosed(sessionId);
    RemoveSession(g_sessionMgr, sessionId);
    //通过对应的sessionid和g_sessionMgr来关闭session
}

RemoveExceptSessionFd每一个在exceptfds当中的元素对应的session全部关闭,并在exceptfds套接字集合当中删除session对应的fd

static int RemoveExceptSessionFd(const TcpSessionMgr *tsm, fd_set *exceptfds)//去除套接字
{
    if (GetTcpMgrLock() != 0) {
        return TRANS_FAILED;
        //申请互斥锁
    }

    if (g_sessionMgr == NULL || g_sessionMgr->listenFd == -1 || exceptfds == NULL) {
        ReleaseTcpMgrLock();
        return TRANS_FAILED;
        //检查参数,如果检查符合要求就释放互斥锁
    }

    if (g_sessionMgr->listenFd >= 0 && FD_ISSET(g_sessionMgr->listenFd, exceptfds)) {
        ReleaseTcpMgrLock();
        return TRANS_FAILED;
        //
    }

    int result = TRANS_FAILED;
    for (int i = 0; i < MAX_SESSION_SUM_NUM; i++) {
        if ((tsm->sessionMap_[i]) == NULL) {
            continue;
        }

        int fd = tsm->sessionMap_[i]->fd;
        if (fd >= 0) {
            if (FD_ISSET(fd, exceptfds)) {//来检查fd是否在exceptfds集合当中
                result = 0;
                SOFTBUS_PRINT("Session is closed. %d\r\n", fd);
                CloseTransSession(fd);
            }
        }
        //将每一个在exceptfds当中的元素对应的session全部关闭
    }

    if (ReleaseTcpMgrLock() != 0) {
        return TRANS_FAILED;
        //检查是否释放互斥锁
    }

    return result;
}

AddSession传入会话管理变量和session,将session添加进会话管理变量。

static bool AddSession(TcpSessionMgr *tsm, TcpSession *session)//添加会话
{
    if (tsm == NULL || session == NULL) {
        SOFTBUS_PRINT("[TRANS] AddSession invalid para\n");
        return false;
        //检查擦传入参数是否为空
    }

    for (int i = 0; i < MAX_SESSION_SUM_NUM; i++) {
        if (tsm->sessionMap_[i] == NULL) {
            //检查数组中的空位置,并存进会话
            tsm->sessionMap_[i] = session;
            return true;
        }
    }

    return false;
}

ProcessConnection通过给定的tcp会话管理,accept函数实现和客户端的连接,并且通过GetOnLineAuthConnByIp来获取用户线上连接信息,将所连接设备的id存入session,并添加进会话管理变量当中,以此来实现进程连接。

//进程链接函数
static void ProcessConnection(TcpSessionMgr *tsm)
{
    struct sockaddr_in addr = { 0 };
    socklen_t addrLen = sizeof(addr);

    int cfd = accept(tsm->listenFd, (struct sockaddr *)&addr, &addrLen);
    //accept函数指定服务端去接受客户端的连接,接收后,返回了客户端套接字的标识,且获得了客户端套接字的“地方”
    if (cfd < 0) {
        SOFTBUS_PRINT("[TRANS] ProcessConnection accept fail\n");
        //cfd小于零说明函数返回失败,accept失败
        return;
    }
    TcpSession *session = CreateTcpSession();
    if (session == NULL) {
        SOFTBUS_PRINT("[TRANS] ProcessConnection CreateTcpSession fail, fd = %d\n", cfd);
        CloseSession(cfd);
        //创建的tcpsession为空的话。关闭cfd对应的会话
        return;
    }

    AuthConn* authConn = GetOnLineAuthConnByIp(inet_ntoa(addr.sin_addr));
    if (authConn != NULL && strncpy_s(session->deviceId, MAX_DEV_ID_LEN, authConn->deviceId,
        strlen(authConn->deviceId)) != 0) {
        //用来将用户连接的设备id复制到会话的设备id
        SOFTBUS_PRINT("[TRANS] Error on copy deviceId of session.");
        free(session);
        CloseSession(cfd);
        //释放空间,关闭会话
        return;
    }
    session->fd = cfd;
    int result = AddSession(tsm, session);
    //将session添加进tsm会话
    if (result == false) {
        SOFTBUS_PRINT("[TRANS] AddSession fail\n");
        free(session);
        CloseSession(cfd);
        return;
    }//检查是否添加成功
    return;
}

下面的代码用来打包数据并且获取信息、并对相关信息进行处理。其中GetReplyMsg用来获取回复,GetIntFromBuf和GetKeyIndex都用来初始化通过复制信息来实现个数组赋值。

static unsigned char* PackBytes(const char *str, int *bufLen)//打包数据
{
    return AuthConnPackBytes(MODULE_SESSION, 1, DEFAULT_SEQNUM, str, bufLen);
    //将数据封装打包的函数。确定数据不为空,确定是否为密文,确定总长度,将信息打包安全拷贝到data中,如果是密文将密钥同样打包入数据中,最后返回data指针指向的数据buf
}

static void GetReplyMsg(cJSON *jsonObj, const TcpSession *session)//用来获取回复消息
{
    cJSON_AddNumberToObject(jsonObj, "CODE", 1);
    cJSON_AddNumberToObject(jsonObj, "API_VERSION", DEFAULT_API_VERSION);
    //cjson中语法,添加数字
    DeviceInfo *local = BusGetLocalDeviceInfo();
    //获取设备信息检查设备是否有效
    if (local == NULL) {
        return;
    }
    char* deviceId = local->deviceId;
    cJSON_AddStringToObject(jsonObj, "DEVICE_ID", deviceId);
    cJSON_AddNumberToObject(jsonObj, "UID", -1);
    cJSON_AddNumberToObject(jsonObj, "PID", -1);
    cJSON_AddStringToObject(jsonObj, "PKG_NAME", session->sessionName);
    cJSON_AddStringToObject(jsonObj, "CLIENT_BUS_NAME", session->sessionName);
    cJSON_AddStringToObject(jsonObj, "AUTH_STATE", "");
    cJSON_AddNumberToObject(jsonObj, "CHANNEL_TYPE", 1);
    //对有效设备相关信息进行更新
}

static int GetIntFromBuf(const char *buf, int offset)//用来将buf中内容以offset的偏置进行复制信息
{
    int val = 0;
    if (memcpy_s(&val, SIZE_OF_INT, buf + offset, SIZE_OF_INT) != 0) {
        //memcpy将源内存地址以指定位置开始,指定长度开始复制到另一个数组中
        return TRANS_FAILED;
    }
    return val;
    //返回新复制信息的数组
}

static int GetKeyIndex(const char *in, unsigned int inOffset, unsigned int indexLen)//获取索引key值的函数
{
    int val = 0;
    if (memcpy_s(&val, indexLen, in + inOffset, indexLen) != EOK) {
        //复制信息
        return -1;
    }
    return val;
}
//关闭所有会话
static void CloseAllSession(const TcpSessionMgr *tsm)
{
    if (GetTcpMgrLock() != 0) {
        return;
        //申请一个互斥锁
    }
    for (int i = 0; i < MAX_SESSION_SUM_NUM; i++) {
        //遍历数组中所有会话,检查是否为空,不为空则关闭会话
        if ((tsm->sessionMap_[i]) == NULL) {
            continue;

        }

        CloseTransSession(tsm->sessionMap_[i]->fd);
        //关闭数据传输会话
    }

    if (ReleaseTcpMgrLock() != 0) {
        return;
    }
    //执行完所有操作释放互斥锁
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HarmonyOS是华为公司自主研发的操作系统,其内核是实现系统各项功能的核心部分。对于HarmonyOS内核源码分析,可以从以下几个方面进行讨论。 首先,HarmonyOS内核源码分析可以关注其整体架构。HarmonyOS内核采用微内核架构,将各个功能模块拆分成独立的服务,通过消息传递进行通信,实现了更高的灵活性和可靠性。通过分析内核的整体架构,可以深入了解到HarmonyOS是如何进行进程管理、内存管理、文件系统等各个方面的功能实现。 其次,可以重点关注HarmonyOS内核的调度机制。调度机制是操作系统内核决定进程、线程执行顺序和时间分配的重要部分。HarmonyOS内核采用了全局时钟中断驱动的抢占式调度机制,能够确保不同任务的公平和高效执行。通过对调度机制的分析可以了解到HarmonyOS内核是如何进行多任务切换、时间片轮转以及任务优先级管理的。 此外,HarmonyOS内核源码分析还可以关注线程同步和通信机制。线程同步和通信是多线程协作的基础,也是操作系统内核重要的功能之一。HarmonyOS内核通过互斥锁、条件变量和信号量等机制实现了线程之间的同步和通信。了解这些机制可以更好地理解HarmonyOS是如何处理多线程并发访问共享资源和协调线程之间的执行顺序的。 最后,分析HarmonyOS内核源码还可以关注其安全性。安全性是一个操作系统内核不能忽视的重要问题。HarmonyOS内核采用了多种安全机制,如安全IPC、安全网卡等,确保系统资源和用户数据的安全。通过分析内核源码中的安全措施可以了解到HarmonyOS是如何保障系统的安全性并防止恶意攻击。 综上所述,对于HarmonyOS内核源码分析需要关注整体架构、调度机制、线程同步和通信机制以及安全性等方面。通过深入分析内核源码,可以更好地了解操作系统的具体实现细节和原理,为开发者提供更好的参考和指导。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值