Example #1
0
void
main(int argc, char **argv)
{
	static char data[1024], dir[1024], ndir[1024];
	int ctl, nctl, fd;

	verbose = 1;

	if(!verbose){
		close(1);
		fd = open("/dev/null", O_WRONLY);
		if(fd != 1){
			dup2(fd, 1);
			close(fd);
		}
	}

	argc--, argv++;
	printf("listen started\n");
	ctl = announce9(argv[0], dir, 0);
	if(ctl < 0){
		fprintf(stderr, "announce %s: %r", argv[0]);
		exit(1);
	}

	for(;;){
		nctl = listen9(dir, ndir, 0);
		if(nctl < 0){
			fprintf(stderr, "listen %s: %r", argv[0]);
			exit(1);
		}

		//switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG)){
		switch(fork()){
		case -1:
			reject9(nctl, ndir, "host overloaded");
			close(nctl);
			continue;
		case 0:
			fd = accept9(nctl, ndir);
			if(fd < 0){
				fprintf(stderr, "accept %s: can't open  %s/data: %r\n",
					argv[0], ndir);
				exit(1);
			}
			printf("incoming call for %s from %s in %s\n", argv[0],
				remoteaddr(ndir), ndir);
			//fprintf(nctl, "keepalive");
			close(ctl);
			close(nctl);
			//putenv("net", ndir);
			/* this is for children that open /dev/cons. Too bad. 
			snprintf(data, sizeof data, "%s/data", ndir);
			bind(data, "/dev/cons", MREPL);
			*/
			dup2(fd, 0);
			dup2(fd, 1);
			dup2(fd, 2);
			close(fd);
			execv(argv[1], argv+1);
//			if(argv[1][0] != '/')
//				exec(smprintf("%s", argv[1]), argv+1);
			fprintf(stderr, "exec: %r\n");
			exit(1);
		default:
			/* reap any available children */
			while (waitpid(-1, 0, WNOHANG) > 0)
				;
			close(nctl);
			break;
		}
	}
}
Example #2
0
int main()
{
	int ret;
	int afd, dfd, lcfd, listen_fd;
	char adir[40], ldir[40];
	int n;
	char buf[256];
	/* We'll use this to see if we actually did epoll_waits instead of blocking
	 * calls.  It's not 100%, but with a human on the other end, it should be
	 * fine. */
	bool has_epolled = FALSE;

#ifdef PLAN9NET
	printf("Using Plan 9's networking stack\n");
	/* This clones a conversation (opens /net/tcp/clone), then reads the cloned
	 * fd (which is the ctl) to givure out the conv number (the line), then
	 * writes "announce [addr]" into ctl.  This "announce" command often has a
	 * "bind" in it too.  plan9 bind just sets the local addr/port.  TCP
	 * announce also does this.  Returns the ctlfd. */
	afd = announce9("tcp!*!23", adir, 0);

	if (afd < 0) {
		perror("Announce failure");
		return -1;
	}
	printf("Announced on line %s\n", adir);
#else
	printf("Using the BSD socket shims over Plan 9's networking stack\n");
	int srv_socket, con_socket;
	struct sockaddr_in dest, srv = {0};
	srv.sin_family = AF_INET;
	srv.sin_addr.s_addr = htonl(INADDR_ANY);
	srv.sin_port = htons(23);
	socklen_t socksize = sizeof(struct sockaddr_in);

	/* Equiv to cloning a converstation in plan 9.  The shim returns the data FD
	 * for the conversation. */
	srv_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
	if (srv_socket < 0) {
		perror("Socket failure");
		return -1;
	}
	/* bind + listen is equiv to announce() in plan 9.  Note that the "bind"
	 * command is used, unlike in the plan9 announce. */
	/* Binds our socket to the given addr/port in srv. */
	ret = bind(srv_socket, (struct sockaddr*)&srv, sizeof(struct sockaddr_in));
	if (ret < 0) {
		perror("Bind failure");
		return -1;
	}
	/* marks the socket as a listener/server */
	ret = listen(srv_socket, 1);
	if (ret < 0) {
		perror("Listen failure");
		return -1;
	}
	printf("Listened on port %d\n", ntohs(srv.sin_port));
#endif

	/* at this point, the server has done all the prep necessary to be able to
	 * sleep/block/wait on an incoming connection. */
	#define EP_SET_SZ 10	/* this is actually the ID of the largest FD */
	int epfd = epoll_create(EP_SET_SZ);
	struct epoll_event ep_ev;
	struct epoll_event results[EP_SET_SZ];

	if (epfd < 0) {
		perror("epoll_create");
		exit(-1);
	}
	ep_ev.events = EPOLLIN | EPOLLET;

#ifdef PLAN9NET

	snprintf(buf, sizeof(buf), "%s/listen", adir);
	listen_fd = open(buf, O_PATH);
	if (listen_fd < 0){
		perror("listen fd");
		return -1;
	}
	/* This is a little subtle.  We're putting a tap on the listen file /
	 * listen_fd.  When this fires, we get an event because of that listen_fd.
	 * But we don't actually listen or do anything to that listen_fd.  It's
	 * solely for monitoring.  We open a path, below, and we'll reattempt to do
	 * *that* operation when someone tells us that our listen tap fires. */
	ep_ev.data.fd = listen_fd;
	if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ep_ev)) {
		perror("epoll_ctl_add listen");
		exit(-1);
	}
	has_epolled = FALSE;
	while (1) {
		/* Opens the conversation's listen file.  This blocks til someone
		 * connects.  When they do, a new conversation is created, and that open
		 * returned an FD for the new conv's ctl.  listen() reads that to find
		 * out the conv number (the line) for this new conv.  listen() returns
		 * the ctl for this new conv.
		 *
		 * Non-block is for the act of listening, and applies to lcfd. */
		lcfd = listen9(adir, ldir, O_NONBLOCK);
		if (lcfd >= 0)
			break;
		if (errno != EAGAIN) {
			perror("Listen failure");
			return -1;
		}
		if (epoll_wait(epfd, results, EP_SET_SZ, -1) != 1) {
			perror("epoll_wait");
			exit(-1);
		}
		has_epolled = TRUE;
		assert(results[0].data.fd == listen_fd);
		assert(results[0].events == EPOLLIN);
	}
	printf("Listened and got line %s\n", ldir);
	assert(has_epolled);

	/* No longer need listen_fd.  You should CTL_DEL before closing. */
	if (epoll_ctl(epfd, EPOLL_CTL_DEL, listen_fd, &ep_ev)) {
		perror("epoll_ctl_del");
		exit(-1);
	}
	close(listen_fd);

	/* Writes "accept [NUM]" into the ctlfd, then opens the conv's data file and
	 * returns that fd.  Writing "accept" is a noop for most of our protocols.
	 * */
	dfd = accept9(lcfd, ldir);
	if (dfd < 0) {
		perror("Accept failure");
		return -1;
	}

