Interestingly there are several ways to write to a socket on a BSD system and it is important for me to understand those to be able to adapt the code to Kyu.
It turns out that write() and send() are the same, except that send() gives the ability to add flags (which are all zero for write(). The only one that I can imagine using is the one to send OOB (out of bounds) messages.
There is also sendto(), which is identical to send() if you have a connection. It allows an address to be specified (which might be useful for UDP, but seems of no use for TCP).
Finally there is sendmsg(). Here instead of giving "buf" and "len" you pass a msghdr structure which looks like this:
struct msghdr { void *msg_name; /* Optional address */ socklen_t msg_namelen; /* Size of address */ struct iovec *msg_iov; /* Scatter/gather array */ size_t msg_iovlen; /* # elements in msg_iov */ void *msg_control; /* Ancillary data, see below */ size_t msg_controllen; /* Ancillary data buffer len */ int msg_flags; /* Flags (ignored) */ };Here the big addition is having the "iovec" structure which could be a scatter/gather array. You also get the option to include "control" data, which might be IP options. Note that the flags are ignored, so you don't get to use flags along with scatter/gather.
In the code (kern/uipc_syscalls.c) this gets packaged up in a "uio" structure like this:
struct iovec { char *iov_base; /* Base address. */ size_t iov_len; /* Length. */ }; struct uio { struct iovec *uio_iov; int uio_iovcnt; off_t uio_offset; int uio_resid; enum uio_seg uio_segflg; enum uio_rw uio_rw; }; auio.uio_iov = mp->msg_iov; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_WRITE; auio.uio_offset = 0; auio.uio_resid = 0;We eventually end up in the routine "sosend":
sosend ( so, addr, uio, top, control, flags) sosend ( so, 0, uio, 0, 0, 0 )So for us, all we care about in sosend is the "uio" structure. And the uio itself gets pretty much handled by:
error = uiomove(mtod(m, caddr_t), (int)len, uio);Here data is being copied from user space into a kernel mbuf. The routine uiomove() is in kern/kern_subr.c
Kyu / [email protected]