Пример #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;
	}
}
Пример #2
0
int
_sock_data(int cfd, char *net, int domain, int stype, int protocol,
	   Rock **rp)
{
	int n, fd;
	Rock *r;
	char name[Ctlsize];

	/* get the data file name */
	n = read(cfd, name, sizeof(name)-1);
	if(n < 0){
		close(cfd);
		errno = ENOBUFS;
		return -1;
	}
	name[n] = 0;
	n = strtoul(name, 0, 0);
	snprintf(name, sizeof name, "/net/%s/%d/data", net, n);

	/* open data file */
	fd = open(name, O_RDWR);
	close(cfd);
	if(fd < 0){
		close(cfd);
		errno = ENOBUFS;
		return -1;
	}

	/* hide stuff under the rock */
	snprintf(name, sizeof name, "/net/%s/%d/ctl", net, n);
	r = _sock_newrock(fd);
	if(r == 0){
		errno = ENOBUFS;
		close(fd);
		return -1;
	}
	if(rp)
		*rp = r;
	memset(&r->raddr, 0, sizeof(r->raddr));
	memset(&r->addr, 0, sizeof(r->addr));
	r->domain = domain;
	r->stype = stype;
	r->protocol = protocol;
	strcpy(r->ctl, name);
	return fd;
}
Пример #3
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;
	}
}
Пример #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;
	}
}
Пример #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;
	}
}