Esempio n. 1
0
int
getpeername(int fd, void *addr, int *alen)
{
	Rock *r;
	int i;
	struct sockaddr_in *rip;
	struct sockaddr_un *runix;

	r = _sock_findrock(fd, 0);
	if(r == 0){
		errno = ENOTSOCK;
		return -1;
	}

	switch(r->domain){
	case PF_INET:
		rip = (struct sockaddr_in*)&r->raddr;
		memmove(addr, rip, sizeof(struct sockaddr_in));
		*alen = sizeof(struct sockaddr_in);
		break;
	case PF_UNIX:
		runix = (struct sockaddr_un*)&r->raddr;
		i = &runix->sun_path[strlen(runix->sun_path)] - (char*)runix;
		memmove(addr, runix, i);
		*alen = i;
		break;
	default:
		errno = EAFNOSUPPORT;
		return -1;
	}
	return 0;
}
Esempio n. 2
0
Rock *_sock_newrock(int fd)
{
	Rock *r;
	struct stat d;

	fstat(fd, &d);
	r = _sock_findrock(fd, &d);
	if (r == 0) {
		r = malloc(sizeof(Rock));
		if (r == 0)
			return 0;
		r->dev = d.st_dev;
		r->inode = d.st_ino;
		/* TODO: this is not thread-safe! */
		r->next = _sock_rock;
		_sock_rock = r;
	}
	assert(r->dev == d.st_dev);
	assert(r->inode == d.st_ino);
	r->domain = 0;
	r->stype = 0;
	r->sopts = 0;
	r->protocol = 0;
	memset(&r->addr, 0, sizeof(r->addr_stor));
	r->reserved = 0;
	memset(&r->raddr, 0, sizeof(r->raddr_stor));
	r->ctl[0] = '\0';
	r->other = -1;
	r->is_listener = FALSE;
	r->listen_fd = -1;
	return r;
}
Esempio n. 3
0
Rock*
_sock_newrock(int fd)
{
	Rock *r;
	struct stat d;

	r = _sock_findrock(fd, &d);
	if(r == 0){
		r = malloc(sizeof(Rock));
		if(r == 0)
			return 0;
		r->dev = d.st_dev;
		r->inode = d.st_ino;
		r->other = -1;
		r->next = _sock_rock;
		_sock_rock = r;
	}
	memset(&r->raddr, 0, sizeof(r->raddr));
	memset(&r->addr, 0, sizeof(r->addr));
	r->reserved = 0;
	r->dev = d.st_dev;
	r->inode = d.st_ino;
	r->other = -1;
	return r;
}
Esempio n. 4
0
int
getsockname(int fd, struct sockaddr *addr, int *alen)
{
	Rock *r;
	int i;
	struct sockaddr_in *lip;
	struct sockaddr_un *lunix;

	r = _sock_findrock(fd, 0);
	if(r == 0){
		errno = ENOTSOCK;
		return -1;
	}

	switch(r->domain){
	case PF_INET:
		lip = (struct sockaddr_in*)addr;
		_sock_ingetaddr(r, lip, alen, "local");
		break;
	case PF_UNIX:
		lunix = (struct sockaddr_un*)&r->addr;
		i = &lunix->sun_path[strlen(lunix->sun_path)] - (char*)lunix;
		memmove(addr, lunix, i);
		*alen = i;
		break;
	default:
		errno = EAFNOSUPPORT;
		return -1;
	}
	return 0;
}
Esempio n. 5
0
/* Used by user/iplib (e.g. epoll).  Opens and returns the FD for the
 * conversation's listen fd, which the caller needs to close.  Returns -1 if the
 * FD is not a listener. */
