| /* 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 |
| } |