sock_receive_internal() and its (ab)use of uio
sock_receive_internal() and its (ab)use of uio
- Subject: sock_receive_internal() and its (ab)use of uio
- From: Sam Vaughan <email@hidden>
- Date: Mon, 25 Jul 2005 17:58:45 +1000
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:
This email sent to email@hidden