rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@0
|
3 #include <string.h>
|
nuclear@0
|
4 #include <errno.h>
|
nuclear@0
|
5 #include <unistd.h>
|
nuclear@0
|
6 #include <fcntl.h>
|
nuclear@0
|
7 #include <sys/select.h>
|
nuclear@0
|
8 #include <sys/types.h>
|
nuclear@0
|
9 #include <sys/socket.h>
|
nuclear@0
|
10 #include <arpa/inet.h>
|
nuclear@0
|
11
|
nuclear@0
|
12 struct client {
|
nuclear@0
|
13 int s;
|
nuclear@0
|
14 char *rcvbuf;
|
nuclear@0
|
15 int bufsz;
|
nuclear@0
|
16 struct client *next;
|
nuclear@0
|
17 };
|
nuclear@0
|
18
|
nuclear@0
|
19 int start_server(void);
|
nuclear@0
|
20 int accept_conn(int lis);
|
nuclear@0
|
21 int handle_client(struct client *c);
|
nuclear@0
|
22
|
nuclear@0
|
23 static int lis;
|
nuclear@0
|
24 static int port = 8080;
|
nuclear@0
|
25 static struct client *clist;
|
nuclear@0
|
26
|
nuclear@0
|
27 int main(int argc, char **argv)
|
nuclear@0
|
28 {
|
nuclear@0
|
29 if((lis = start_server()) == -1) {
|
nuclear@0
|
30 return 1;
|
nuclear@0
|
31 }
|
nuclear@0
|
32
|
nuclear@0
|
33 for(;;) {
|
nuclear@0
|
34 struct client *c, dummy;
|
nuclear@0
|
35 int maxfd = lis;
|
nuclear@0
|
36 fd_set rdset;
|
nuclear@0
|
37
|
nuclear@0
|
38 FD_ZERO(&rdset);
|
nuclear@0
|
39 FD_SET(lis, &rdset);
|
nuclear@0
|
40
|
nuclear@0
|
41 c = clist;
|
nuclear@0
|
42 while(c) {
|
nuclear@0
|
43 if(c->s > maxfd) {
|
nuclear@0
|
44 maxfd = c->s;
|
nuclear@0
|
45 }
|
nuclear@0
|
46 FD_SET(c->s, &rdset);
|
nuclear@0
|
47 c = c->next;
|
nuclear@0
|
48 }
|
nuclear@0
|
49
|
nuclear@0
|
50 while(select(maxfd + 1, &rdset, 0, 0, 0) == -1 && errno == EINTR);
|
nuclear@0
|
51
|
nuclear@0
|
52 c = clist;
|
nuclear@0
|
53 while(c) {
|
nuclear@0
|
54 if(FD_ISSET(c->s, &rdset)) {
|
nuclear@0
|
55 handle_client(c);
|
nuclear@0
|
56 }
|
nuclear@0
|
57 c = c->next;
|
nuclear@0
|
58 }
|
nuclear@0
|
59
|
nuclear@0
|
60 if(FD_ISSET(lis, &rdset)) {
|
nuclear@0
|
61 accept_conn(lis);
|
nuclear@0
|
62 }
|
nuclear@0
|
63
|
nuclear@0
|
64 dummy.next = clist;
|
nuclear@0
|
65 c = &dummy;
|
nuclear@0
|
66
|
nuclear@0
|
67 while(c->next) {
|
nuclear@0
|
68 struct client *n = c->next;
|
nuclear@0
|
69
|
nuclear@0
|
70 if(n->s == -1) {
|
nuclear@0
|
71 /* marked for removal */
|
nuclear@0
|
72 c->next = n->next;
|
nuclear@0
|
73 free(n);
|
nuclear@0
|
74 } else {
|
nuclear@0
|
75 c = c->next;
|
nuclear@0
|
76 }
|
nuclear@0
|
77 }
|
nuclear@0
|
78 }
|
nuclear@0
|
79 }
|
nuclear@0
|
80
|
nuclear@0
|
81 int start_server(void)
|
nuclear@0
|
82 {
|
nuclear@0
|
83 int s;
|
nuclear@0
|
84 struct sockaddr_in sa;
|
nuclear@0
|
85
|
nuclear@0
|
86 if((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
|
nuclear@0
|
87 perror("failed to create listening socket");
|
nuclear@0
|
88 return -1;
|
nuclear@0
|
89 }
|
nuclear@0
|
90 fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
|
nuclear@0
|
91
|
nuclear@0
|
92 memset(&sa, 0, sizeof sa);
|
nuclear@0
|
93 sa.sin_family = AF_INET;
|
nuclear@0
|
94 sa.sin_addr.s_addr = INADDR_ANY;
|
nuclear@0
|
95 sa.sin_port = htons(port);
|
nuclear@0
|
96
|
nuclear@0
|
97 if(bind(s, (struct sockaddr*)&sa, sizeof sa) == -1) {
|
nuclear@0
|
98 fprintf(stderr, "failed to bind socket to port %d: %s\n", port, strerror(errno));
|
nuclear@0
|
99 return -1;
|
nuclear@0
|
100 }
|
nuclear@0
|
101 listen(s, 16);
|
nuclear@0
|
102
|
nuclear@0
|
103 return s;
|
nuclear@0
|
104 }
|
nuclear@0
|
105
|
nuclear@0
|
106 int accept_conn(int lis)
|
nuclear@0
|
107 {
|
nuclear@0
|
108 int s;
|
nuclear@0
|
109 struct client *c;
|
nuclear@0
|
110 struct sockaddr_in addr;
|
nuclear@0
|
111 socklen_t addr_sz = sizeof addr;
|
nuclear@0
|
112
|
nuclear@0
|
113 if((s = accept(lis, (struct sockaddr*)&addr, &addr_sz)) == -1) {
|
nuclear@0
|
114 perror("failed to accept incoming connection");
|
nuclear@0
|
115 return -1;
|
nuclear@0
|
116 }
|
nuclear@0
|
117 fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
|
nuclear@0
|
118
|
nuclear@0
|
119 if(!(c = malloc(sizeof *c))) {
|
nuclear@0
|
120 perror("failed to allocate memory while accepting connection");
|
nuclear@0
|
121 return -1;
|
nuclear@0
|
122 }
|
nuclear@0
|
123 c->s = s;
|
nuclear@0
|
124 c->rcvbuf = 0;
|
nuclear@0
|
125 c->bufsz = 0;
|
nuclear@0
|
126 c->next = clist;
|
nuclear@0
|
127 clist = c;
|
nuclear@0
|
128 return 0;
|
nuclear@0
|
129 }
|
nuclear@0
|
130
|
nuclear@0
|
131 int handle_client(struct client *c)
|
nuclear@0
|
132 {
|
nuclear@0
|
133 static char buf[2048];
|
nuclear@0
|
134 int rdsz;
|
nuclear@0
|
135
|
nuclear@0
|
136 while((rdsz = recv(c->s, buf, sizeof buf, 0)) > 0) {
|
nuclear@0
|
137 if(c->rcvbuf) {
|
nuclear@0
|
138 int newsz = c->bufsz + rdsz;
|
nuclear@0
|
139 char *newbuf = realloc(buf, newsz);
|
nuclear@0
|
140 if(!newbuf) {
|
nuclear@0
|
141 fprintf(stderr, "failed to allocate %d byte buffer\n", newsz);
|
nuclear@0
|
142 /* TODO http error */
|
nuclear@0
|
143 goto drop;
|
nuclear@0
|
144 }
|
nuclear@0
|
145
|
nuclear@0
|
146 memcpy(newbuf + c->bufsz, buf, rdsz);
|
nuclear@0
|
147
|
nuclear@0
|
148 c->rcvbuf = newbuf;
|
nuclear@0
|
149 c->bufsz = newsz;
|
nuclear@0
|
150 }
|
nuclear@0
|
151 }
|
nuclear@0
|
152
|
nuclear@0
|
153 /* TODO: parse header, drop on invalid, determine if the request
|
nuclear@0
|
154 * is complete and process
|
nuclear@0
|
155 */
|
nuclear@0
|
156
|
nuclear@0
|
157 if(rdsz == -1 && errno != EAGAIN) {
|
nuclear@0
|
158 drop:
|
nuclear@0
|
159 close(c->s);
|
nuclear@0
|
160 c->s = -1;
|
nuclear@0
|
161 free(c->rcvbuf);
|
nuclear@0
|
162 }
|
nuclear@0
|
163 return 0;
|
nuclear@0
|
164 }
|