> After digging through test_socket.py for over an hour (the MRO for
> RecvmsgUDP6Test is enormous!!), I've boiled the issue down to this:
>
> import socket
> MSG = b'asdf qwer zxcv'
> serv = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
> serv.bind(("::1", 0))
> cli = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
> cli.bind(("::1", 0))
> cli.sendto(MSG, serv.getsockname())
> print(serv.recvmsg(len(MSG) - 3, 0, socket.MSG_PEEK))
> print(serv.recvmsg(len(MSG), 0, socket.MSG_PEEK))
> print(serv.recvmsg(len(MSG)))
>
> On my main system, this produces three lines of output: the first has
> truncated text, the second has full text, and the third also has full
> text. This proves that MSG_PEEK is working correctly. On the buildbot,
> though, the first one stalls out. Commenting that line out produces
> correct results - peek the full data, then read it, and all is well.
>
> Any idea why partial read on a datagram socket would sometimes stall?

I think it would stall if there is no data to receive. Maybe check the
return value of sendto(), to ensure it is sending the whole message.

Attached is a C program which should do the equivalent of your
boiled-down Python script, in case that helps:

$ gcc -Wall peek-udp6.c -o peek-udp6
$ ./peek-udp6
Bytes sent: 14
Received [asdf qwer z]
Received [asdf qwer zxcv]
Received [asdf qwer zxcv]

Other things that come to mind are to see if there is anything odd
about the buildbot’s Linux kernel and glibc versions. Maybe run the
Python script under “strace” to see if anything strange is going on.
/*
$ gcc -Wall peek-udp6.c -o peek-udp6
$ ./peek-udp6
Bytes sent: 14
Received [asdf qwer z]
Received [asdf qwer zxcv]
Received [asdf qwer zxcv]
*/

#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>

static const char MSG[] = "asdf qwer zxcv";
static const size_t MSG_LEN = sizeof MSG - 1;

int main() {
    int serv = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
    if(serv < 0) {
        perror("serv socket()");
        return 1;
    }
    
    struct sockaddr_in6 bind_addr;
    memset(&bind_addr, 0, sizeof bind_addr);
    bind_addr.sin6_family = AF_INET6;
    bind_addr.sin6_port = htons(0);
    bind_addr.sin6_addr = (struct in6_addr)IN6ADDR_LOOPBACK_INIT;
    if(bind(serv, (struct sockaddr *)&bind_addr, sizeof bind_addr) < 0) {
        perror("bind(serv)");
        return 1;
    }
    
    int cli = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
    if(cli < 0) {
        perror("cli socket()");
        return 1;
    }
    
    if(bind(cli, (struct sockaddr *)&bind_addr, sizeof bind_addr) < 0) {
        perror("bind(cli)");
        return 1;
    }
    
    struct sockaddr_in6 addr;
    socklen_t addr_len = sizeof addr;
    if(getsockname(serv, (struct sockaddr *)&addr, &addr_len) < 0) {
        perror("getsockname()");
        return 1;
    }
    ssize_t size;
    size = sendto(cli, MSG, MSG_LEN, 0, (struct sockaddr *)&addr, addr_len);
    if(size < 0) {
        perror("sendto()");
        return 1;
    }
    printf("Bytes sent: %zi\n", size);
    
    char buffer[MSG_LEN];
    struct msghdr message = {
        .msg_name = &addr,
        .msg_namelen = sizeof addr,
        .msg_iov = (struct iovec [1]){
            {.iov_base = buffer, .iov_len = MSG_LEN - 3},
        },
        .msg_iovlen = 1,
    };
    size = recvmsg(serv, &message, MSG_PEEK);
    if(size < 0) {
        perror("short recvmsg(MSG_PEEK)");
        return 1;
    }
    printf("Received [%.*s]\n", (int)size, buffer);
    
    message.msg_iov[0].iov_len = MSG_LEN;
    size = recvmsg(serv, &message, MSG_PEEK);
    if(size < 0) {
        perror("full recvmsg(MSG_PEEK)");
        return 1;
    }
    printf("Received [%.*s]\n", (int)size, buffer);
    
    size = recvmsg(serv, &message, 0);
    if(size < 0) {
        perror("full recvmsg(0)");
        return 1;
    }
    printf("Received [%.*s]\n", (int)size, buffer);
    
    return 0;
}
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to