int MdioIpcServer::syncd_ipc_task_main()

in syncd/MdioIpcServer.cpp [199:441]


int MdioIpcServer::syncd_ipc_task_main()
{
    SWSS_LOG_ENTER();

    int i;
    int fd;
    int len;
    int ret;
    int sock_srv;
    int sock_cli;
    int sock_max;
    syncd_mdio_ipc_conn_t conn[MDIO_CONN_MAX];
    struct sockaddr_un addr;
    char path[64];
    fd_set rfds;
    char cmd[SYNCD_IPC_BUFF_SIZE], resp[SYNCD_IPC_BUFF_SIZE], *argv[64], *save;
    int argc = 0;

    strcpy(path, SYNCD_IPC_SOCK_SYNCD);
    fd = open(path, O_DIRECTORY);
    if (fd < 0)
    {
        SWSS_LOG_ERROR("Unable to open the directory %s for IPC\n", path);
        return errno;
    }

    sock_srv = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock_srv < 0)
    {
        SWSS_LOG_ERROR("socket() returns %d", errno);
        return errno;
    }

    /***************************************/
    /* Set up the UNIX socket address      */
    /* by using AF_UNIX for the family and */
    /* giving it a file path to bind to.   */
    /*                                     */
    /* Delete the file so the bind will    */
    /* succeed, then bind to that file.    */
    /***************************************/
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    sprintf(addr.sun_path, "%s/%s.srv", path, SYNCD_IPC_SOCK_FILE);
    unlink(addr.sun_path);
    if (bind(sock_srv, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        SWSS_LOG_ERROR("bind() returns %d", errno);
        close(sock_srv);
        return errno;
    }

    /* Listen for the upcoming client sockets */
    if (listen(sock_srv, MDIO_CONN_MAX) < 0)
    {
        SWSS_LOG_ERROR("listen() returns %d", errno);
        unlink(addr.sun_path);
        close(sock_srv);
        return errno;
    }

    SWSS_LOG_NOTICE("IPC service is online\n");

    memset(conn, 0, sizeof(conn));
    while (m_taskAlive)
    {
        time_t now;
        struct timeval timeout;

        /* garbage collection */
        now = time(NULL);
        for (i = 0; i < MDIO_CONN_MAX; ++i)
        {
            if ((conn[i].fd > 0) && (conn[i].timeout < now))
            {
                SWSS_LOG_NOTICE("socket %d: connection timeout\n", conn[i].fd);
                close(conn[i].fd);
                conn[i].fd = 0;
                conn[i].timeout = 0;
            }
        }

        /* reset read file descriptors */
        FD_ZERO(&rfds);
        FD_SET(sock_srv, &rfds);
        sock_max = sock_srv;
        for (i = 0; i < MDIO_CONN_MAX; ++i)
        {
            if (conn[i].fd <= 0)
            {
                continue;
            }
            FD_SET(conn[i].fd, &rfds);
            if (sock_max < conn[i].fd)
            {
                sock_max = conn[i].fd;
            }
        }

        /* monitor the socket descriptors */
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        ret = select(sock_max + 1, &rfds, NULL, NULL, &timeout);
        if (ret == 0)
        {
            continue;
        }
        else if (ret < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            else
            {
                SWSS_LOG_ERROR("select() returns %d", errno);
                break;
            }
        }

        /* Accept the new connection */
        now = time(NULL);
        if (FD_ISSET(sock_srv, &rfds))
        {
            sock_cli = accept(sock_srv, NULL, NULL);
            if (sock_cli <= 0)
            {
                SWSS_LOG_ERROR("accept() returns %d", errno);
                continue;
            }

            for (i = 0; i < MDIO_CONN_MAX; ++i)
            {
                if (conn[i].fd <= 0)
                {
                    break;
                }
            }
            if (i < MDIO_CONN_MAX)
            {
                conn[i].fd = sock_cli;
                conn[i].timeout = now + MDIO_SERVER_TIMEOUT;
            }
            else
            {
                SWSS_LOG_ERROR("too many connections!");
                close(sock_cli);
            }
        }

        /* Handle the client requests */
        for (i = 0; i < MDIO_CONN_MAX; ++i)
        {
            sai_status_t rc = SAI_STATUS_NOT_SUPPORTED;

            sock_cli = conn[i].fd;
            if ((sock_cli <= 0) || !FD_ISSET(sock_cli, &rfds))
            {
                continue;
            }

            /* get the command message */
            len = (int)recv(sock_cli, (void *)cmd, sizeof(cmd) - 1, 0);
            if (len <= 0)
            {
                close(sock_cli);
                conn[i].fd = 0;
                conn[i].timeout = 0;
                continue;
            }
            cmd[len] = 0;

            /* tokenize the command string */
            argc = 0;
            std::string str(cmd);
            boost::algorithm::trim(str);
            boost::algorithm::to_lower(str);
            std::vector<char>v(str.size()+1);
            memcpy( &v.front(), str.c_str(), str.size() + 1 );
            argv[argc++] = strtok_r(v.data(), " \t\r\n", &save);
            while (argc < COUNTOF(argv))
            {
                argv[argc] = strtok_r(NULL, " \t\r\n", &save);
                if (argv[argc] == NULL)
                    break;
                ++argc;
            }

            /* command dispatch */
            resp[0] = 0;
            rc = SAI_STATUS_NOT_SUPPORTED;
            if (argv[0] == NULL)
            {
                rc = SAI_STATUS_NOT_SUPPORTED;
            }
            else if (strcmp("mdio", argv[0]) == 0)
            {
                rc = MdioIpcServer::syncd_ipc_cmd_mdio(resp, argc, argv);
                if (rc != 0)
                {
                    SWSS_LOG_ERROR("command %s returns %d", cmd, rc);
                }
            }
            else if (strcmp("mdio-cl22", argv[0]) == 0)
            {
                rc = MdioIpcServer::syncd_ipc_cmd_mdio_cl22(resp, argc, argv);
                if (rc != 0)
                {
                    SWSS_LOG_ERROR("command %s returns %d", cmd, rc);
                }
            }

            /* build the error message */
            if (rc != SAI_STATUS_SUCCESS)
            {
                sprintf(resp, "%d\n", rc);
            }

            /* send out the response */
            len = (int)strlen(resp);
            if (send(sock_cli, resp, len, 0) < len)
            {
                SWSS_LOG_ERROR("send() returns %d", errno);
            }

            /* update the connection timeout counter */
            conn[i].timeout = time(NULL) + MDIO_SERVER_TIMEOUT;
        }
    }

    /* close socket descriptors */
    for (i = 0; i < MDIO_CONN_MAX; ++i)
    {
        if (conn[i].fd <= 0)
        {
            continue;
        }
        close(conn[i].fd);
    }
    close(sock_srv);
    unlink(addr.sun_path);
    return errno;
}