int _sock_get_listen_fd(int sock_fd)
{
	char listen_file[Ctlsize + 3];
	char *x, *last_ctl;
	Rock *r = _sock_findrock(sock_fd, 0);
	int ret;

	if (!r)
		return -1;
	if (!r->is_listener)
		return -1;
	/* We want an FD for the "listen" file.  This is for epoll.  We
	 * could optimize and only do this on demand, but whatever. */
	strncpy(listen_file, r->ctl, sizeof(listen_file));
	/* We want the conversation directory.  We can find the last "ctl"
	 * in the CTL name (they could have mounted at /ctlfoo/net/) */
	x = listen_file;
	do {
		last_ctl = x;
		x++;	/* move forward enough to not find the same "ctl" */
		x = strstr(x, "ctl");
	} while (x);
	/* last_ctl is either listen_file (if we never found ctl, which should never
	 * happen) or it points at the 'c' in the last "ctl". */
	assert(last_ctl != listen_file);
	strcpy(last_ctl, "listen");
	ret = open(listen_file, O_PATH);
	/* Probably a bug in the rock code (or the kernel!) if we couldn't walk to
	 * our listen. */
	assert(ret >= 0);
	r->listen_fd = ret;
	return ret;
}
Esempio n. 6
0
/* If fd is a nonblocking socket, this returns O_NONBLOCK */
static int get_nonblock_status(int fd)
{
	Rock *r = _sock_findrock(fd, 0);
	if (!r)
		return 0;
	return r->sopts & SOCK_NONBLOCK ? O_NONBLOCK : 0;
}
Esempio n. 7
0
int
issocket(int fd)
{
	Rock *r;

	r = _sock_findrock(fd, 0);
	return (r != 0);
}
Esempio n. 8
0
void _sock_fd_closed(int fd)
{
	Rock *r = _sock_findrock(fd, 0);

	if (!r)
		return;
	if (r->is_listener)
		close(r->listen_fd);
}
Esempio n. 9
0
/* Give the socket FD the local address ADDR (which is LEN bytes long).  */
int __bind(int fd, __CONST_SOCKADDR_ARG addr, socklen_t alen)
{
	int n, cfd;
	socklen_t len;
	Rock *r;
	char msg[128];
	struct sockaddr_in *lip;

	/* assign the address */
	r = _sock_findrock(fd, 0);
	if (r == 0) {
		errno = ENOTSOCK;
		return -1;
	}
	if (alen > sizeof(r->addr_stor)) {
		errno = ENAMETOOLONG;
		return -1;
	}
	memmove(&r->addr, addr.__sockaddr__, alen);

	/* the rest is IP sepecific */
	if (r->domain != PF_INET)
		return 0;

	cfd = open(r->ctl, O_RDWR);
	if (cfd < 0) {
		errno = EBADF;
		return -1;
	}
	lip = (struct sockaddr_in *)&r->addr;
	if (lip->sin_port > 0)
		snprintf(msg, sizeof msg, "bind %d", ntohs(lip->sin_port));
	else
		strcpy(msg, "bind *");
	n = write(cfd, msg, strlen(msg));
	if (n < 0) {
		errno = EOPNOTSUPP;	/* Improve error reporting!!! */
		close(cfd);
		return -1;
	}
	if (lip->sin_port <= 0)
		_sock_ingetaddr(r, lip, &len, "local");
	/* UDP sockets are in headers mode, and need to be announced.  This isn't a
	 * full announce, in that the kernel UDP stack doesn't expect someone to
	 * open the listen file or anything like that. */
	if ((r->domain == PF_INET) && (r->stype == SOCK_DGRAM)) {
		n = snprintf(msg, sizeof(msg), "announce *!%d", ntohs(lip->sin_port));
		n = write(cfd, msg, n);
		if (n < 0) {
			perror("bind-announce failed");
			return -1;
		}
	}
	close(cfd);
	return 0;
}
Esempio n. 10
0
/* Used by user/iplib (e.g. epoll).  Looks up the FD listen file for this
 * conversation.  Returns -1 if the FD is not a listener. */
int _sock_lookup_listen_fd(int sock_fd)
{
	Rock *r = _sock_findrock(sock_fd, 0);

	if (!r)
		return -1;
	if (!r->is_listener)
		return -1;
	return r->listen_fd;
}
Esempio n. 11
0
/* Returns a rock* if the socket exists and is UDP */
Rock *udp_sock_get_rock(int fd)
{
	Rock *r = _sock_findrock(fd, 0);
	if (!r) {
		errno = ENOTSOCK;
		return 0;
	}
	if ((r->domain == PF_INET) && (r->stype == SOCK_DGRAM))
		return r;
	else
		return 0;
}
Esempio n. 12
0
/* Sets the fd's nonblock status IAW arg's settings.  Returns 0 on success.
 * Modifies *arg such that the new version is the one that should be passed to
 * the kernel for setfl. */
