| /*  | 
 |  * 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) |