Changes user includes to <library/header.h> (XCC)
[akaros.git] / tests / listener.c
1 /* Echo server, runs on port 23.  Main purpose is low-level network debugging
2  * and to show how networking commands in plan 9 correspond to BSD sockets
3  * (which are now a part of our sysdeps in glibc). 
4  *
5  * if you want to build the BSD sockets version, you need to change the #define
6  * and link with just glibc instead of -liplib.  easiest way is to build
7  * manually:
8  *
9  * $ x86_64-ros-gcc   -O2 -std=gnu99 -fno-stack-protector -fgnu89-inline -g 
10  * -o obj/tests/listener tests/listener.c -lpthread -lbenchutil -lm
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 #define PLAN9NET 1
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <parlib/parlib.h>
20 #include <unistd.h>
21 #include <parlib/event.h>
22 #include <benchutil/measure.h>
23 #include <parlib/uthread.h>
24 #include <parlib/timing.h>
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29
30 #ifdef PLAN9NET
31
32 #include <iplib/iplib.h>
33
34 #else
35
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40
41 #endif
42
43 int main()
44 {
45         int ret;
46         int afd, dfd, lcfd;
47         char adir[40], ldir[40];
48         int n;
49         char buf[256];
50         char debugbuf[256];
51
52 #ifdef PLAN9NET
53         /* This clones a conversation (opens /net/tcp/clone), then reads the cloned
54          * fd (which is the ctl) to givure out the conv number (the line), then
55          * writes "announce [addr]" into ctl.  This "announce" command often has a
56          * "bind" in it too.  plan9 bind just sets the local addr/port.  TCP
57          * announce also does this.  Returns the ctlfd. */
58         afd = announce("tcp!*!23", adir);
59
60         if (afd < 0) {
61                 perror("Announce failure");
62                 return -1;
63         }
64         printf("Announced on line %s\n", adir);
65 #else
66         int srv_socket, con_socket;
67         struct sockaddr_in dest, srv = {0};
68         srv.sin_family = AF_INET;
69         srv.sin_addr.s_addr = htonl(INADDR_ANY);
70         srv.sin_port = htons(23);
71         socklen_t socksize = sizeof(struct sockaddr_in);
72
73         /* Equiv to cloning a converstation in plan 9.  The shim returns the data FD
74          * for the conversation. */
75         srv_socket = socket(AF_INET, SOCK_STREAM, 0);
76         if (srv_socket < 0) {
77                 perror("Socket failure");
78                 return -1;
79         }
80
81         /* bind + listen is equiv to announce() in plan 9.  Note that the "bind"
82          * command is used, unlike in the plan9 announce. */
83         /* Binds our socket to the given addr/port in srv. */
84         ret = bind(srv_socket, (struct sockaddr*)&srv, sizeof(struct sockaddr_in));
85         if (ret < 0) {
86                 perror("Bind failure");
87                 return -1;
88         }
89         /* marks the socket as a listener/server */
90         ret = listen(srv_socket, 1);
91         if (ret < 0) {
92                 perror("Listen failure");
93                 return -1;
94         }
95 #endif
96
97         /* at this point, the server has done all the prep necessary to be able to
98          * sleep/block/wait on an incoming connection. */
99
100 #ifdef PLAN9NET
101         /* Opens the conversation's listen file.  This blocks til someone connects.
102          * When they do, a new conversation is created, and that open returned an FD
103          * for the new conv's ctl.  listen() reads that to find out the conv number
104          * (the line) for this new conv.  listen() returns the ctl for this new
105          * conv. */
106         lcfd = listen(adir, ldir);
107
108         if (lcfd < 0) {
109                 perror("Listen failure");
110                 return -1;
111         }
112         printf("Listened and got line %s\n", ldir);
113
114         /* Writes "accept [NUM]" into the ctlfd, then opens the conv's data file and
115          * returns that fd.  Writing "accept" is a noop for most of our protocols.
116          * */
117         dfd = accept(lcfd, ldir);
118         if (dfd < 0) {
119                 perror("Accept failure");
120                 return -1;
121         }
122 #else
123         /* returns an FD for a new socket. */
124         dfd = accept(srv_socket, (struct sockaddr*)&dest, &socksize);
125         if (dfd < 0) {
126                 perror("Accept failure");
127                 return -1;
128         }
129 #endif
130
131         /* echo until EOF */
132         while ((n = read(dfd, buf, sizeof(buf))) > 0) {
133                 snprintf(debugbuf, n, "%s", buf);
134                 printf("Server read: %s", debugbuf);
135                 write(dfd, buf, n);
136         }
137
138 #ifdef PLAN9NET
139         close(dfd);             /* data fd for the new conv, from listen */
140         close(lcfd);    /* ctl fd for the new conv, from listen */
141         close(afd);             /* ctl fd for the listening conv */
142 #else
143         close(dfd);             /* new connection socket, from accept */
144         close(srv_socket);
145 #endif
146 }