blob: aff60bb74c0838d9523fb5d04a1f925cb67d9083 [file] [log] [blame]
/*
* 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)