Linux splice() returning EINVAL (“Invalid argument”)

随声附和 提交于 2019-12-05 12:29:14

Found my answer. tl;dr - UDP isn't supported on the inbound side.

After enough Googling I stumbled upon a forum discussion and some test code which prints out a table of in/out fd types and their support:

$ ./a.out 
in\out     pipe    reg     chr     unix    tcp    udp
pipe       yes     yes     yes     yes     yes    yes
reg        yes     no      no      no      no     no
chr        yes     no      no      no      no     no
unix       no      no      no      no      no     no
tcp        yes     no      no      no      no     no
udp        no      no      no      no      no     no

Yeah, it is definitely not supported for reading from a UDP socket, even in the latest kernels. References to the kernel source follow.

splice invokes do_splice in the kernel, which calls do_splice_to, which calls the splice_read member in the file_operations structure for the file.

For sockets, that structure is defined as socket_file_ops in net/socket.c, which initializes the splice_read field to sock_splice_read.

That function, in turn, contains this line of code:

if (unlikely(!sock->ops->splice_read))
    return -EINVAL;

The ops field of the socket is a struct proto_ops. For an IPv4 UDP socket, it is initialized to inet_dgram_ops in net/ipv4/af_inet.c. Finally, that structure does not explicitly initialize the splice_read field of struct proto_ops; i.e., it initializes it to zero.

So sock_splice_read returns -EINVAL, and that propagates up.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!