Re: sock_receive_internal() and its (ab)use of uio
Re: sock_receive_internal() and its (ab)use of uio
- Subject: Re: sock_receive_internal() and its (ab)use of uio
- From: Josh Graessley <email@hidden>
- Date: Mon, 25 Jul 2005 11:03:31 -0700
Hi Sam,
The socket KPI was written to simplify the use of sockets in the
kernel. The new socket KPI is based more on the user space APIs for
interacting with sockets. sock_send is very much like sendmsg,
sock_receive is like recvmsg.
You may create a new iovec array to point to the buffers you're
interested in copying in to.
One other thing to be aware of is that the pointers in the iovec
array must point to data that resides in the kernel's address space.
If you need to receive in to a buffer in another process you will
need to copy the data yourself. To avoid copying the data twice, you
can use the sock_receivembuf variant which will receive the mbuf
chain without performing a copy.
-josh
On Jul 25, 2005, at 12:58 AM, Sam Vaughan wrote:
I'm trying to clean up the areas in our code where I'm using
symbols from mach_kernel instead of the 10.4 KPI. One of these is
the use of soreceive() and sosend().
I avoided using the KPI on these two initially because the new
interface that uses struct msghdr looked confusing. Now that I've
delved into it a bit more it looks pretty much unworkable. Let me
use sock_receive() here as an example.
When linking directly to the kernel, I can simply pass a uio
pointer to soreceive() as follows:
soreceive(so, NULL, uiop, NULL, NULL, flagsp);
I can do this safe in the knowledge that it will use uio_move() to
transfer the data it reads into my uio, using and updating my
uio_offset and uio_resid fields as appropriate.
My first attempt at a KPI replacement looked like this:
size_t bytes = uio->uio_resid;
struct msghdr msg = {0};
msg.msg_iov = uiop->uio_iov;
msg.msg_iovlen = uiop->uio_iovcnt;
error = sock_receive(so, &msg, 0, &bytes);
if (!error)
{
uiop->uio_offset += bytes;
uiop->uio_resid -= bytes;
ASSERT(uiop->uio_resid >= 0);
}
But it's clearly deficient because the uio_offset isn't being
passed into sock_receive(). It's also not clear that it will use
my uio_resid value. Sure enough when you run it up, this code
asserts pretty quickly, having read more than I wanted it to.
The problem as I see it is that the new socket KPI doesn't allow
you to specify an offset and a resid along with your iovecs. It's
therefore not possible to read into a range of memory somewhere in
the middle of the buffers represented by your iovecs.
If you use sock_receivembuf(), the data argument to
sock_receive_internal() won't be NULL and the value in recvdlen
will get used as the uio's resid. This solves one of the
problems. Unfortunately the call to uio_createwithbuffer() will
still specify 0 for the initial offset of the uio, so this is no
good if you want to read into somewhere in the middle of your buffers.
The only solution I can see at the moment is to create yet another
uio structure before calling sock_receive(). This uio would be
given iovecs with data addresses and lengths that represent the
region of the original buffers to be received into. This is
clearly not an optimal solution, given the extra overhead and
unnecessary code to write and debug.
It seems odd to me that the shiny new uio KPI wasn't used in the
sock_receive() and sock_send() interfaces, since this is exactly
the functionality that uios are designed (and were previously used)
for. I've raised a radar bug requesting sock_receive_uio() and
sock_send_uio() to be added, (#4191646) but I'd be interested to
hear other people's opinions on this.
Sam
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
40apple.com
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden