Search code examples
udppipesplicezero-copy

Linux splice() returning EINVAL ("Invalid argument")


I'm trying to experiment with using splice (man 2 splice) to copy data from a UDP socket directly to a file. Unfortunately the first call to splice() returns EINVAL.

The man page states:

EINVAL Target file system doesn't support splicing; target file is opened in
       append mode; neither of the descriptors refers to a pipe; or offset
       given for nonseekable device.

However, I believe none of those conditions apply. I'm using Fedora 15 (kernel 2.6.40-4) so I believe splice() is supported on all filesystems. The target file should be irrelevant in the first call to splice, but for completeness I'm opening it via open(path, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR). Both calls use a pipe and neither call uses an offset besides NULL.

Here's my sample code:

int sz = splice(sock_fd, 0, mPipeFds[1], 0, 8192, SPLICE_F_MORE);
if (-1 == sz)
{
int err = errno;
LOG4CXX_ERROR(spLogger, "splice from: " << strerror(err));
return 0;
}

sz = splice(mPipeFds[0], 0, file_fd, 0, sz, SPLICE_F_MORE);
if (-1 == sz)
{
int err = errno;
LOG4CXX_ERROR(spLogger, "splice to: " << strerror(err));
}

return 0;

sock_fd is initialized by the following psuedocode:

int sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK);
bind(sock_fd, ...);

Possibly related is that this code snippet is running inside a libevent loop. libevent is using epoll() to determine if the UDP socket is hot.


Solution

  • 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