static int set_nonblock_status(int fd, int *arg)
{
	int ret = 0;
	Rock *r = _sock_findrock(fd, 0);
	if (!r) {
		/* We don't clear O_NONBLOCK, so non-sockets will still pass it to the
		 * kernel and probably error out */
		return 0;
	}
	/* XOR of two flag tests, checking if we need to change anything */
	if (!(r->sopts & SOCK_NONBLOCK) != !(*arg & O_NONBLOCK))
		ret = toggle_nonblock(r);
	/* Either way, we clear O_NONBLOCK, so we don't ask the kernel to set it */
	*arg &= ~O_NONBLOCK;
	return ret;
}
Esempio n. 13
0
int __setsockopt(int sockfd, int level, int optname, const __ptr_t __optval,
                 socklen_t optlen)
{
	Rock *r = _sock_findrock(sockfd, 0);
	void *optval = (void*)__optval;
	if (!r) {
		/* could be EBADF too, we can't tell */
		__set_errno(ENOTSOCK);
		return -1;
	}
	switch (level) {
		case (SOL_SOCKET):
			return sol_socket_sso(r, optname, optval, optlen);
		default:
			__set_errno(ENOPROTOOPT);
			return -1;
	};
}
Esempio n. 14
0
int
rcmd(char **dst, int port, char *luser, char *ruser, char *cmd, int *fd2p)
{
	char c;
	int i, fd, lfd, fd2, port2;
	struct hostent *h;
	Rock *r;
	struct sockaddr_in in;
	char buf[128];
	void	(*x)(int);

	h = gethostbyname(*dst);
	if(h == 0)
		return -1;
	*dst = h->h_name;

	/* connect using a reserved tcp port */
	fd = socket(PF_INET, SOCK_STREAM, 0);
	if(fd < 0)
		return -1;
	r = _sock_findrock(fd, 0);
	if(r == 0){
		errno = ENOTSOCK;
		return -1;
	}
	r->reserved = 1;
	in.sin_family = AF_INET;
	in.sin_port = htons(port);
	memmove(&in.sin_addr, h->h_addr_list[0], sizeof(in.sin_addr));
	if(connect(fd, &in, sizeof(in)) < 0){
		close(fd);
		return -1;
	}

	/* error stream */
	if(fd2p){
		/* create an error stream and wait for a call in */
		for(i = 0; i < 10; i++){
			lfd = rresvport(&port2);
			if(lfd < 0)
				continue;
			if(listen(lfd, 1) == 0)
				break;
			close(lfd);
		}
		if(i >= 10){
			fprintf(stderr, pbotch);
			return -1;
		}

		snprintf(buf, sizeof buf, "%d", port2);
		if(write(fd, buf, strlen(buf)+1) < 0){
			close(fd);
			close(lfd);
			fprintf(stderr, lbotch);
			return -1;
		}
	} else {
		if(write(fd, "", 1) < 0){
			fprintf(stderr, pbotch);
			return -1;
		}
	}

	/* pass id's and command */
	if(write(fd, luser, strlen(luser)+1) < 0
	|| write(fd, ruser, strlen(ruser)+1) < 0
	|| write(fd, cmd, strlen(cmd)+1) < 0){
		if(fd2p)
			close(fd2);
		fprintf(stderr, pbotch);
		return -1;
	}

	if(fd2p){
		x = signal(SIGALRM, ding);
		alarm(15);
		fd2 = accept(lfd, &in, &i);
		alarm(0);
		close(lfd);
		signal(SIGALRM, x);

		if(fd2 < 0){
			close(fd);
			close(lfd);
			fprintf(stderr, lbotch);
			return -1;
		}
		*fd2p = fd2;
	}

	/* get reply */
	if(read(fd, &c, 1) != 1){
		if(fd2p)
			close(fd2);
		fprintf(stderr, pbotch);
		return -1;
	}
	if(c == 0)
		return fd;
	i = 0;
	while(c){
		buf[i++] = c;
		if(read(fd, &c, 1) != 1)
			break;
		if(i >= sizeof(buf)-1)
			break;
	}
	buf[i] = 0;
	fprintf(stderr, "rcmd: %s\n", buf);
	close(fd);
	return -1;
}
Esempio n. 15
0
#include <sys/uio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>

#include "plan9_sockets.h"

