zoukankan      html  css  js  c++  java
  • Broadcom的消息机制

    在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 = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
    {
    cmsLog_error("Could not create socket");
    return fd;
    }

    /*
    * 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));

    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_init

    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;

  • 相关阅读:
    SVN相关
    Sublime text 2/3 中 Package Control 的安装与使用方法
    JavaScript 限制input输入类型(多种方法实现)
    yahoo的30条优化规则
    浏览器页面加载解析渲染机制(一)
    Cookies 和 Session的区别
    Post Get 区别
    Vue 学习之 关键字、关键单词
    移动H5前端性能优化指南
    『Python基础练习题』day01
  • 原文地址:https://www.cnblogs.com/chenxuelian/p/6135655.html
Copyright © 2011-2022 走看看