| /* Copyright (c) 2014 The Regents of the University of California | 
 |  * Barret Rhoden <brho@cs.berkeley.edu> | 
 |  * See LICENSE for details. | 
 |  * | 
 |  * Echo server, runs on port 23.  Main purpose is low-level network debugging | 
 |  * and to show how networking commands in plan 9 correspond to BSD sockets | 
 |  * (which are now a part of our sysdeps in glibc).  | 
 |  * | 
 |  * If you want to build the BSD sockets version, you need to comment out the | 
 |  * #define for PLAN9NET. | 
 |  * | 
 |  * based off http://www2.informatik.hu-berlin.de/~apolze/LV/plan9.docs/net.V | 
 |  * and http://en.wikibooks.org/wiki/C_Programming/Networking_in_UNIX */ | 
 |  | 
 | /* Comment this out for BSD sockets */ | 
 | #define PLAN9NET | 
 |  | 
 | #include <stdlib.h> | 
 | #include <stdio.h> | 
 | #include <parlib/parlib.h> | 
 | #include <unistd.h> | 
 | #include <parlib/event.h> | 
 | #include <benchutil/measure.h> | 
 | #include <parlib/uthread.h> | 
 | #include <parlib/timing.h> | 
 |  | 
 | #include <sys/types.h> | 
 | #include <sys/stat.h> | 
 | #include <fcntl.h> | 
 |  | 
 | #ifdef PLAN9NET | 
 |  | 
 | #include <iplib/iplib.h> | 
 |  | 
 | #else | 
 |  | 
 | #include <sys/types.h> | 
 | #include <sys/socket.h> | 
 | #include <netinet/in.h> | 
 | #include <arpa/inet.h> | 
 |  | 
 | #endif | 
 |  | 
 | int main() | 
 | { | 
 | 	int ret; | 
 | 	int afd, dfd, lcfd; | 
 | 	char adir[40], ldir[40]; | 
 | 	int n; | 
 | 	char buf[256]; | 
 |  | 
 | #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, 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 */ | 
 | 	printf("Server read: "); | 
 | 	while ((n = read(dfd, buf, sizeof(buf))) > 0) { | 
 | 		for (int i = 0; i < n; i++) | 
 | 			printf("%c", buf[i]); | 
 | 		fflush(stdout); | 
 | 		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 | 
 | } |