OpenHarmony源码:分布式软总线trans_service模块(1)/认证通道管理
一、 概述
trans_service模块基于系统内核提供的socket通信,向authmanager模块提供设备认证通道管理和设备认证数据的传输;向业务模块提供session管理和基于session的数据收发功能,并且通过GCM模块的加密功能提供收发报文的加解密保护。
二、 源码分析
- 入口函数为StartListener(),主要是针对Linux系统内核,其它系统之后会有补充,解析如下
/*
函数功能: 启动监听其他设备的连接请求或者新数据响应
函数参数:callback 回调函数的地址;ip 需要绑定的server端ip地址
函数返回值:返回建立TCP连接的套接字的port
详细:监听器的主要作用是监听新连接请求和已建立连接的数据通信。
1.首先作为server端产生监听套接字fd,然后绑定端口和IP,这里的端口绑定采用了动态分配的方式。
2.然后创建子线程执行监听任务,采用的是select的io复用方式来处理并发请求。
*/
int StartListener(BaseListener *callback, const char *ip)
{
if (callback == NULL || ip == NULL) {
return -DBE_BAD_PARAM;
}
g_callback = callback;
//产生并初始化监听描述符,传入的SESSIONPORT为0,绑定0端口号的意义在于动态选取本地可用端口号,不用考虑端口重用的问题
int rc = InitListenFd(ip, SESSIONPORT);
if (rc != DBE_SUCCESS) {
return -DBE_BAD_PARAM;
}
//捕获SIGPIPE信号,SIG_IGN表示忽视该信号,不执行SIGPIPE默认操作:终止程序
signal(SIGPIPE, SIG_IGN);
//初始化线程属性,"auth"为线程名,线程栈大小为0x800 | MIN_STACK_SIZE,单位为字节,线程优先级为20
ThreadAttr attr = {"auth", 0x800, 20, 0, 0};
//创建子线程进行监听任务,包括设备认证过程中的新连接或者新数据
register ThreadId threadId = (ThreadId)AuthCreate((Runnable)WaitProcess, &attr);
if (threadId == NULL) {//创建子线程失败,则返回-1
SOFTBUS_PRINT("[TRANS] StartListener AuthCreate fail\n");
return -1;
}
//返回建立TCP连接的套接字的port,因为这里绑定的端口是0,其实是内核随机分配的端口号
return GetSockPort(g_listenFd);
}
- 调用 InitListenFd() 函数产生并初始化监听套接字fd
/*
函数功能: 产生并初始化监听描述符
函数参数:ip server端IP地址;port server端端口
函数返回值:成功返回0,失败返回错误码
详细:
*/
static int InitListenFd(const char *ip, int port)//
{
if (ip == NULL || g_listenFd != -1) {
return -DBE_BAD_PARAM;
}
if (strncmp(ip, "0.0.0.0", strlen(ip)) == 0) {//如果输入ip为0.0.0.0,则返回错误码
return -DBE_BAD_PARAM;
}
int rc = OpenTcpServer(ip, port);//初始化server端套接字,生成监听fd
if (rc < 0) {
SOFTBUS_PRINT("[TRANS] InitListenFd OpenTcpServer fail\n");
return rc;
}
g_listenFd = rc;
//更新最大描述符值,因为后续需要为select函数提供最大描述符值,select函数需要获得监听集合中所有文件描述符的范围
RefreshMaxFd(g_listenFd);
//将该fd从CLOSED转换到LISTEN状态,监听client端(主动端)发起的连接信息
rc = listen(rc, DEFAULT_BACKLOG);
if (rc != 0) {
SOFTBUS_PRINT("[TRANS] InitListenFd listen fail\n");
StopListener();
return -DBE_LISTEN_FAIL;
}
return DBE_SUCCESS;
}
- OpenTcpServer() 函数
/*
函数功能: 初始化server端套接字,绑定ip地址及port
函数参数:ip 需要进行绑定的ip地址;port 需要进行绑定的port
函数返回值:成功返回生成的套接字描述符,失败返回错误码
详细:
*/
int OpenTcpServer(const char *ip, uint16_t port)
{
if (ip == NULL) {
return -DBE_BAD_PARAM;
}
struct sockaddr_in addr = {0};
errno = 0;
//将点分十进制的ip字符串转化为网络字节序的32位ip地址
int rc = inet_pton(AF_INET, ip, &addr.sin_addr);
if (rc <= 0) {
return -DBE_BAD_IP;
}
addr.sin_family = AF_INET;//ipv4
addr.sin_port = htons(port);//网络字节序的port
errno = 0;
int fd = socket(AF_INET, SOCK_STREAM, 0);//生成基于TCP协议的套接字描述符
if (fd < 0) {
return -DBE_OPEN_SOCKET;
}
SetServerOption(fd);//设置套接字选项,地址可重用和禁用Nagle算法
errno = 0;
rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));//绑定server端IP地址和port
if (rc < 0) {
ShutDown(fd);
return -DBE_BIND_SOCKET;
}
return fd;
}
- 创建线程用于设备身份认证:AuthCreate() 函数
/*
函数功能: 初始化用于身份验证的线程相关属性并创建线程
函数参数:run 子线程回调函数;attr 线程属性结构体地址
函数返回值:线程id
详细:
*/
ThreadId AuthCreate(Runnable run, const ThreadAttr *attr)
{
pthread_attr_t threadAttr;
pthread_attr_init(&threadAttr);//初始化一个线程属性对象threadAttr
pthread_attr_setstacksize(&threadAttr, (attr->stackSize | MIN_STACK_SIZE));//设置线程的栈大小
struct sched_param sched = {attr->priority};
pthread_attr_setschedparam(&threadAttr, &sched);//设置线程调度优先级
pthread_key_create(&g_localKey, NULL);//创建线程私有的全局数据(TSD),同名而地址不同
pthread_t threadId = 0;
int errCode = pthread_create(&threadId, &threadAttr, run, NULL);//创建线程
if (errCode != 0) {
return NULL;
}
return (ThreadId)threadId;//返回void * 类型的线程id
}
- 执行线程回调函数 WaitProcess()
/*
函数功能: 使用忙等方式,调用select()来监听listenFd和数据g_dataFd的信息,如果监听到有数据可读,则进入ProcessAuthData来处理
函数参数:无
函数返回值:无
详细:
*/
static void WaitProcess(void)
{
SOFTBUS_PRINT("[TRANS] WaitProcess begin\n");
fd_set readSet;//可读描述符fd集合
fd_set exceptfds;//异常描述符fd集合
while (1) {//轮询监听可读事件或者异常事件的变化
/*每次调用select前都要重新设置文件描述符和时间,因为事件发生后,文件描述符和时间都被内核修改*/
FD_ZERO(&readSet);//清空描述符集合
FD_ZERO(&exceptfds);
FD_SET(g_listenFd, &readSet);//将监听fd添加到可读集合中
if (g_dataFd >= 0) {//如果通信描述符存在,将通信描述符添加至可读集合和异常集合中
FD_SET(g_dataFd, &readSet);
FD_SET(g_dataFd, &exceptfds);
}
//开始监听readSet和exceptfds
int ret = select(g_maxFd 1, &readSet, NULL, &exceptfds, NULL);
if (ret > 0) {//ret大于0表示监听的集合中有ret个描述符状态发生改变
if (!ProcessAuthData(g_listenFd, &readSet)) {//处理接收到的认证数据
SOFTBUS_PRINT("[TRANS] WaitProcess ProcessAuthData fail\n");
StopListener();//关闭监听器
break;
}
} else if (ret < 0) {//发生错误
//产生中断或者异常
if (errno == EINTR || (g_dataFd > 0 && FD_ISSET(g_dataFd, &exceptfds))) {
SOFTBUS_PRINT("[TRANS] errno == EINTR or g_dataFd is in exceptfds set.\n");
CloseAuthSessionFd(g_dataFd);//关闭认证会话的连接
continue;
}
SOFTBUS_PRINT("[TRANS] WaitProcess select fail, stop listener\n");
StopListener();//关闭监听器
break;
}
}
}
- ProcessAuthData() 函数
/*
函数功能: 处理listenFd的事件调用accept建立连接生成通信描述符g_dataFd,或者处理g_dataFd的通信事件
函数参数:监听描述符listenFd,可读描述符集合
函数返回值:成功返回true,失败返回false
详细:
*/
static bool ProcessAuthData(int listenFd, const fd_set *readSet)
{
if (readSet == NULL || g_callback == NULL || g_callback->onConnectEvent == NULL ||
g_callback->onDataEvent == NULL) {
return false;
}
//如果有设备发起连接,响应listenFd事件,accept建立socket连接,然后调用回调函数onConnectEvent处理连接事件
if (FD_ISSET(listenFd, readSet)) {
struct sockaddr_in addrClient = {0};
socklen_t addrLen = sizeof(addrClient);
g_dataFd = accept(listenFd, (struct sockaddr *)(&addrClient), &addrLen);//建立socket连接
if (g_dataFd < 0) {//accept函数执行出错
CloseAuthSessionFd(listenFd);
return false;
}
//更新最大描述符值,因为后续需要为select函数提供最大描述符值,select函数需要获得监听集合中所有文件描述符的范围
RefreshMaxFd(g_dataFd);
if (g_callback->onConnectEvent(g_dataFd, inet_ntoa(addrClient.sin_addr)) != 0) {//响应连接事件
CloseAuthSessionFd(g_dataFd);
}
}
//如果接收到设备发送的可读数据,响应g_dataFd的事件,调用回调函数onDataEvent处理数据传输事件
if (g_dataFd > 0 && FD_ISSET(g_dataFd, readSet)) {
g_callback->onDataEvent(g_dataFd);//响应通信事件
}
return true;
}
至此,trans_service模块为认证模块提供了认证通道管理和认证数据的收发,具体的认证过程及具体的认证协议在authmanager模块实现。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhibbbki
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22