akaros/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/recvfrom.c
<<
>>
Prefs
   1/* 
   2 * This file is part of the UCB release of Plan 9. It is subject to the license
   3 * terms in the LICENSE file found in the top-level directory of this
   4 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
   5 * part of the UCB release of Plan 9, including this file, may be copied,
   6 * modified, propagated, or distributed except according to the terms contained
   7 * in the LICENSE file.
   8 */
   9/* posix */
  10#include <sys/types.h>
  11#include <unistd.h>
  12#include <fcntl.h>
  13#include <errno.h>
  14#include <stdlib.h>
  15
  16/* bsd extensions */
  17#include <sys/uio.h>
  18#include <sys/socket.h>
  19#include <netinet/in.h>
  20
  21#include <sys/plan9_helpers.h>
  22
  23/* UDP sockets need to have headers added to the payload for all packets, since
  24 * we're supporting blind sendto/recvfrom. */
  25static ssize_t __recvfrom_udp(int fd, const struct iovec *iov, int iovcnt,
  26                              int flags, __SOCKADDR_ARG from,
  27                              socklen_t * __restrict fromlen)
  28{
  29        int ret;
  30        struct sockaddr_in *remote = from.__sockaddr_in__;
  31        struct iovec real_iov[iovcnt + 1];
  32        char hdrs[P9_UDP_HDR_SZ];
  33        uint8_t *p;
  34
  35        real_iov[0].iov_base = hdrs;
  36        real_iov[0].iov_len = P9_UDP_HDR_SZ;
  37        memcpy(real_iov + 1, iov, iovcnt * sizeof(struct iovec));
  38        ret = readv(fd, real_iov, iovcnt + 1);
  39        /* Subtracting before the check, so that we error out if we got less
  40         * than the headers needed */
  41        ret -= P9_UDP_HDR_SZ;
  42        if (ret < 0)
  43                return -1;
  44        /* Might not have a remote, if we were called via recv().  Could assert
  45         * that it's the same remote that we think we connected to, and that we
  46         * were already connected. (TODO) */
  47        if (remote) {
  48                p = (uint8_t*)hdrs;
  49                remote->sin_family = AF_INET;
  50                remote->sin_addr.s_addr = plan9addr_to_naddr(p);
  51                p += 16;
  52                p += 16;        /* skip local addr */
  53                p += 16;        /* skip ipifc */
  54                /* sin_port and p are both in network-ordering */
  55                remote->sin_port = *(uint16_t*)p;
  56                *fromlen = sizeof(struct sockaddr_in);
  57        }
  58        return ret;
  59}
  60
  61ssize_t __recvfrom_iov(int fd, const struct iovec *iov, int iovcnt,
  62                       int flags, __SOCKADDR_ARG from,
  63                       socklen_t * __restrict fromlen)
  64{
  65        if (flags & MSG_OOB) {
  66                errno = EOPNOTSUPP;
  67                return -1;
  68        }
  69        if (udp_sock_get_rock(fd))
  70                return __recvfrom_udp(fd, iov, iovcnt, flags, from, fromlen);
  71        if (from.__sockaddr__ && getpeername(fd, from, fromlen) < 0)
  72                return -1;
  73        return readv(fd, iov, iovcnt);
  74}
  75
  76/* Read N bytes into BUF through socket FD from peer at address FROM (which is
  77 * FROMLEN bytes long).  Returns the number read or -1 for errors.  */
  78ssize_t __recvfrom(int fd, void *__restrict buf, size_t n, int flags,
  79                   __SOCKADDR_ARG from, socklen_t * __restrict fromlen)
  80{
  81        struct iovec iov[1];
  82
  83        iov[0].iov_base = buf;
  84        iov[0].iov_len = n;
  85        return __recvfrom_iov(fd, iov, 1, flags, from, fromlen);
  86}
  87weak_alias(__recvfrom, recvfrom)
  88