宝塔服务器面板,一键全能部署及管理,送你10850元礼包,点我领取

在Broadcom中提供了自己的消息机制,有两种消息形式:Request/Response and Event(事件)

Request/Response消息:进程之间的通信都是通过smd,所有的消息都是先发送到smd,smd收到信息后,如果消息目的是smd的就做相应的操作,如果不是,就把这个消息route出去

Event messages :对某些事件感兴趣的进程,可以CMS_MSG_REGISTER_EVENT_INTEREST注册此感兴趣事件。事件发生时,将事件信息发送给smd,smd再将事件信息发送给感兴趣的进程。

1. smd与其他进程的通信的实现

smd监听消息

if fd = socketAF_LOCAL, SOCK_STREAM, 0)) < 0)
{
cmsLog_error”Could not create socket”);
return fd;
}

/*
* Bind my server address and listen.
*/
memset&serverAddr, 0, sizeofserverAddr));
serverAddr.sun_family = AF_LOCAL;
strncpyserverAddr.sun_path, SMD_MESSAGE_ADDR, sizeofserverAddr.sun_path));

rc = bindfd, struct sockaddr *) &serverAddr, sizeofserverAddr));
if rc != 0)
{
cmsLog_error”bind to %s failed, rc=%d errno=%d”, SMD_MESSAGE_ADDR, rc, errno);
closefd);
return -1;
}

rc = listenfd, SMD_MESSAGE_BACKLOG);
if rc != 0)
{
cmsLog_error”listen to %s failed, rc=%d errno=%d”, SMD_MESSAGE_ADDR, rc, errno);
closefd);
return -1;
}

其他进程连接到smd:cmsMsg_init

cmsMsg_init具体实现

/*
* Create a unix domain socket.
*/
handle->commFd = socketAF_LOCAL, SOCK_STREAM, 0);
if handle->commFd < 0)
{
cmsLog_error”Could not create socket”);
cmsMem_freehandle);
return CMSRET_INTERNAL_ERROR;
}

/*
* Set close-on-exec, even though all apps should close their
* fd’s before fork and exec.
*/
if rc = fcntlhandle->commFd, F_SETFD, FD_CLOEXEC)) != 0)
{
cmsLog_error”set close-on-exec failed, rc=%d errno=%d”, rc, errno);
closehandle->commFd);
cmsMem_freehandle);
return CMSRET_INTERNAL_ERROR;
}

/*
* Connect to smd.
*/
memset&serverAddr, 0, sizeofserverAddr));
serverAddr.sun_family = AF_LOCAL;
strncpyserverAddr.sun_path, SMD_MESSAGE_ADDR, sizeofserverAddr.sun_path));

rc = connecthandle->commFd, struct sockaddr *) &serverAddr, sizeofserverAddr));
if rc != 0)
{
cmsLog_error”connect to %s failed, rc=%d errno=%d”, SMD_MESSAGE_ADDR, rc, errno);
closehandle->commFd);
cmsMem_freehandle);
return CMSRET_INTERNAL_ERROR;
}
else
{
cmsLog_debug”commFd=%d connected to smd”, handle->commFd);
}

这样就建立了其他进程与smd的连接,阻塞等待事件的发生

/* pend, waiting for one or more fds to become ready */
rv = selectmaxFd+1, &readFds, NULL, NULL, &tm);

用cmsMsg_send cmsMsg_receive发送接收信息,事件发生之后,processMessage处理信息

2. 与kernel的通信

底层 atm, dsl, eth 状态发生改变的时候,会发信息给ssk,ssk再把信息发送给smd

/*
* Initialize special socket to kernel for WAN link-up, link-down events.
* The kernel notification mechanism uses the error channel of some existing fd.
* See webmain in cfm/web.
*/
if ret = initKernelMonitorFd)) != CMSRET_SUCCESS)

initKernelMonitorFd:

if kernelMonitorFd = socketAF_NETLINK, SOCK_RAW, NETLINK_BRCM_MONITOR)) < 0)
//if kernelMonitorFd = socketAF_NETLINK, SOCK_RAW, NETLINK_UNUSED)) < 0)
{
cmsLog_error”Could not open netlink socket for kernel monitor”);
return CMSRET_INTERNAL_ERROR;
}
else
{
cmsLog_debug”kernelMonitorFd=%d”, kernelMonitorFd);
}

addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid);
addr.nl_groups = 0;

if bindkernelMonitorFd,struct sockaddr *)&addr,sizeofaddr))<0)
{
cmsLog_error”Could not bind netlink socket for kernel monitor”);
closekernelMonitorFd);
kernelMonitorFd = CMS_INVALID_FD;
return CMSRET_INTERNAL_ERROR;
}

然后将kernelMonitorFd  加入select集中,阻塞n = selectmaxFd+1, &readFds, NULL, &errorFds, &tv);

if FD_ISSETkernelMonitorFd, &readFds))
{
processKernelMonitor);
}

processKernelMonitor:轮询信息

/* There can be more than one message per recvmsg */
fornl_msgHdr = struct nlmsghdr *) buf; NLMSG_OK nl_msgHdr, unsigned int)recvLen);
nl_msgHdr = NLMSG_NEXT nl_msgHdr, recvLen))

3. 事件消息

首先需要注册感兴趣的事件

msg->type = CMS_MSG_REGISTER_EVENT_INTEREST;
msg->flags_request = 1;
msg->flags_response = 0;
msg->flags_event = 0;
msg->wordData = CMS_MSG_DHCP6C_STATE_CHANGED;
if ret = cmsMsg_sendAndGetReplymsgHandle, msg)) != CMSRET_SUCCESS)
{

}

当dhcp6c发生改变的时候,发送事件信息到smd

msg->type = CMS_MSG_DHCP6C_STATE_CHANGED;
msg->src = MAKE_SPECIFIC_EIDgetpid), EID_DHCP6C);
msg->dst = EID_SMD;
msg->flags_event = 1;
msg->dataLength = sizeofDhcp6cStateChangedMsgBody);

memcpydhcp6cBody, &dhcp6cMsgBody, sizeofDhcp6cStateChangedMsgBody));

if ret = cmsMsg_sendmsgHandle, msg)) != CMSRET_SUCCESS)

smd收到事件信息之后,查找感兴趣的进程将信息发送出去

distributeEventMessage

这里CMS_MSG_DHCP6C_STATE_CHANGED是在ssk注册的,所以到ssk,ssk收到信息之后

#ifdef DMP_X_BROADCOM_COM_IPV6_1 /* aka SUPPORT_IPV6 */
case CMS_MSG_DHCP6C_STATE_CHANGED:
processDhcp6cStateChangedmsg);
break;