| /*  | 
 |  * 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 <stdlib.h> | 
 | #include <stdio.h> | 
 | #include <fcntl.h> | 
 | #include <string.h> | 
 | #include <errno.h> | 
 |  | 
 | /* bsd extensions */ | 
 | #include <sys/uio.h> | 
 | #include <sys/socket.h> | 
 | #include <netinet/in.h> | 
 | #include <sys/un.h> | 
 | #include <arpa/inet.h> | 
 |  | 
 | #include <sys/plan9_helpers.h> | 
 |  | 
 | /* Open a connection on socket FD to peer at ADDR (which LEN bytes long). | 
 |    For connectionless socket types, just set the default address to send to | 
 |    and the only address from which to accept transmissions. | 
 |    Return 0 on success, -1 for errors.  */ | 
 | int __connect(int fd, __CONST_SOCKADDR_ARG addr, socklen_t alen) | 
 | { | 
 | 	Rock *r; | 
 | 	int n, nfd; | 
 | 	char msg[8 + 256 + 1], file[8 + 256 + 1]; | 
 | 	struct sockaddr_in *lip, *rip; | 
 | 	struct sockaddr_un *runix; | 
 | 	static int vers; | 
 | 	int open_flags; | 
 |  | 
 | 	r = _sock_findrock(fd, 0); | 
 | 	if (r == 0) { | 
 | 		errno = ENOTSOCK; | 
 | 		return -1; | 
 | 	} | 
 | 	if (alen > sizeof(r->raddr_stor)) { | 
 | 		errno = ENAMETOOLONG; | 
 | 		return -1; | 
 | 	} | 
 | 	memmove(&r->raddr, addr.__sockaddr__, alen); | 
 |  | 
 | 	switch (r->domain) { | 
 | 	case PF_INET: | 
 | 		/* UDP sockets are already announced (during bind), so we can't | 
 | 		 * issue a connect message.  Either connect or announce, not | 
 | 		 * both.  All sends will later do a sendto, based off the | 
 | 		 * contents of r->raddr, so we're already done here */ | 
 | 		if (r->stype == SOCK_DGRAM) | 
 | 			return 0; | 
 | 		/* whatever .. */ | 
 | 		rip = (struct sockaddr_in *)addr.__sockaddr_in__; | 
 | 		lip = (struct sockaddr_in *)&r->addr; | 
 | 		if (lip->sin_port) | 
 | 			snprintf(msg, sizeof msg, "connect %s!%d%s %d", | 
 | 				 inet_ntoa(rip->sin_addr), ntohs(rip->sin_port), | 
 | 				 r->reserved ? "!r" : "", ntohs(lip->sin_port)); | 
 | 		else | 
 | 			snprintf(msg, sizeof msg, "connect %s!%d%s", | 
 | 				 inet_ntoa(rip->sin_addr), ntohs(rip->sin_port), | 
 | 				 r->reserved ? "!r" : ""); | 
 | 		n = write(r->ctl_fd, msg, strlen(msg)); | 
 | 		if (n < 0) | 
 | 			return -1; | 
 | 		return 0; | 
 | 	case PF_UNIX: | 
 | 		/* null terminate the address */ | 
 | 		if (alen == sizeof(r->raddr)) | 
 | 			alen--; | 
 | 		*(((char *)&r->raddr) + alen) = 0; | 
 |  | 
 | 		if (r->other < 0) { | 
 | 			errno = EINVAL;	//EGREG; | 
 | 			return -1; | 
 | 		} | 
 |  | 
 | 		/* put far end of our pipe in /srv */ | 
 | 		snprintf(msg, sizeof msg, "UD.%d.%d", getpid(), vers++); | 
 | 		if (_sock_srv(msg, r->other) < 0) { | 
 | 			r->other = -1; | 
 | 			return -1; | 
 | 		} | 
 | 		r->other = -1; | 
 |  | 
 | 		/* tell server the /srv file to open */ | 
 | 		runix = (struct sockaddr_un *)&r->raddr; | 
 | 		_sock_srvname(file, runix->sun_path); | 
 | 		open_flags = O_RDWR; | 
 | 		open_flags |= (r->sopts & SOCK_CLOEXEC ? O_CLOEXEC : 0); | 
 | 		nfd = open(file, open_flags); | 
 | 		if (nfd < 0) { | 
 | 			unlink(msg); | 
 | 			return -1; | 
 | 		} | 
 | 		if (write(nfd, msg, strlen(msg)) < 0) { | 
 | 			close(nfd); | 
 | 			unlink(msg); | 
 | 			return -1; | 
 | 		} | 
 | 		close(nfd); | 
 |  | 
 | 		/* wait for server to open it and then remove it */ | 
 | 		read(fd, file, sizeof(file)); | 
 | 		_sock_srvname(file, msg); | 
 | 		unlink(file); | 
 | 		return 0; | 
 | 	default: | 
 | 		errno = EAFNOSUPPORT; | 
 | 		return -1; | 
 | 	} | 
 | } | 
 | weak_alias(__connect, connect) | 
 | libc_hidden_def(__connect) |