【问题标题】:Can socket in SCM_RIGHTS protocol type send data even file description is -1即使文件描述为-1,SCM_RIGHTS 协议类型的套接字也可以发送数据
【发布时间】:2021-07-21 22:21:27
【问题描述】:

现在我使用 SCM_RIGHTS 协议来发送 fd(文件描述)。但有时我的 fd 由于某种原因会得到 -1。而且我想告诉接收者,即使在这个时候,发送者也有错。
但是当我使用“sendmsg”时会得到:发送消息失败:文件描述符错误
我的发件人代码如下:

int32_t SendFrame(const char *sockPath, char *sendFrameInfo, uint32_t sendFrameInfoLen,
                  int32_t inFd) {
    int SockFd = socket(AF_UNIX, SOCK_DGRAM, 0);
    struct sockaddr_un peer;

    /* Create name. */
    peer.sun_family = AF_UNIX;
    strcpy(peer.sun_path, sockPath);
    int ret = connect(SockFd, (struct sockaddr *)&peer, sizeof(struct sockaddr_un));
    struct msghdr msg = {0};
    struct cmsghdr *cmsg;
    char buf[CMSG_SPACE(sizeof(int))];
    memset(buf, '\0', sizeof(buf));
    struct iovec io = {.iov_base = (void *)sendFrameInfo, .iov_len = sendFrameInfoLen};

    msg.msg_iov = &io;
    msg.msg_iovlen = 1;
    msg.msg_control = buf;
    msg.msg_controllen = sizeof(buf);

    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));

    memcpy((int *)CMSG_DATA(cmsg), &inFd, sizeof(int));

    if (sendmsg(SockFd, &msg, 0) < 0) {
        printf("SendFrame(%s) Failed to send message: %s", sockPath, strerror(errno));
        return -1;
    }
    return 0;
};

下面是我的接收器代码:

int32_t recvFrame(char *buf, int32_t fd, uint32_t timeout_ms, uint32_t bufsize) {
    struct msghdr msg = {0};
    struct cmsghdr *cmsg;

    char msg_control[CMSG_SPACE(sizeof(int))];
    memset(msg_control, '\0', sizeof(msg_control));
    
    struct iovec io = { .iov_base = &buf, .iov_len = bufsize };

    msg.msg_iov = &io;
    msg.msg_iovlen = 1;
    msg.msg_control = msg_control;
    msg.msg_controllen = sizeof(msg_control);

    struct timeval timeout;
    timeout.tv_sec = timeout_ms / 1000;
    timeout.tv_usec = (timeout_ms % 1000) * 1000;

    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
    ssize_t len = recvmsg(fd, &msg, 0);
    if (len < 0) {
        perror("Failed to receive message");
        return -errno;
    }

    cmsg = CMSG_FIRSTHDR(&msg);

    int new fd = *((int32_t *)CMSG_DATA(cmsg));
    return 0;
}

现在我可以使用那么我如何使用“msg_iov”来发送其他消息。所以我想接收消息事件发送者的 fd 是 -1 然后我可以检查“msg_iov”发生了什么。
谢谢!

BR/蒂姆

【问题讨论】:

    标签: c linux sockets


    【解决方案1】:

    不,你只能传递有效的文件描述符,-1永远不是有效的文件描述符(因为它是在发生错误时返回的)。

    我建议在消息中包含一个特殊字节 (char),用于描述错误——例如,作为消息中的第一个字符。如果传递了文件描述符,则为零,如果发生错误(描述错误的值),则为非零。这样,有效负载数据的长度永远不会为零,这使得在发送任何数据之前检测套接字关闭变得更加容易。 (你看,零长度读取/接收通常表示输入结束。)

    因为errno 值不一定在机器之间匹配,所以您应该将特殊字节值转换为 errno 代码,反之亦然。

    或者,如果消息没有其他数据,您可以将错误消息作为字符串发送,包括末尾的'\0' end-of-string 标记;传递文件描述符时,仅使用 '\0' 作为数据负载。

    【讨论】:

      猜你喜欢
      • 2021-06-06
      • 1970-01-01
      • 1970-01-01
      • 2015-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-09
      • 1970-01-01
      相关资源
      最近更新 更多