#else

	ep_ev.data.fd = srv_socket;
	if (epoll_ctl(epfd, EPOLL_CTL_ADD, srv_socket, &ep_ev)) {
		perror("epoll_ctl_add srv_socket");
		exit(-1);
	}
	has_epolled = FALSE;
	while (1) {
		/* returns an FD for a new socket. */
		dfd = accept(srv_socket, (struct sockaddr*)&dest, &socksize);
		if (dfd >= 0)
			break;
		if (errno != EAGAIN) {
			perror("Accept failure");
			return -1;
		}
		if (epoll_wait(epfd, results, EP_SET_SZ, -1) != 1) {
			perror("epoll_wait");
			exit(-1);
		}
		has_epolled = TRUE;
		assert(results[0].data.fd == srv_socket);
		assert(results[0].events == EPOLLIN);
	}
	printf("Accepted and got dfd %d\n", dfd);
	assert(has_epolled);
	if (epoll_ctl(epfd, EPOLL_CTL_DEL, srv_socket, &ep_ev)) {
		perror("epoll_ctl_del");
		while (1);
		exit(-1);
	}

#endif

	/* In lieu of accept4, we set the new socket's nonblock status manually.
	 * Both OSs do this.  */
	ret = fcntl(dfd, F_SETFL, O_NONBLOCK);
	if (ret < 0) {
		perror("setfl dfd");
		exit(-1);
	}
	ep_ev.data.fd = dfd;
	if (epoll_ctl(epfd, EPOLL_CTL_ADD, dfd, &ep_ev)) {
		perror("epoll_ctl_add dvd");
		exit(-1);
	}
	/* echo until EOF */
	has_epolled = FALSE;
	printf("Server read: ");
	while (1) {
		while ((n = read(dfd, buf, sizeof(buf))) > 0) {
			for (int i = 0; i < n; i++)
				printf("%c", buf[i]);
			fflush(stdout);
			/* Should epoll on this direction too. */
			if (write(dfd, buf, n) < 0) {
				perror("writing");
				exit(-1);
			}
		}
		if (n == 0)
			break;
		if (epoll_wait(epfd, results, EP_SET_SZ, -1) != 1) {
			perror("epoll_wait 2");
			exit(-1);
		}
		has_epolled = TRUE;
		assert(results[0].data.fd == dfd);
		/* you might get a HUP, but keep on reading! */
	}
	assert(has_epolled);
	if (epoll_ctl(epfd, EPOLL_CTL_DEL, dfd, &ep_ev)) {
		perror("epoll_ctl_del dfd");
		exit(-1);
	}

