Example #1
0
int
socket(int domain, int stype, int protocol)
{
	Rock *r;
	int cfd, fd, n;
	int pfd[2];
	char *net;

	switch(domain){
	case PF_INET:
	case PF_INET6:
		/* get a free network directory */
		switch(stype){
		case SOCK_DGRAM:
			net = "udp";
			cfd = open("/net/udp/clone", O_RDWR);
			break;
		case SOCK_STREAM:
			net = "tcp";
			cfd = open("/net/tcp/clone", O_RDWR);
			break;
		case SOCK_RDM:
			net = "il";
			cfd = open("/net/il/clone", O_RDWR);
			break;
		default:
			errno = EPROTONOSUPPORT;
			return -1;
		}
		if(cfd < 0)
			return -1;
		return _sock_data(cfd, net, domain, stype, protocol, 0);
	case PF_UNIX:
		if(pipe(pfd) < 0)
			return -1;
		r = _sock_newrock(pfd[0]);
		if(r == 0){
			close(pfd[0]);
			close(pfd[1]);
			errno = ENOBUFS;
			return -1;
		}
		r->domain = domain;
		r->stype = stype;
		r->protocol = protocol;
		r->other = pfd[1];
		return pfd[0];
	default:
		errno = EPROTONOSUPPORT;
		return -1;
	}
}
Example #2
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;
	}
}
Example #3
0
/*
 * replace the fd with a pipe and start a process to
 * accept calls in.  this is all to make select work.
 */
static int
listenproc(Rock *r, int fd)
{
	Rock *nr;
	char *net;
	int cfd, nfd, dfd;
	int pfd[2];
	struct stat d;
	char *p;
	char listen[Ctlsize];
	char name[Ctlsize];

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

	strcpy(listen, r->ctl);
	p = strrchr(listen, '/');
	if(p == 0)
		return -1;
	strcpy(p+1, "listen");

	if(pipe(pfd) < 0)
		return -1;

	/* replace fd with a pipe */
	nfd = dup(fd);
	dup2(pfd[0], fd);
	close(pfd[0]);
	fstat(fd, &d);
	r->inode = d.st_ino;
	r->dev = d.st_dev;

	/* start listening process */
	switch(fork()){
	case -1:
		close(pfd[1]);
		close(nfd);
		return -1;
	case 0:
		if(_muxsid == -1) {
			rfork(RFNOTEG);
			_muxsid = getpgrp();
		} else
			setpgid(getpid(), _muxsid);
		rendezvous(2, _muxsid);
		break;
	default:
		atexit(_killmuxsid);
		_muxsid = rendezvous(2, 0);
		close(pfd[1]);
		close(nfd);
		return 0;
	}

/*	for(fd = 0; fd < 30; fd++)
		if(fd != nfd && fd != pfd[1])
			close(fd); */

	for(;;){
		cfd = open(listen, O_RDWR);
		if(cfd < 0)
			break;

		dfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr);
		if(dfd < 0)
			break;

		if(write(pfd[1], nr->ctl, strlen(nr->ctl)) < 0)
			break;
		if(read(pfd[1], name, sizeof(name)) <= 0)
			break;

		close(dfd);
	}
	exit(0);
	return 0;
}
Example #4
0
/* Create a new socket of type TYPE in domain DOMAIN, using
   protocol PROTOCOL.  If PROTOCOL is zero, one is chosen automatically.
   Returns a file descriptor for the new socket, or -1 for errors.  */
int __socket(int domain, int type, int protocol)
{
	Rock *r;
	int cfd, n;
	int open_flags = O_RDWR;
	int pfd[2];
	char *net;
	char msg[128];
	static struct close_cb _sock_close_cb = {.func = _sock_fd_closed};

	run_once(register_close_cb(&_sock_close_cb));

	switch (domain) {
		case PF_INET:
			open_flags |= (type & SOCK_NONBLOCK ? O_NONBLOCK : 0);
			/* get a free network directory */
			switch (_sock_strip_opts(type)) {
				case SOCK_DGRAM:
					net = "udp";
					cfd = open("/net/udp/clone", open_flags);
					/* All BSD UDP sockets are in 'headers' mode, where each
					 * packet has the remote addr:port, local addr:port and
					 * other info. */
					if (!(cfd < 0)) {
						n = snprintf(msg, sizeof(msg), "headers");
						n = write(cfd, msg, n);
						if (n < 0) {
							perror("UDP socket headers failed");
							return -1;
						}
						if (lseek(cfd, 0, SEEK_SET) != 0) {
							perror("UDP socket seek failed");
							return -1;
						}
					}
					break;
				case SOCK_STREAM:
					net = "tcp";
					cfd = open("/net/tcp/clone", open_flags);
					break;
				default:
					errno = EPROTONOSUPPORT;
					return -1;
			}
			if (cfd < 0) {
				return -1;
			}
			return _sock_data(cfd, net, domain, type, protocol, 0);
		case PF_UNIX:
			if (pipe(pfd) < 0) {
				return -1;
			}
			r = _sock_newrock(pfd[0]);
			r->domain = domain;
			r->stype = _sock_strip_opts(type);
			r->sopts = _sock_get_opts(type);
			r->protocol = protocol;
			r->other = pfd[1];
			return pfd[0];
		default:
			errno = EPROTONOSUPPORT;
			return -1;
	}
}
Example #5
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;
	}
}