Set the socket family in recvfrom() (XCC)
[akaros.git] / tools / compilers / gcc-glibc / glibc-2.19-akaros / sysdeps / akaros / recvfrom.c
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. */
25 static 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 than
40          * 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                 remote->sin_port = (p[0] << 0) | (p[1] << 8);
55                 remote->sin_port = *(uint16_t *) p;
56                 *fromlen = sizeof(struct sockaddr_in);
57         }
58         return ret;
59 }
60
61 ssize_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 (from.__sockaddr__ && getsockname(fd, from, fromlen) < 0)
70                 return -1;
71         if (udp_sock_get_rock(fd))
72                 return __recvfrom_udp(fd, iov, iovcnt, flags, from, fromlen);
73         else
74                 return readv(fd, iov, iovcnt);
75 }
76
77 /* Read N bytes into BUF through socket FD from peer at address FROM (which is
78  * FROMLEN bytes long).  Returns the number read or -1 for errors.  */
79 ssize_t __recvfrom(int fd, void *__restrict buf, size_t n,
80                                    int flags, __SOCKADDR_ARG from,
81                                    socklen_t * __restrict fromlen)
82 {
83         struct iovec iov[1];
84
85         iov[0].iov_base = buf;
86         iov[0].iov_len = n;
87         return __recvfrom_iov(fd, iov, 1, flags, from, fromlen);
88 }
89 weak_alias(__recvfrom, recvfrom)