Added a request library component.
[ashd.git] / src / htparser.c
CommitLineData
f0bbedf7
FT
1/*
2 ashd - A Sane HTTP Daemon
3 Copyright (C) 2008 Fredrik Tolf <fredrik@dolda2000.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include <stdlib.h>
20#include <unistd.h>
21#include <stdio.h>
f4cdf919
FT
22#include <string.h>
23#include <sys/select.h>
24#include <sys/socket.h>
25#include <netinet/in.h>
26#include <errno.h>
f0bbedf7
FT
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <utils.h>
f4cdf919
FT
32#include <mt.h>
33#include <log.h>
34
35#define EV_READ 1
36#define EV_WRITE 2
37
38struct blocker {
39 struct blocker *n, *p;
40 int fd;
41 int ev;
42 struct muth *th;
43};
44
45static struct blocker *blockers;
46
47static int block(int fd, int ev)
48{
49 struct blocker *bl;
50 int rv;
51
52 omalloc(bl);
53 bl->fd = fd;
54 bl->ev = ev;
55 bl->th = current;
56 bl->n = blockers;
57 if(blockers)
58 blockers->p = bl;
59 blockers = bl;
60 rv = yield();
61 if(bl->n)
62 bl->n->p = bl->p;
63 if(bl->p)
64 bl->p->n = bl->n;
65 if(bl == blockers)
66 blockers = bl->n;
67 return(rv);
68}
69
70static int listensock4(int port)
71{
72 struct sockaddr_in name;
73 int fd;
74 int valbuf;
75
76 memset(&name, 0, sizeof(name));
77 name.sin_family = AF_INET;
78 name.sin_port = htons(port);
79 if((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
80 return(-1);
81 valbuf = 1;
82 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &valbuf, sizeof(valbuf));
83 if(bind(fd, (struct sockaddr *)&name, sizeof(name))) {
84 close(fd);
85 return(-1);
86 }
87 if(listen(fd, 16) < 0) {
88 close(fd);
89 return(-1);
90 }
91 return(fd);
92}
93
94static int listensock6(int port)
95{
96 struct sockaddr_in6 name;
97 int fd;
98 int valbuf;
99
100 memset(&name, 0, sizeof(name));
101 name.sin6_family = AF_INET6;
102 name.sin6_port = htons(port);
103 if((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0)
104 return(-1);
105 valbuf = 1;
106 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &valbuf, sizeof(valbuf));
107 if(bind(fd, (struct sockaddr *)&name, sizeof(name))) {
108 close(fd);
109 return(-1);
110 }
111 if(listen(fd, 16) < 0) {
112 close(fd);
113 return(-1);
114 }
115 return(fd);
116}
117
118static void listenloop(struct muth *muth, va_list args)
119{
120 vavar(int, ss);
121 int ns;
122 struct sockaddr_storage name;
123 socklen_t namelen;
124
125 while(1) {
126 namelen = sizeof(name);
127 block(ss, EV_READ);
128 ns = accept(ss, (struct sockaddr *)&name, &namelen);
129 block(ns, EV_WRITE);
130 write(ns, "test\n", 5);
131 close(ns);
132 }
133}
134
135static void ioloop(void)
136{
137 int ret;
138 fd_set rfds, wfds, efds;
139 struct blocker *bl, *nbl;
140 int maxfd;
141 int ev;
142
143 while(1) {
144 FD_ZERO(&rfds);
145 FD_ZERO(&wfds);
146 FD_ZERO(&efds);
147 maxfd = 0;
148 for(bl = blockers; bl; bl = bl->n) {
149 if(bl->ev & EV_READ)
150 FD_SET(bl->fd, &rfds);
151 if(bl->ev & EV_WRITE)
152 FD_SET(bl->fd, &wfds);
153 FD_SET(bl->fd, &efds);
154 if(bl->fd > maxfd)
155 maxfd = bl->fd;
156 }
157 ret = select(maxfd + 1, &rfds, &wfds, &efds, NULL);
158 if(ret < 0) {
159 if(errno != EINTR) {
160 flog(LOG_CRIT, "ioloop: select errored out: %s", strerror(errno));
161 /* To avoid CPU hogging in case it's bad, which it
162 * probably is. */
163 sleep(1);
164 }
165 }
166 for(bl = blockers; bl; bl = nbl) {
167 nbl = bl->n;
168 ev = 0;
169 if(FD_ISSET(bl->fd, &rfds))
170 ev |= EV_READ;
171 if(FD_ISSET(bl->fd, &wfds))
172 ev |= EV_WRITE;
173 if(FD_ISSET(bl->fd, &efds))
174 ev = -1;
175 resume(bl->th, ev);
176 }
177 }
178}
f0bbedf7
FT
179
180int main(int argc, char **argv)
181{
f4cdf919
FT
182 int fd;
183
184 if((fd = listensock6(8080)) < 0) {
185 flog(LOG_ERR, "could not listen on IPv6: %s", strerror(errno));
186 return(1);
187 }
188 mustart(listenloop, fd);
189 if((fd = listensock4(8080)) < 0) {
190 if(errno != EADDRINUSE) {
191 flog(LOG_ERR, "could not listen on IPv4: %s", strerror(errno));
192 return(1);
193 }
194 } else {
195 mustart(listenloop, fd);
196 }
197 ioloop();
198 return(0);
f0bbedf7 199}