在Broadcom中提供了本身的消息機制,有兩種消息形式:Request/Response and Event(事件)web
Request/Response消息:進程之間的通訊都是經過smd,全部的消息都是先發送到smd,smd收到信息後,若是消息目的是smd的就作相應的操做,若是不是,就把這個消息route出去app
Event messages :對某些事件感興趣的進程,能夠CMS_MSG_REGISTER_EVENT_INTEREST註冊此感興趣事件。事件發生時,將事件信息發送給smd,smd再將事件信息發送給感興趣的進程。dom
1. smd與其餘進程的通訊的實現socket
smd監聽消息debug
if ((fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
{
cmsLog_error("Could not create socket");
return fd;
}unix
/*
* Bind my server address and listen.
*/
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sun_family = AF_LOCAL;
strncpy(serverAddr.sun_path, SMD_MESSAGE_ADDR, sizeof(serverAddr.sun_path));server
rc = bind(fd, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
if (rc != 0)
{
cmsLog_error("bind to %s failed, rc=%d errno=%d", SMD_MESSAGE_ADDR, rc, errno);
close(fd);
return -1;
}進程
rc = listen(fd, SMD_MESSAGE_BACKLOG);
if (rc != 0)
{
cmsLog_error("listen to %s failed, rc=%d errno=%d", SMD_MESSAGE_ADDR, rc, errno);
close(fd);
return -1;
}事件
其餘進程鏈接到smd:cmsMsg_initci
cmsMsg_init具體實現
/*
* Create a unix domain socket.
*/
handle->commFd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (handle->commFd < 0)
{
cmsLog_error("Could not create socket");
cmsMem_free(handle);
return CMSRET_INTERNAL_ERROR;
}
/*
* Set close-on-exec, even though all apps should close their
* fd's before fork and exec.
*/
if ((rc = fcntl(handle->commFd, F_SETFD, FD_CLOEXEC)) != 0)
{
cmsLog_error("set close-on-exec failed, rc=%d errno=%d", rc, errno);
close(handle->commFd);
cmsMem_free(handle);
return CMSRET_INTERNAL_ERROR;
}
/*
* Connect to smd.
*/
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sun_family = AF_LOCAL;
strncpy(serverAddr.sun_path, SMD_MESSAGE_ADDR, sizeof(serverAddr.sun_path));
rc = connect(handle->commFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
if (rc != 0)
{
cmsLog_error("connect to %s failed, rc=%d errno=%d", SMD_MESSAGE_ADDR, rc, errno);
close(handle->commFd);
cmsMem_free(handle);
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 = select(maxFd+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 = socket(AF_NETLINK, SOCK_RAW, NETLINK_BRCM_MONITOR)) < 0)
//if ((kernelMonitorFd = socket(AF_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 (bind(kernelMonitorFd,(struct sockaddr *)&addr,sizeof(addr))<0)
{
cmsLog_error("Could not bind netlink socket for kernel monitor");
close(kernelMonitorFd);
kernelMonitorFd = CMS_INVALID_FD;
return CMSRET_INTERNAL_ERROR;
}
而後將kernelMonitorFd 加入select集中,阻塞n = select(maxFd+1, &readFds, NULL, &errorFds, &tv);
if (FD_ISSET(kernelMonitorFd, &readFds))
{
processKernelMonitor();
}
processKernelMonitor:輪詢信息
/* There can be more than one message per recvmsg */
for(nl_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_sendAndGetReply(msgHandle, msg)) != CMSRET_SUCCESS)
{
}
當dhcp6c發生改變的時候,發送事件信息到smd
msg->type = CMS_MSG_DHCP6C_STATE_CHANGED;
msg->src = MAKE_SPECIFIC_EID(getpid(), EID_DHCP6C);
msg->dst = EID_SMD;
msg->flags_event = 1;
msg->dataLength = sizeof(Dhcp6cStateChangedMsgBody);
memcpy(dhcp6cBody, &dhcp6cMsgBody, sizeof(Dhcp6cStateChangedMsgBody));
if ((ret = cmsMsg_send(msgHandle, 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: processDhcp6cStateChanged(msg); break;