tcp_session_manager.c代码分析下篇
本篇主要分析tcp_session_manager.c中出现的函数
一、相关链接和本篇代码相关的一些背景知识和该文件的上一部分代码详解:
- tcp_socket机制详解
- 互斥锁和消息队列详解
- tcp_session详解
- tcp_session_manager.c代码分析上篇
- tcp_session_manager.c代码分析中篇
SelectSessionLoop函数用来处理会话线程数据
static void SelectSessionLoop(TcpSessionMgr *tsm)
{
if (tsm == NULL) {
return;
}
SOFTBUS_PRINT("[TRANS] SelectSessionLoop begin\n");
tsm->isSelectLoopRunning = true;
while (true) {
fd_set readfds;
fd_set exceptfds;
int maxFd = InitSelectList(tsm, &readfds, &exceptfds);
//将tsm中非空元素的套接字写进readfds集合和exceptfds集合
if (maxFd = NAME_LENGTH) {
SOFTBUS_PRINT("[TRANS] CreateSessionServerInner name length is too big\n");
return TRANS_FAILED;
//检查会话名和模块名字的标准是否合格
}
int findIndex = -1;
for (int i = 0; i serverListenerMap[i] == NULL) {
findIndex = i;
break;
//遍历所有会话服务器,找出空值对应下标
}
}
if (findIndex == -1) {
return TRANS_FAILED;
}
if (findIndex >= 0 && findIndex serverListenerMap[findIndex] = calloc(1, sizeof(SessionListenerMap));
if (g_sessionMgr->serverListenerMap[findIndex] == NULL) {
return TRANS_FAILED;
//对上次找出空值,将空值对应位置申请空间内存
}
SessionListenerMap *listenerMap = g_sessionMgr->serverListenerMap[findIndex];
if (strncpy_s(listenerMap->sessionName, NAME_LENGTH, sessionName, strlen(sessionName)) ||
strncpy_s(listenerMap->moduleName, NAME_LENGTH, moduleName, strlen(moduleName))) {
//将会话名二号模块名字复制到指定位置
free(listenerMap);
listenerMap = NULL;
return TRANS_FAILED;
}
listenerMap->listener = listener;//监听变量赋值
}
return 0;
}
RemoveSessionServerInner通过模块名和会话名实现服务器的删除
static int RemoveSessionServerInner(const char* moduleName, const char *sessionName)//删除内部服务器
{
if (g_sessionMgr == NULL) {
return TRANS_FAILED;
}//检查参数
int removeFd = -1;
for (int i = 0; i sessionMap_[i] != NULL &&
strcmp(g_sessionMgr->sessionMap_[i]->sessionName, sessionName) == 0) {
removeFd = g_sessionMgr->sessionMap_[i]->fd;
//检查非空值释放会话空间并且关闭数据传输会话
CloseTransSession(removeFd);
free(g_sessionMgr->sessionMap_[i]);
g_sessionMgr->sessionMap_[i] = NULL;
}
}
for (int i = 0; i serverListenerMap[i];
if (serverListener != NULL && (strcmp(serverListener->sessionName, sessionName) == 0) &&
//检查服务器监听是否开启,以及监听会话名和传入的会话名是否相同,监听的模块名和传入的模块名是否相同
(strcmp(serverListener->moduleName, moduleName) == 0)) {
if (serverListener->listener != NULL && serverListener->listener->onSessionClosed != NULL) {
serverListener->listener->onSessionClosed(removeFd);//关闭会话
}
free(serverListener);//关闭服务器的监听
serverListener = NULL;
break;
}
}
return 0;
}
该条件编译中第一部分函数已在前面出现过,主要用来处理线程数据
#if defined(__LITEOS_M__) || defined(__LITEOS_RISCV__)
int StartSelectLoop(TcpSessionMgr *tsm)
{
if (tsm == NULL) {
return TRANS_FAILED;
}
if (tsm->isSelectLoopRunning) {
return 0;
}
osThreadId_t sessionLoopTaskId;
osThreadAttr_t attr;
attr.name = "trans_session_task";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = (LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE * 2);
attr.priority = osPriorityNormal5; // LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO -> cmsis prio
sessionLoopTaskId = osThreadNew((osThreadFunc_t)SelectSessionLoop, (void *)tsm, &attr);
if (NULL == sessionLoopTaskId) {
SOFTBUS_PRINT("[TRANS] StartSelectLoop TaskCreate fail\n");
return TRANS_FAILED;
}
return 0;
}
该代码块主要用来创建线程,实现线程中数据处理
#else
#define MIN_STACK_SIZE 0x8000
static pthread_key_t g_localKey = 0;
typedef void *(*Runnable)(void *argv);
typedef struct ThreadAttr ThreadAttr;
struct ThreadAttr {
const char *name; // 线程
uint32_t stackSize; // 堆栈大小
uint8_t priority; // 优先级
uint8_t reserved1; // reserved1 (must be 0)//可以看作是端口
uint16_t reserved2; // reserved2 (must be 0)
};
typedef void *ThreadId;
ThreadId TcpCreate(Runnable run, void *argv, const ThreadAttr *attr)//用来创建一个tcp相关的线程
{
if (attr == NULL) {
return NULL;
}
int ret;
pthread_attr_t threadAttr;
ret = pthread_attr_init(&threadAttr);//对线程进行初始化
if (ret != 0) {//初始化是否成功
SOFTBUS_PRINT("[TRANS] TcpCreate pthread attr init fail\n");
}
ret = pthread_attr_setstacksize(&threadAttr, (attr->stackSize | MIN_STACK_SIZE));
//指定线程堆栈区的大小
if (ret != 0) {
SOFTBUS_PRINT("[TRANS] TcpCreate pthread attr setstacksize fail\n");//分配大小是否成功
}
struct sched_param sched = {attr->priority};
ret = pthread_attr_setschedparam(&threadAttr, &sched);//用于设置线程的调用策略和优先级,第一个参数为线程ID,第二个参数优先级
if (ret != 0) {
SOFTBUS_PRINT("[TRANS] TcpCreate pthread attr setschedparam fail\n");
//检查是否优先级设置失败
}
ret = pthread_key_create(&g_localKey, NULL);//对线程池中找到数据分配至g_localKey,第二个参数为清理函数。NULL表示选择默认的数据清理函数
if (ret != 0) {
SOFTBUS_PRINT("[TRANS] TcpCreate pthread key create fail\n");
}
pthread_t threadId = 0;
ret = pthread_create(&threadId, &threadAttr, run, argv);//创建一个线程
/*第一个参数为指向线程 标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。
最后一个参数是运行函数的参数。*/
if (ret != 0) {
return NULL;
}
return (ThreadId)threadId;//最后返回线程的ID
}
int StartSelectLoop(TcpSessionMgr *tsm)//线程处理所有的会话数据接收
{
if (tsm == NULL) {
return TRANS_FAILED;
//检查参数
}
if (tsm->isSelectLoopRunning) {
return 0;
//检查tsm的SelectLoop状态是否运行
}
ThreadAttr attr = {"tcp", 0x800, 20, 0, 0};
register ThreadId threadId = (ThreadId)TcpCreate((Runnable)SelectSessionLoop, tsm, &attr);
//创建并定义了一个寄存器线程变量
if (threadId == NULL) {
return TRANS_FAILED;
}
tsm->isSelectLoopRunning = true;//线程处理中
}
#endif
CreateTcpSessionMgr函数和RemoveTcpSessionMgr实现TcpSessionMgr的创建和删除,参数为服务器和本地ip
int CreateTcpSessionMgr(bool asServer, const char* localIp)//传入一个服务器和本地ip来创建一个tcp会话管理器
{
if (localIp == NULL) {//检查传入的ip参数是否为空
return TRANS_FAILED;
}
if (InitTcpMgrLock() != 0 || GetTcpMgrLock() != 0) {
return TRANS_FAILED;
//初始化mutex相关锁和互斥体。申请互斥锁
}
int ret = InitGSessionMgr();
if (ReleaseTcpMgrLock() != 0 || ret != 0) {
FreeSessionMgr();
//初始化GSessionMgr失败iu释放互斥锁,函数退出
return TRANS_FAILED;
}
g_sessionMgr->asServer = asServer;
int listenFd = OpenTcpServer(localIp, DEFAULT_TRANS_PORT);//根据端口和ip打开服务器,并将套接字写进listenfd
if (listenFd listenFd = listenFd;//将服务器的套接字写进g_sessionMgr->listenFd
signal(SIGPIPE, SIG_IGN);//使用函数来处理信号SIGPIPE,SIG_IGN为忽视信号函数
if (StartSelectLoop(g_sessionMgr) != 0) {//使用线程处理g_sessionMgr中数据
SOFTBUS_PRINT("[TRANS] CreateTcpSessionMgr StartSelectLoop fail\n");
CloseSession(listenFd);
FreeSessionMgr();
return TRANS_FAILED;
}
return GetSockPort(listenFd);
//返回listenFd对应套接字的socket端口
}
int RemoveTcpSessionMgr(void)//删除TcpSessionMgr
{
if (g_sessionMgr == NULL) {
return TRANS_FAILED;//检查g_sessionMgr
}
CloseAllSession(g_sessionMgr);
//关闭g_sessionMgr相关所有session
if (GetTcpMgrLock() != 0) {//申请互斥锁
return TRANS_FAILED;
}
CloseFd(g_sessionMgr->listenFd);//关闭g_sessionMgr->listenFd对应文件设备
g_sessionMgr->listenFd = -1;//将listenfd改为-1,相当于没有所连接的listenfd
if (ReleaseTcpMgrLock() != 0) {
return TRANS_FAILED;
//释放互斥锁。
}
return 0;
}
CreateSessionServer函数和RemoveSessionServer为创建和删除会话服务器的函数 通过会话名,模块名,监听名
int CreateSessionServer(const char* moduleName, const char* sessionName, struct ISessionListener *listener)//创建会话服务器
{
if (moduleName == NULL || sessionName == NULL || listener == NULL) {
return TRANS_FAILED;//检查参数
}
if (SoftBusCheckPermission(SOFTBUS_PERMISSION_NAME) != 0) {
return TRANS_FAILED;//检查权限
}
if (GetTcpMgrLock() != 0) {
return TRANS_FAILED;//申请互斥锁,一边操作数据文件设备
}
int ret = CreateSessionServerInner(moduleName, sessionName, listener);//根据moduleName, sessionName, listener创建一个内部的会话服务器
if (ReleaseTcpMgrLock() != 0) {
return TRANS_FAILED;
//释放互斥锁
}
return ret;
}
int RemoveSessionServer(const char* moduleName, const char *sessionName)//删除会话服务器
{
if (moduleName == NULL || sessionName == NULL) {
SOFTBUS_PRINT("[TRANS] moduleName == NULL || sessionName == NULL\n");
return TRANS_FAILED;//检查参数
}
if (SoftBusCheckPermission(SOFTBUS_PERMISSION_NAME) != 0) {
return TRANS_FAILED;//检查用户的权限
}
if (GetTcpMgrLock() != 0) {
return TRANS_FAILED;//申请加互斥锁
}
int ret = RemoveSessionServerInner(moduleName, sessionName);//删除内部的会话服务器
if (ReleaseTcpMgrLock() != 0) {
return TRANS_FAILED;//释放锁
}
return ret;
}
SendBytes和TransPackBytes两个函数实现数据传输并加密。将session会话中sendData中数据发送带连接另一端的socket,大小为sendDataLen。传输依赖于ace_gcm.c文件中EncryptTransData函数,实现数据的传输和加密。
static unsigned char *TransPackBytes(TcpSession *session, const unsigned char *sendData, unsigned int sendDataLen,
int *bufLen)
{
if (session == NULL || sendData == NULL || bufLen == NULL || sendDataLen > SEND_BUFF_MAX_SIZE || sendDataLen == 0) {
return NULL;//检查传入参数
}
int allLen = sendDataLen + TRANS_PACKET_HEAD_SIZE + OVERHEAD_LEN;
if (allLen > RECIVED_BUFF_SIZE || allLen seqNum++;
unsigned char *buf = (unsigned char *)malloc(allLen);//申请一个buf数组
if (buf == NULL) {
return NULL;
}
memset_s(buf, allLen, 0, allLen);//初始化buf数组
unsigned int magicnum = PKG_HEADER_IDENTIFIER;
AesGcmCipherKey cipherKey = {0};
unsigned char* randomIv = GenerateRandomIv();
if (randomIv == NULL) {
free(buf);
return NULL;
}
int offset = 0;
int ret = memcpy_s(buf + offset, allLen - offset, &magicnum, SIZE_OF_INT);
offset += SIZE_OF_INT;
ret += memcpy_s(buf + offset, allLen - offset, &seqNum, SIZE_OF_INT);
offset += SIZE_OF_INT;
ret += memcpy_s(buf + offset, allLen - offset, &flags, SIZE_OF_INT);
offset += SIZE_OF_INT;
int dataLen = sendDataLen + OVERHEAD_LEN;
ret += memcpy_s(buf + offset, allLen - offset, &dataLen, SIZE_OF_INT);
offset += SIZE_OF_INT;
//不断将magicnum,seqNum,flags,dataLen中内容复制到指定数组buf的指定位置
cipherKey.keybits = GCM_KEY_BITS_LEN_256;
ret += memcpy_s(cipherKey.key, SESSION_KEY_LENGTH, session->sessionKey, SESSION_KEY_LENGTH);
ret += memcpy_s(cipherKey.iv, IV_LEN, randomIv, IV_LEN);
//将session->sessionKey写进cipherKey.key,将随机向量randomIv写进cipherKey.iv,同时释放randomIv
free(randomIv);
ret += memcpy_s(cipherKey.iv, SIZE_OF_INT, &seqNum, SIZE_OF_INT);
if (ret != 0) {
free(buf);
return NULL;
}
int cipherLen = EncryptTransData(&cipherKey, sendData, sendDataLen, buf + offset, sendDataLen + OVERHEAD_LEN);//对数据发送并进行加密,写进buf
if (cipherLen len) {
SOFTBUS_PRINT("[TRANS] len is too small.\n");
return TRANS_FAILED;
//检查len和id长度
}
if (strncpy_s(devId, len, id, strlen(id)) != 0) {
SOFTBUS_PRINT("[TRANS] devId copy failed.\n");
return TRANS_FAILED;
//将id中内容复制到devid中指定位置
}
return 0;
}
CloseSession函数实现会话的关闭
void CloseSession(int sessionId)//关闭会话
{
if (SoftBusCheckPermission(SOFTBUS_PERMISSION_NAME) != 0) {
return;
//检查权限后退出
}
if (GetTcpMgrLock() != 0) {
return;
//获取tcp管理互斥锁后退出
}
CloseTransSession(sessionId);
if (ReleaseTcpMgrLock() != 0) {
return;
//释放tcp互斥锁后退出
}
return;
}