Use iovecs for sendto() (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 2 Sep 2016 18:05:45 +0000 (14:05 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 6 Sep 2016 13:26:23 +0000 (09:26 -0400)
This is a prereq for handling sendmsg() nicely.  Callers of sendmsg() are
likely to actually use iovecs, so we should attempt to support that.  Note
that readv()/writev() are not vectored yet.

Rebuild glibc.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sendto.c

index 55a6d8b..c7c48ff 100644 (file)
 
 #include <sys/plan9_helpers.h>
 
-/* Send N bytes of BUF on socket FD to peer at address TO (which is
-   TOLEN bytes long).  Returns the number sent, or -1 for errors.  */
-ssize_t __sendto(int fd, const void *buf, size_t n,
-                                int flags, __CONST_SOCKADDR_ARG to, socklen_t tolen)
+/* UDP sockets need to have headers added to the payload for all packets, since
+ * we're supporting blind sendto/recvfrom. */
+static ssize_t __sendto_udp(Rock *r, int fd, const struct iovec *iov, int
+                            iovcnt, int flags, __CONST_SOCKADDR_ARG to,
+                            socklen_t tolen)
+{
+       int ret;
+       uint32_t remote_addr;
+       uint16_t remote_port;
+       struct iovec real_iov[iovcnt + 1];
+       char hdrs[P9_UDP_HDR_SZ];
+       uint8_t *p;
+
+       real_iov[0].iov_base = hdrs;
+       real_iov[0].iov_len = P9_UDP_HDR_SZ;
+       memcpy(real_iov + 1, iov, iovcnt * sizeof(struct iovec));
+       memset(hdrs, 0, P9_UDP_HDR_SZ);
+
+       /* Might not have a to if we were called from send() */
+       if (!to.__sockaddr__) {
+               /* if they didn't connect yet, then there's no telling what raddr
+                * will be.  TODO: check a state flag or something? */
+               to.__sockaddr__ = (struct sockaddr *)(&r->raddr);
+       }
+       remote_addr = (to.__sockaddr_in__)->sin_addr.s_addr;
+       remote_port = (to.__sockaddr_in__)->sin_port;
+       p = (uint8_t*)hdrs;
+       naddr_to_plan9addr(remote_addr, p);
+       p += 16;
+       /* we don't need to specify an address.  if we don't specify a valid
+        * local IP addr, the kernel will pick the one closest to dest */
+       p += 16;
+       p += 16;        /* skip ipifc */
+       *(uint16_t*)p = remote_port;
+       p += 2;
+       p += 2; /* skip local port */
+
+       ret = writev(fd, real_iov, iovcnt + 1);
+       ret -= P9_UDP_HDR_SZ;
+       if (ret < 0)
+               return -1;
+       return ret;
+}
+
+ssize_t __sendto_iov(int fd, const struct iovec *iov, int iovcnt,
+                     int flags, __CONST_SOCKADDR_ARG to, socklen_t tolen)
 {
        Rock *r;
+
        if (flags & MSG_OOB) {
                errno = EOPNOTSUPP;
                return -1;
        }
-       /* UDP sockets need to have headers added to the payload for all packets,
-        * since we're supporting blind sendto/recvfrom. */
-       if ((r = udp_sock_get_rock(fd))) {
-               int ret;
-               uint32_t remote_addr;
-               uint16_t remote_port;
-               uint8_t *p, *newbuf;
-               /* Might not have a to if we were called from send() */
-               if (!to.__sockaddr__) {
-                       /* if they didn't connect yet, then there's no telling what raddr
-                        * will be.  TODO: check a state flag or something? */
-                       to.__sockaddr__ = (struct sockaddr *)(&r->raddr);
-               }
-               remote_addr = (to.__sockaddr_in__)->sin_addr.s_addr;
-               remote_port = (to.__sockaddr_in__)->sin_port;
-               newbuf = malloc(n + P9_UDP_HDR_SZ);
-               if (!newbuf) {
-                       errno = ENOMEM;
-                       return -1;
-               }
-               p = newbuf;
-               naddr_to_plan9addr(remote_addr, p);
-               p += 16;
-               /* we don't need to specify an address.  if we don't specify a valid
-                * local IP addr, the kernel will pick the one closest to dest */
-               p += 16;
-               p += 16;        /* skip ipifc */
-               *(uint16_t *) p = remote_port;
-               p += 2;
-               p += 2; /* skip local port */
-               memcpy(p, buf, n);
-               ret = write(fd, newbuf, n + P9_UDP_HDR_SZ);
-               free(newbuf);
-               if (ret < 0)
-                       return -1;
-               return ret - P9_UDP_HDR_SZ;
-       }
-       return write(fd, buf, n);
+       r = udp_sock_get_rock(fd);
+       if (r)
+               return __sendto_udp(r, fd, iov, iovcnt, flags, to, tolen);
+       else
+               return writev(fd, iov, iovcnt);
 }
 
+/* Send N bytes of BUF on socket FD to peer at address TO (which is TOLEN bytes
+ * long).  Returns the number sent, or -1 for errors.  */
+ssize_t __sendto(int fd, const void *buf, size_t n,
+                                int flags, __CONST_SOCKADDR_ARG to, socklen_t tolen)
+{
+       struct iovec iov[1];
+
+       iov[0].iov_base = buf;
+       iov[0].iov_len = n;
+       return __sendto_iov(fd, iov, 1, flags, to, tolen);
+}
 weak_alias(__sendto, sendto)