| /* |
| * This file is part of the UCB release of Plan 9. It is subject to the license |
| * terms in the LICENSE file found in the top-level directory of this |
| * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No |
| * part of the UCB release of Plan 9, including this file, may be copied, |
| * modified, propagated, or distributed except according to the terms contained |
| * in the LICENSE file. |
| */ |
| /* posix */ |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <stdlib.h> |
| |
| /* bsd extensions */ |
| #include <sys/uio.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| |
| #include <sys/plan9_helpers.h> |
| |
| /* 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 */ |
| /* remote_port and p are both in network-ordering */ |
| *(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; |
| } |
| 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) |