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