akaros/tests/listener.c
<<
>>
Prefs
   1/* Copyright (c) 2014 The Regents of the University of California
   2 * Barret Rhoden <brho@cs.berkeley.edu>
   3 * See LICENSE for details.
   4 *
   5 * Echo server, runs on port 23.  Main purpose is low-level network debugging
   6 * and to show how networking commands in plan 9 correspond to BSD sockets
   7 * (which are now a part of our sysdeps in glibc). 
   8 *
   9 * If you want to build the BSD sockets version, you need to comment out the
  10 * #define for PLAN9NET.
  11 *
  12 * based off http://www2.informatik.hu-berlin.de/~apolze/LV/plan9.docs/net.V
  13 * and http://en.wikibooks.org/wiki/C_Programming/Networking_in_UNIX */
  14
  15/* Comment this out for BSD sockets */
  16#define PLAN9NET
  17
  18#include <stdlib.h>
  19#include <stdio.h>
  20#include <parlib/parlib.h>
  21#include <unistd.h>
  22#include <parlib/event.h>
  23#include <benchutil/measure.h>
  24#include <parlib/uthread.h>
  25#include <parlib/timing.h>
  26
  27#include <sys/types.h>
  28#include <sys/stat.h>
  29#include <fcntl.h>
  30
  31#ifdef PLAN9NET
  32
  33#include <iplib/iplib.h>
  34
  35#else
  36
  37#include <sys/types.h>
  38#include <sys/socket.h>
  39#include <netinet/in.h>
  40#include <arpa/inet.h>
  41
  42#endif
  43
  44int main()
  45{
  46        int ret;
  47        int afd, dfd, lcfd;
  48        char adir[40], ldir[40];
  49        int n;
  50        char buf[256];
  51
  52#ifdef PLAN9NET
  53        printf("Using Plan 9's networking stack\n");
  54        /* This clones a conversation (opens /net/tcp/clone), then reads the
  55         * cloned fd (which is the ctl) to givure out the conv number (the
  56         * line), then writes "announce [addr]" into ctl.  This "announce"
  57         * command often has a "bind" in it too.  plan9 bind just sets the local
  58         * addr/port.  TCP announce also does this.  Returns the ctlfd. */
  59        afd = announce9("tcp!*!23", adir, 0);
  60
  61        if (afd < 0) {
  62                perror("Announce failure");
  63                return -1;
  64        }
  65        printf("Announced on line %s\n", adir);
  66#else
  67        printf("Using the BSD socket shims over Plan 9's networking stack\n");
  68
  69        int srv_socket, con_socket;
  70        struct sockaddr_in dest, srv = {0};
  71
  72        srv.sin_family = AF_INET;
  73        srv.sin_addr.s_addr = htonl(INADDR_ANY);
  74        srv.sin_port = htons(23);
  75        socklen_t socksize = sizeof(struct sockaddr_in);
  76
  77        /* Equiv to cloning a converstation in plan 9.  The shim returns the
  78         * data FD for the conversation. */
  79        srv_socket = socket(AF_INET, SOCK_STREAM, 0);
  80        if (srv_socket < 0) {
  81                perror("Socket failure");
  82                return -1;
  83        }
  84
  85        /* bind + listen is equiv to announce() in plan 9.  Note that the "bind"
  86         * command is used, unlike in the plan9 announce. */
  87        /* Binds our socket to the given addr/port in srv. */
  88        ret = bind(srv_socket, (struct sockaddr*)&srv,
  89                   sizeof(struct sockaddr_in));
  90        if (ret < 0) {
  91                perror("Bind failure");
  92                return -1;
  93        }
  94        /* marks the socket as a listener/server */
  95        ret = listen(srv_socket, 1);
  96        if (ret < 0) {
  97                perror("Listen failure");
  98                return -1;
  99        }
 100#endif
 101
 102        /* at this point, the server has done all the prep necessary to be able
 103         * to sleep/block/wait on an incoming connection. */
 104
 105#ifdef PLAN9NET
 106        /* Opens the conversation's listen file.  This blocks til someone
 107         * connects.  When they do, a new conversation is created, and that open
 108         * returned an FD for the new conv's ctl.  listen() reads that to find
 109         * out the conv number (the line) for this new conv.  listen() returns
 110         * the ctl for this new conv. */
 111        lcfd = listen9(adir, ldir, 0);
 112
 113        if (lcfd < 0) {
 114                perror("Listen failure");
 115                return -1;
 116        }
 117        printf("Listened and got line %s\n", ldir);
 118
 119        /* Writes "accept [NUM]" into the ctlfd, then opens the conv's data file
 120         * and returns that fd.  Writing "accept" is a noop for most of our
 121         * protocols.  */
 122        dfd = accept9(lcfd, ldir);
 123        if (dfd < 0) {
 124                perror("Accept failure");
 125                return -1;
 126        }
 127#else
 128        /* returns an FD for a new socket. */
 129        dfd = accept(srv_socket, (struct sockaddr*)&dest, &socksize);
 130        if (dfd < 0) {
 131                perror("Accept failure");
 132                return -1;
 133        }
 134#endif
 135
 136        /* echo until EOF */
 137        printf("Server read: ");
 138        while ((n = read(dfd, buf, sizeof(buf))) > 0) {
 139                for (int i = 0; i < n; i++)
 140                        printf("%c", buf[i]);
 141                fflush(stdout);
 142                write(dfd, buf, n);
 143        }
 144
 145#ifdef PLAN9NET
 146        close(dfd);             /* data fd for the new conv, from listen */
 147        close(lcfd);    /* ctl fd for the new conv, from listen */
 148        close(afd);             /* ctl fd for the listening conv */
 149#else
 150        close(dfd);             /* new connection socket, from accept */
 151        close(srv_socket);
 152#endif
 153}
 154