vmm: remove the leading '%' from the printc vmcall
[akaros.git] / tests / listener.c
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
44 int 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 }