Figure 1. Zero-Copy Receive Example #2
static enum onload_zc_callback_rc
zc_recv_callback(struct onload_zc_recv_args *args, int flag)
{
struct user_info *zc_info = args->user_ptr;
int i, zc_rc = 0;
for( i = 0; i < args->msg.msghdr.msg_iovlen; ++i ) {
zc_rc += args->msg.iov[i].iov_len;
handle_msg(args->msg.iov[i].iov_base,
args->msg.iov[i].iov_len);
}
if( zc_rc == 0 )
return ONLOAD_ZC_TERMINATE;
zc_info->zc_rc += zc_rc;
if( (zc_info->flags & MSG_WAITALL) &&
(zc_info->zc_rc < zc_info->size) )
return ONLOAD_ZC_CONTINUE;
else return ONLOAD_ZC_TERMINATE;
}
struct onload_zc_recv_args zc_args;
ssize_t do_recv_zc(int fd, void* buf, size_t len, int flags)
{
struct user_info info; int rc;
init_user_info(&info);
memset(&zc_args, 0, sizeof(zc_args));
zc_args.user_ptr = &info;
zc_args.flags = 0;
zc_args.cb = &zc_recv_callback;
if( flags & MSG_DONTWAIT )
zc_args.flags |= ONLOAD_MSG_DONTWAIT;
rc = onload_zc_recv(fd, &zc_args);
if( rc == -ENOTEMPTY) {
if( ( rc = onload_recvmsg_kernel(fd, &msg, 0) ) < 0 )
printf("onload_recvmsg_kernel failed\n");
}
else if( rc == 0 ) {
/* zc_rc gets set by callback to bytes received, so we
* can return that to appear like standard recv call */
rc = info.zc_rc;
}
return rc;
}
Note:
onload_zc_recv()
should not be used together with onload_set_recv_filter()
and only supports accelerated (Onloaded) sockets. For example, when bound to a broadcast address the socket fd is handed off to the kernel and this function will return ESOCKNOTSUPPORT
.