#ifdef PLAN9NET
	close(dfd);		/* data fd for the new conv, from listen */
	close(lcfd);	/* ctl fd for the new conv, from listen */
	close(afd);		/* ctl fd for the listening conv */
#else
	close(dfd);		/* new connection socket, from accept */
	close(srv_socket);
#endif
}
Example #3
0
int main(void)
{
	int ret;
	int afd, dfd, lcfd, listen_fd;
	char adir[40], ldir[40];
	int n;
	char buf[256];

	/* We'll use this to see if we actually did a select instead of blocking
	 * calls.  It's not 100%, but with a human on the other end, it should be
	 * fine. */
	bool has_selected = FALSE;

#ifdef PLAN9NET
	printf("Using Plan 9's networking stack\n");
	/* This clones a conversation (opens /net/tcp/clone), then reads the cloned
	 * fd (which is the ctl) to givure out the conv number (the line), then
	 * writes "announce [addr]" into ctl.  This "announce" command often has a
	 * "bind" in it too.  plan9 bind just sets the local addr/port.  TCP
	 * announce also does this.  Returns the ctlfd. */
	afd = announce9("tcp!*!23", adir, O_NONBLOCK);

	if (afd < 0) {
		perror("Announce failure");
		return -1;
	}
	printf("Announced on line %s\n", adir);
#else
	printf("Using the BSD socket shims over Plan 9's networking stack\n");
	int srv_socket;
	struct sockaddr_in dest, srv = {0};

	srv.sin_family = AF_INET;
	srv.sin_addr.s_addr = htonl(INADDR_ANY);
	srv.sin_port = htons(23);
	socklen_t socksize = sizeof(struct sockaddr_in);

	/* Equiv to cloning a converstation in plan 9.  The shim returns the data FD
	 * for the conversation. */
	srv_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
	if (srv_socket < 0) {
		perror("Socket failure");
		return -1;
	}
	/* bind + listen is equiv to announce() in plan 9.  Note that the "bind"
	 * command is used, unlike in the plan9 announce. */
	/* Binds our socket to the given addr/port in srv. */
	ret = bind(srv_socket, (struct sockaddr*)&srv, sizeof(struct sockaddr_in));
	if (ret < 0) {
		perror("Bind failure");
		return -1;
	}
	/* marks the socket as a listener/server */
	ret = listen(srv_socket, 1);
	if (ret < 0) {
		perror("Listen failure");
		return -1;
	}
	printf("Listened on port %d\n", ntohs(srv.sin_port));
#endif

	/* at this point, the server has done all the prep necessary to be able to
	 * sleep/block/wait on an incoming connection. */
	fd_set rfds;

#ifdef PLAN9NET

	snprintf(buf, sizeof(buf), "%s/listen", adir);
	listen_fd = open(buf, O_PATH);
	if (listen_fd < 0) {
		perror("listen fd");
		return -1;
	}
	FD_ZERO(&rfds);
	FD_SET(listen_fd, &rfds);
	has_selected = FALSE;
	while (1) {
		/* Opens the conversation's listen file.  This blocks til someone
		 * connects.  When they do, a new conversation is created, and that open
		 * returned an FD for the new conv's ctl.  listen() reads that to find
		 * out the conv number (the line) for this new conv.  listen() returns
		 * the ctl for this new conv.
		 *
		 * Non-block is for the new connection.  Not the act of listening. */
		lcfd = listen9(adir, ldir, O_NONBLOCK);
		if (lcfd >= 0)
			break;
		if (errno != EAGAIN) {
			perror("Listen failure");
			return -1;
		}
		if (select(listen_fd + 1, &rfds, 0, 0, 0) < 0) {
			perror("select");
			return -1;
		}
		has_selected = TRUE;
		assert(FD_ISSET(listen_fd, &rfds));
	}
	printf("Listened and got line %s\n", ldir);
	assert(has_selected);
	/* No longer need listen_fd. */
	close(listen_fd);
	/* Writes "accept [NUM]" into the ctlfd, then opens the conv's data file and
	 * returns that fd.  Writing "accept" is a noop for most of our protocols.
	 * */
	dfd = accept9(lcfd, ldir);
	if (dfd < 0) {
		perror("Accept failure");
		return -1;
	}

#else

	FD_ZERO(&rfds);
	FD_SET(srv_socket, &rfds);
	has_selected = FALSE;
	while (1) {
		/* returns an FD for a new socket. */
		dfd = accept(srv_socket, (struct sockaddr*)&dest, &socksize);
		if (dfd >= 0)
			break;
		if (errno != EAGAIN) {
			perror("Accept failure");
			return -1;
		}
		if (select(srv_socket + 1, &rfds, 0, 0, 0) < 0) {
			perror("select");
			return -1;
		}
		has_selected = TRUE;
		assert(FD_ISSET(srv_socket, &rfds));
	}
	printf("Accepted and got dfd %d\n", dfd);
	assert(has_selected);
	/* In lieu of accept4, we set the new socket's nonblock status manually */
	ret = fcntl(dfd, F_SETFL, O_NONBLOCK);
	if (ret < 0) {
		perror("setfl dfd");
		exit(-1);
	}

#endif

	FD_SET(dfd, &rfds);
	/* echo until EOF */
	has_selected = FALSE;
	printf("Server read: ");
	while (1) {
		while ((n = read(dfd, buf, sizeof(buf))) > 0) {
			for (int i = 0; i < n; i++)
				printf("%c", buf[i]);
			fflush(stdout);
			/* Should select on this direction too. */
			if (write(dfd, buf, n) < 0) {
				perror("writing");
				exit(-1);
			}
		}
		if (n == 0)
			break;
		if (select(dfd + 1, &rfds, 0, 0, 0) < 0) {
			perror("select 2");
			exit(-1);
		}
		has_selected = TRUE;
		assert(FD_ISSET(dfd, &rfds));
		/* you might get a HUP, but keep on reading! */
	}
	assert(has_selected);

#ifdef PLAN9NET
	close(dfd);		/* data fd for the new conv, from listen */
	close(lcfd);	/* ctl fd for the new conv, from listen */
	close(afd);		/* ctl fd for the listening conv */
#else
	close(dfd);		/* new connection socket, from accept */
	close(srv_socket);
#endif
}
Example #4
0
int main()
{
	int ret;
	int afd, dfd, lcfd;
	char adir[40], ldir[40];
	int n;
	char buf[256];
	char debugbuf[256];

#ifdef PLAN9NET
	/* This clones a conversation (opens /net/tcp/clone), then reads the cloned
	 * fd (which is the ctl) to givure out the conv number (the line), then
	 * writes "announce [addr]" into ctl.  This "announce" command often has a
	 * "bind" in it too.  plan9 bind just sets the local addr/port.  TCP
	 * announce also does this.  Returns the ctlfd. */
	afd = announce9("tcp!*!23", adir, 0);

	if (afd < 0) {
		perror("Announce failure");
		return -1;
	}
	printf("Announced on line %s\n", adir);
#else
	int srv_socket, con_socket;
	struct sockaddr_in dest, srv = {0};
	srv.sin_family = AF_INET;
	srv.sin_addr.s_addr = htonl(INADDR_ANY);
	srv.sin_port = htons(23);
	socklen_t socksize = sizeof(struct sockaddr_in);

	/* Equiv to cloning a converstation in plan 9.  The shim returns the data FD
	 * for the conversation. */
	srv_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (srv_socket < 0) {
		perror("Socket failure");
		return -1;
	}

	/* bind + listen is equiv to announce() in plan 9.  Note that the "bind"
	 * command is used, unlike in the plan9 announce. */
	/* Binds our socket to the given addr/port in srv. */
	ret = bind(srv_socket, (struct sockaddr*)&srv, sizeof(struct sockaddr_in));
	if (ret < 0) {
		perror("Bind failure");
		return -1;
	}
	/* marks the socket as a listener/server */
	ret = listen(srv_socket, 1);
	if (ret < 0) {
		perror("Listen failure");
		return -1;
	}
#endif

	/* at this point, the server has done all the prep necessary to be able to
	 * sleep/block/wait on an incoming connection. */

#ifdef PLAN9NET
	/* Opens the conversation's listen file.  This blocks til someone connects.
	 * When they do, a new conversation is created, and that open returned an FD
	 * for the new conv's ctl.  listen() reads that to find out the conv number
	 * (the line) for this new conv.  listen() returns the ctl for this new
	 * conv. */
	lcfd = listen9(adir, ldir, 0);

	if (lcfd < 0) {
		perror("Listen failure");
		return -1;
	}
	printf("Listened and got line %s\n", ldir);

	/* Writes "accept [NUM]" into the ctlfd, then opens the conv's data file and
	 * returns that fd.  Writing "accept" is a noop for most of our protocols.
	 * */
	dfd = accept9(lcfd, ldir);
	if (dfd < 0) {
		perror("Accept failure");
		return -1;
	}
#else
	/* returns an FD for a new socket. */
	dfd = accept(srv_socket, (struct sockaddr*)&dest, &socksize);
	if (dfd < 0) {
		perror("Accept failure");
		return -1;
	}
#endif

	/* echo until EOF */
	while ((n = read(dfd, buf, sizeof(buf))) > 0) {
		snprintf(debugbuf, n, "%s", buf);
		printf("Server read: %s", debugbuf);
		write(dfd, buf, n);
	}

#ifdef PLAN9NET
	close(dfd);		/* data fd for the new conv, from listen */
	close(lcfd);	/* ctl fd for the new conv, from listen */
	close(afd);		/* ctl fd for the listening conv */
#else
	close(dfd);		/* new connection socket, from accept */
	close(srv_socket);
#endif
}