/* Put the local address of FD into *ADDR and its length in *LEN.  */
int __getsockname(int fd, __SOCKADDR_ARG addr, socklen_t * __restrict alen)
{
	Rock *r;
	int i;
	struct sockaddr_in *lip;
	struct sockaddr_un *lunix;

	r = _sock_findrock(fd, 0);
	if (r == 0) {
		errno = ENOTSOCK;
		return -1;
	}

	switch (r->domain) {
		case PF_INET:
			lip = addr.__sockaddr_in__;
			_sock_ingetaddr(r, lip, alen, "local");
			break;
		case PF_UNIX:
			lunix = (struct sockaddr_un *)&r->addr;
			i = &lunix->sun_path[strlen(lunix->sun_path)] - (char *)lunix;
			memmove(addr.__sockaddr_un__, lunix, i);
			*alen = i;
Esempio n. 16
0
int
listen(int fd, int i)
{
	Rock *r;
	int n, cfd;
	char msg[128];
	struct sockaddr_in *lip;
	struct sockaddr_un *lunix;

	r = _sock_findrock(fd, 0);
	if(r == 0){
		errno = ENOTSOCK;
		return -1;
	}

	switch(r->domain){
	case PF_INET:
		cfd = open(r->ctl, O_RDWR);
		if(cfd < 0){
			errno = EBADF;
			return -1;
		}
		lip = (struct sockaddr_in*)&r->addr;
		if(1 || lip->sin_port >= 0) {	/* sin_port is unsigned */
			if(write(cfd, "bind 0", 6) < 0) {
				errno = EGREG;
				close(cfd);
				return -1;
			}
			snprintf(msg, sizeof msg, "announce %d",
				ntohs(lip->sin_port));
		}
		else
			strcpy(msg, "announce *");
		n = write(cfd, msg, strlen(msg));
		if(n < 0){
			errno = EOPNOTSUPP;	/* Improve error reporting!!! */
			close(cfd);
			return -1;
		}
		close(cfd);

		return listenproc(r, fd);
	case PF_UNIX:
		if(r->other < 0){
			errno = EGREG;
			return -1;
		}
		lunix = (struct sockaddr_un*)&r->addr;
		if(_sock_srv(lunix->sun_path, r->other) < 0){
			_syserrno();
			r->other = -1;
			return -1;
		}
		r->other = -1;
		return 0;
	default:
		errno = EAFNOSUPPORT;
		return -1;
	}
}
Esempio n. 17
0
int __libc_accept4(int fd, __SOCKADDR_ARG addr, socklen_t *alen, int a4_flags)
{
	int nfd, lcfd;
	socklen_t n;
	Rock *r, *nr;
	struct sockaddr_in *ip;
	char name[Ctlsize];
	char file[8 + Ctlsize + 1];
	const char *net = 0;
	char listen[Ctlsize];
	int open_flags;

	r = _sock_findrock(fd, 0);
	if (r == 0) {
		errno = ENOTSOCK;
		return -1;
	}

	switch (r->domain) {
	case PF_INET:
		switch (r->stype) {
		case SOCK_DGRAM:
			net = "udp";
			break;
		case SOCK_STREAM:
			net = "tcp";
			break;
		}
		/* at this point, our FD is for the data file.  we need to open
		 * the listen file. */
		_sock_get_conv_filename(r, "listen", listen);
		open_flags = O_RDWR;
		/* This is for the listen - maybe don't block on open */
		open_flags |= (r->sopts & SOCK_NONBLOCK ? O_NONBLOCK : 0);
		/* This is for the ctl we get back - maybe CLOEXEC, based on
		 * what accept4 wants for the child */
		open_flags |= (a4_flags & SOCK_CLOEXEC ? O_CLOEXEC : 0);
		lcfd = open(listen, open_flags);
		if (lcfd < 0)
			return -1;
		/* at this point, we have a new conversation, and lcfd is its
		 * ctl fd.  nfd will be the FD for that conv's data file.
		 * sock_data will store our lcfd in the rock and return the data
		 * file fd.
		 *
		 * Note, we pass the listen socket's stype, but not it's sopts.
		 * The sopts (e.g. SOCK_NONBLOCK) apply to the original socket,
		 * not to the new one.  Instead, we pass the accept4 flags,
		 * which are the sopts for the new socket.  Note that this is
		 * just the sopts.  Both the listen socket and the new socket
		 * have the same stype. */
		nfd = _sock_data(lcfd, net, r->domain, a4_flags | r->stype,
		                 r->protocol, &nr);
		if (nfd < 0)
			return -1;

		/* get remote address */
		ip = (struct sockaddr_in *)&nr->raddr;
		_sock_ingetaddr(nr, ip, &n, "remote");
		if (addr.__sockaddr__) {
			memmove(addr.__sockaddr_in__, ip,
				sizeof(struct sockaddr_in));
			*alen = sizeof(struct sockaddr_in);
		}

		return nfd;
	case PF_UNIX:
		if (r->other >= 0) {
			errno = EINVAL;	// was EGREG
			return -1;
		}

		for (;;) {
			/* read path to new connection */
			n = read(fd, name, sizeof(name) - 1);
			if (n < 0)
				return -1;
			if (n == 0)
				continue;
			name[n] = 0;

			/* open new connection */
			_sock_srvname(file, name);
			open_flags = O_RDWR;
			/* This is for the listen - maybe don't block on open */
			open_flags |= (r->sopts &
				       SOCK_NONBLOCK ? O_NONBLOCK : 0);
			/* This is for the ctl we get back - maybe CLOEXEC,
			 * based on what accept4 wants for the child */
			open_flags |= (a4_flags & SOCK_CLOEXEC ? O_CLOEXEC : 0);
			nfd = open(file, open_flags);
			if (nfd < 0)
				continue;

			/* confirm opening on new connection */
			if (write(nfd, name, strlen(name)) > 0)
				break;

			close(nfd);
		}

		nr = _sock_newrock(nfd);
		if (nr == 0) {
			close(nfd);
			return -1;
		}
		nr->domain = r->domain;
		nr->stype = r->stype;
		nr->sopts = a4_flags;
		nr->protocol = r->protocol;

		return nfd;
	default:
		errno = EOPNOTSUPP;
		return -1;
	}
}
Esempio n. 18
0
int
accept(int fd, void *a, int *alen)
{
	int n, nfd, cfd;
	Rock *r, *nr;
	struct sockaddr_in *ip;
	char name[Ctlsize];
	char file[8+Ctlsize+1];
	char *net;

	r = _sock_findrock(fd, 0);
	if(r == 0){
		errno = ENOTSOCK;
		return -1;
	}

	switch(r->domain){
	case PF_INET:
		switch(r->stype){
		case SOCK_DGRAM:
			net = "udp";
			break;
		case SOCK_STREAM:
			net = "tcp";
			break;
		default:
			net = "gok";
			break;
		}

		/* get control file name from listener process */
		n = read(fd, name, sizeof(name)-1);
		if(n <= 0){
			_syserrno();
			return -1;
		}
		name[n] = 0;
		cfd = open(name, O_RDWR);
		if(cfd < 0){
			_syserrno();
			return -1;
		}

		nfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr);
		if(nfd < 0){
			_syserrno();
			return -1;
		}

		if(write(fd, "OK", 2) < 0){
			close(nfd);
			_syserrno();
			return -1;
		}

		/* get remote address */
		ip = (struct sockaddr_in*)&nr->raddr;
		_sock_ingetaddr(nr, ip, &n, "remote");
		if(a){
			memmove(a, ip, sizeof(struct sockaddr_in));
			*alen = sizeof(struct sockaddr_in);
		}

		return nfd;
	case PF_UNIX:
		if(r->other >= 0){
			errno = EGREG;
			return -1;
		}

		for(;;){
			/* read path to new connection */
			n = read(fd, name, sizeof(name) - 1);
			if(n < 0)
				return -1;
			if(n == 0)
				continue;
			name[n] = 0;

			/* open new connection */
			_sock_srvname(file, name);
			nfd = open(file, O_RDWR);
			if(nfd < 0)
				continue;

			/* confirm opening on new connection */
			if(write(nfd, name, strlen(name)) > 0)
				break;

			close(nfd);
		}

		nr = _sock_newrock(nfd);
		if(nr == 0){
			close(nfd);
			return -1;
		}
		nr->domain = r->domain;
		nr->stype = r->stype;
		nr->protocol = r->protocol;

		return nfd;
	default:
		errno = EOPNOTSUPP;
		return -1;
	}
}