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