accf_http.c revision 1.1.2.2 1 1.1.2.2 wrstuden /*-
2 1.1.2.2 wrstuden * Copyright (c) 2000 Paycounter, Inc.
3 1.1.2.2 wrstuden * Author: Alfred Perlstein <alfred (at) paycounter.com>, <alfred (at) FreeBSD.org>
4 1.1.2.2 wrstuden * All rights reserved.
5 1.1.2.2 wrstuden *
6 1.1.2.2 wrstuden * Redistribution and use in source and binary forms, with or without
7 1.1.2.2 wrstuden * modification, are permitted provided that the following conditions
8 1.1.2.2 wrstuden * are met:
9 1.1.2.2 wrstuden * 1. Redistributions of source code must retain the above copyright
10 1.1.2.2 wrstuden * notice, this list of conditions and the following disclaimer.
11 1.1.2.2 wrstuden * 2. Redistributions in binary form must reproduce the above copyright
12 1.1.2.2 wrstuden * notice, this list of conditions and the following disclaimer in the
13 1.1.2.2 wrstuden * documentation and/or other materials provided with the distribution.
14 1.1.2.2 wrstuden *
15 1.1.2.2 wrstuden * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 1.1.2.2 wrstuden * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 1.1.2.2 wrstuden * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 1.1.2.2 wrstuden * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 1.1.2.2 wrstuden * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 1.1.2.2 wrstuden * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 1.1.2.2 wrstuden * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 1.1.2.2 wrstuden * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 1.1.2.2 wrstuden * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 1.1.2.2 wrstuden * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 1.1.2.2 wrstuden * SUCH DAMAGE.
26 1.1.2.2 wrstuden */
27 1.1.2.2 wrstuden
28 1.1.2.2 wrstuden #include <sys/cdefs.h>
29 1.1.2.2 wrstuden __KERNEL_RCSID(0, "$NetBSD: accf_http.c,v 1.1.2.2 2008/09/18 04:37:00 wrstuden Exp $");
30 1.1.2.2 wrstuden
31 1.1.2.2 wrstuden #define ACCEPT_FILTER_MOD
32 1.1.2.2 wrstuden
33 1.1.2.2 wrstuden #include <sys/param.h>
34 1.1.2.2 wrstuden #include <sys/kernel.h>
35 1.1.2.2 wrstuden #include <sys/mbuf.h>
36 1.1.2.2 wrstuden #include <sys/lkm.h>
37 1.1.2.2 wrstuden #include <sys/signalvar.h>
38 1.1.2.2 wrstuden #include <sys/sysctl.h>
39 1.1.2.2 wrstuden #include <sys/socket.h>
40 1.1.2.2 wrstuden #include <sys/socketvar.h>
41 1.1.2.2 wrstuden #include <netinet/accept_filter.h>
42 1.1.2.2 wrstuden
43 1.1.2.2 wrstuden /* check for GET/HEAD */
44 1.1.2.2 wrstuden static void sohashttpget(struct socket *so, void *arg, int waitflag);
45 1.1.2.2 wrstuden /* check for HTTP/1.0 or HTTP/1.1 */
46 1.1.2.2 wrstuden static void soparsehttpvers(struct socket *so, void *arg, int waitflag);
47 1.1.2.2 wrstuden /* check for end of HTTP/1.x request */
48 1.1.2.2 wrstuden static void soishttpconnected(struct socket *so, void *arg, int waitflag);
49 1.1.2.2 wrstuden /* strcmp on an mbuf chain */
50 1.1.2.2 wrstuden static int mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, const char *cmp);
51 1.1.2.2 wrstuden /* strncmp on an mbuf chain */
52 1.1.2.2 wrstuden static int mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset,
53 1.1.2.2 wrstuden int len, const char *cmp);
54 1.1.2.2 wrstuden /* socketbuffer is full */
55 1.1.2.2 wrstuden static int sbfull(struct sockbuf *sb);
56 1.1.2.2 wrstuden
57 1.1.2.2 wrstuden static struct accept_filter accf_http_filter = {
58 1.1.2.2 wrstuden "httpready",
59 1.1.2.2 wrstuden sohashttpget,
60 1.1.2.2 wrstuden NULL,
61 1.1.2.2 wrstuden NULL,
62 1.1.2.2 wrstuden {NULL,}
63 1.1.2.2 wrstuden };
64 1.1.2.2 wrstuden
65 1.1.2.2 wrstuden /*
66 1.1.2.2 wrstuden * Names of HTTP Accept filter sysctl objects
67 1.1.2.2 wrstuden */
68 1.1.2.2 wrstuden
69 1.1.2.2 wrstuden #define ACCFCTL_PARSEVER 1 /* Parse HTTP version */
70 1.1.2.2 wrstuden
71 1.1.2.2 wrstuden static int parse_http_version = 1;
72 1.1.2.2 wrstuden
73 1.1.2.2 wrstuden SYSCTL_SETUP(sysctl_net_inet_accf__http_setup, "sysctl net.inet.accf.http subtree setup")
74 1.1.2.2 wrstuden {
75 1.1.2.2 wrstuden sysctl_createv(clog, 0, NULL, NULL,
76 1.1.2.2 wrstuden CTLFLAG_PERMANENT,
77 1.1.2.2 wrstuden CTLTYPE_NODE, "net", NULL,
78 1.1.2.2 wrstuden NULL, 0, NULL, 0,
79 1.1.2.2 wrstuden CTL_NET, CTL_EOL);
80 1.1.2.2 wrstuden sysctl_createv(clog, 0, NULL, NULL,
81 1.1.2.2 wrstuden CTLFLAG_PERMANENT,
82 1.1.2.2 wrstuden CTLTYPE_NODE, "inet", NULL,
83 1.1.2.2 wrstuden NULL, 0, NULL, 0,
84 1.1.2.2 wrstuden CTL_NET, PF_INET, CTL_EOL);
85 1.1.2.2 wrstuden sysctl_createv(clog, 0, NULL, NULL,
86 1.1.2.2 wrstuden CTLFLAG_PERMANENT,
87 1.1.2.2 wrstuden CTLTYPE_NODE, "accf", NULL,
88 1.1.2.2 wrstuden NULL, 0, NULL, 0,
89 1.1.2.2 wrstuden CTL_NET, PF_INET, SO_ACCEPTFILTER, CTL_EOL);
90 1.1.2.2 wrstuden sysctl_createv(clog, 0, NULL, NULL,
91 1.1.2.2 wrstuden CTLFLAG_PERMANENT,
92 1.1.2.2 wrstuden CTLTYPE_NODE, "http",
93 1.1.2.2 wrstuden SYSCTL_DESCR("HTTP accept filter"),
94 1.1.2.2 wrstuden NULL, 0, NULL, 0,
95 1.1.2.2 wrstuden CTL_NET, PF_INET, SO_ACCEPTFILTER, ACCF_HTTP, CTL_EOL);
96 1.1.2.2 wrstuden sysctl_createv(clog, 0, NULL, NULL,
97 1.1.2.2 wrstuden CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
98 1.1.2.2 wrstuden CTLTYPE_INT, "parsehttpversion",
99 1.1.2.2 wrstuden SYSCTL_DESCR("Parse http version so that non "
100 1.1.2.2 wrstuden "1.x requests work"),
101 1.1.2.2 wrstuden NULL, 0, &parse_http_version, 0,
102 1.1.2.2 wrstuden CTL_NET, PF_INET, SO_ACCEPTFILTER, ACCF_HTTP,
103 1.1.2.2 wrstuden ACCFCTL_PARSEVER, CTL_EOL);
104 1.1.2.2 wrstuden }
105 1.1.2.2 wrstuden
106 1.1.2.2 wrstuden void accf_httpattach(int);
107 1.1.2.2 wrstuden void accf_httpattach(int num)
108 1.1.2.2 wrstuden {
109 1.1.2.2 wrstuden accept_filt_generic_mod_event(NULL, LKM_E_LOAD, &accf_http_filter);
110 1.1.2.2 wrstuden }
111 1.1.2.2 wrstuden
112 1.1.2.2 wrstuden /*
113 1.1.2.2 wrstuden * This code is to make HTTP ready accept filer as LKM.
114 1.1.2.2 wrstuden * To compile as LKM we need to move this set of code into
115 1.1.2.2 wrstuden * another file and include this file for compilation when
116 1.1.2.2 wrstuden * making LKM
117 1.1.2.2 wrstuden */
118 1.1.2.2 wrstuden
119 1.1.2.2 wrstuden #ifdef _LKM
120 1.1.2.2 wrstuden static int accf_http_handle(struct lkm_table * lkmtp, int cmd);
121 1.1.2.2 wrstuden int accf_http_lkmentry(struct lkm_table * lkmtp, int cmd, int ver);
122 1.1.2.2 wrstuden
123 1.1.2.2 wrstuden MOD_MISC("accf_http");
124 1.1.2.2 wrstuden
125 1.1.2.2 wrstuden static int accf_http_handle(struct lkm_table * lkmtp, int cmd)
126 1.1.2.2 wrstuden {
127 1.1.2.2 wrstuden
128 1.1.2.2 wrstuden return accept_filt_generic_mod_event(lkmtp, cmd, &accf_http_filter);
129 1.1.2.2 wrstuden }
130 1.1.2.2 wrstuden
131 1.1.2.2 wrstuden /*
132 1.1.2.2 wrstuden * the module entry point.
133 1.1.2.2 wrstuden */
134 1.1.2.2 wrstuden int
135 1.1.2.2 wrstuden accf_http_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
136 1.1.2.2 wrstuden {
137 1.1.2.2 wrstuden DISPATCH(lkmtp, cmd, ver, accf_http_handle, accf_http_handle,
138 1.1.2.2 wrstuden accf_http_handle)
139 1.1.2.2 wrstuden }
140 1.1.2.2 wrstuden #endif
141 1.1.2.2 wrstuden
142 1.1.2.2 wrstuden #ifdef ACCF_HTTP_DEBUG
143 1.1.2.2 wrstuden #define DPRINT(fmt, args...) \
144 1.1.2.2 wrstuden do { \
145 1.1.2.2 wrstuden printf("%s:%d: " fmt "\n", __func__, __LINE__, ##args); \
146 1.1.2.2 wrstuden } while (0)
147 1.1.2.2 wrstuden #else
148 1.1.2.2 wrstuden #define DPRINT(fmt, args...)
149 1.1.2.2 wrstuden #endif
150 1.1.2.2 wrstuden
151 1.1.2.2 wrstuden static int
152 1.1.2.2 wrstuden sbfull(struct sockbuf *sb)
153 1.1.2.2 wrstuden {
154 1.1.2.2 wrstuden
155 1.1.2.2 wrstuden DPRINT("sbfull, cc(%ld) >= hiwat(%ld): %d, "
156 1.1.2.2 wrstuden "mbcnt(%ld) >= mbmax(%ld): %d",
157 1.1.2.2 wrstuden sb->sb_cc, sb->sb_hiwat, sb->sb_cc >= sb->sb_hiwat,
158 1.1.2.2 wrstuden sb->sb_mbcnt, sb->sb_mbmax, sb->sb_mbcnt >= sb->sb_mbmax);
159 1.1.2.2 wrstuden return (sb->sb_cc >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax);
160 1.1.2.2 wrstuden }
161 1.1.2.2 wrstuden
162 1.1.2.2 wrstuden /*
163 1.1.2.2 wrstuden * start at mbuf m, (must provide npkt if exists)
164 1.1.2.2 wrstuden * starting at offset in m compare characters in mbuf chain for 'cmp'
165 1.1.2.2 wrstuden */
166 1.1.2.2 wrstuden static int
167 1.1.2.2 wrstuden mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, const char *cmp)
168 1.1.2.2 wrstuden {
169 1.1.2.2 wrstuden struct mbuf *n;
170 1.1.2.2 wrstuden
171 1.1.2.2 wrstuden for (; m != NULL; m = n) {
172 1.1.2.2 wrstuden n = npkt;
173 1.1.2.2 wrstuden if (npkt)
174 1.1.2.2 wrstuden npkt = npkt->m_nextpkt;
175 1.1.2.2 wrstuden for (; m; m = m->m_next) {
176 1.1.2.2 wrstuden for (; offset < m->m_len; offset++, cmp++) {
177 1.1.2.2 wrstuden if (*cmp == '\0')
178 1.1.2.2 wrstuden return (1);
179 1.1.2.2 wrstuden else if (*cmp != *(mtod(m, char *) + offset))
180 1.1.2.2 wrstuden return (0);
181 1.1.2.2 wrstuden }
182 1.1.2.2 wrstuden if (*cmp == '\0')
183 1.1.2.2 wrstuden return (1);
184 1.1.2.2 wrstuden offset = 0;
185 1.1.2.2 wrstuden }
186 1.1.2.2 wrstuden }
187 1.1.2.2 wrstuden return (0);
188 1.1.2.2 wrstuden }
189 1.1.2.2 wrstuden
190 1.1.2.2 wrstuden /*
191 1.1.2.2 wrstuden * start at mbuf m, (must provide npkt if exists)
192 1.1.2.2 wrstuden * starting at offset in m compare characters in mbuf chain for 'cmp'
193 1.1.2.2 wrstuden * stop at 'max' characters
194 1.1.2.2 wrstuden */
195 1.1.2.2 wrstuden static int
196 1.1.2.2 wrstuden mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset, int len, const char *cmp)
197 1.1.2.2 wrstuden {
198 1.1.2.2 wrstuden struct mbuf *n;
199 1.1.2.2 wrstuden
200 1.1.2.2 wrstuden for (; m != NULL; m = n) {
201 1.1.2.2 wrstuden n = npkt;
202 1.1.2.2 wrstuden if (npkt)
203 1.1.2.2 wrstuden npkt = npkt->m_nextpkt;
204 1.1.2.2 wrstuden for (; m; m = m->m_next) {
205 1.1.2.2 wrstuden for (; offset < m->m_len; offset++, cmp++, len--) {
206 1.1.2.2 wrstuden if (len == 0 || *cmp == '\0')
207 1.1.2.2 wrstuden return (1);
208 1.1.2.2 wrstuden else if (*cmp != *(mtod(m, char *) + offset))
209 1.1.2.2 wrstuden return (0);
210 1.1.2.2 wrstuden }
211 1.1.2.2 wrstuden if (len == 0 || *cmp == '\0')
212 1.1.2.2 wrstuden return (1);
213 1.1.2.2 wrstuden offset = 0;
214 1.1.2.2 wrstuden }
215 1.1.2.2 wrstuden }
216 1.1.2.2 wrstuden return (0);
217 1.1.2.2 wrstuden }
218 1.1.2.2 wrstuden
219 1.1.2.2 wrstuden #define STRSETUP(sptr, slen, str) \
220 1.1.2.2 wrstuden do { \
221 1.1.2.2 wrstuden sptr = str; \
222 1.1.2.2 wrstuden slen = sizeof(str) - 1; \
223 1.1.2.2 wrstuden } while(0)
224 1.1.2.2 wrstuden
225 1.1.2.2 wrstuden static void
226 1.1.2.2 wrstuden sohashttpget(struct socket *so, void *arg, int waitflag)
227 1.1.2.2 wrstuden {
228 1.1.2.2 wrstuden
229 1.1.2.2 wrstuden if ((so->so_state & SS_CANTRCVMORE) == 0 && !sbfull(&so->so_rcv)) {
230 1.1.2.2 wrstuden struct mbuf *m;
231 1.1.2.2 wrstuden const char *cmp;
232 1.1.2.2 wrstuden int cmplen, cc;
233 1.1.2.2 wrstuden
234 1.1.2.2 wrstuden m = so->so_rcv.sb_mb;
235 1.1.2.2 wrstuden cc = so->so_rcv.sb_cc - 1;
236 1.1.2.2 wrstuden if (cc < 1)
237 1.1.2.2 wrstuden return;
238 1.1.2.2 wrstuden switch (*mtod(m, char *)) {
239 1.1.2.2 wrstuden case 'G':
240 1.1.2.2 wrstuden STRSETUP(cmp, cmplen, "ET ");
241 1.1.2.2 wrstuden break;
242 1.1.2.2 wrstuden case 'H':
243 1.1.2.2 wrstuden STRSETUP(cmp, cmplen, "EAD ");
244 1.1.2.2 wrstuden break;
245 1.1.2.2 wrstuden default:
246 1.1.2.2 wrstuden goto fallout;
247 1.1.2.2 wrstuden }
248 1.1.2.2 wrstuden if (cc < cmplen) {
249 1.1.2.2 wrstuden if (mbufstrncmp(m, m->m_nextpkt, 1, cc, cmp) == 1) {
250 1.1.2.2 wrstuden DPRINT("short cc (%d) but mbufstrncmp ok", cc);
251 1.1.2.2 wrstuden return;
252 1.1.2.2 wrstuden } else {
253 1.1.2.2 wrstuden DPRINT("short cc (%d) mbufstrncmp failed", cc);
254 1.1.2.2 wrstuden goto fallout;
255 1.1.2.2 wrstuden }
256 1.1.2.2 wrstuden }
257 1.1.2.2 wrstuden if (mbufstrcmp(m, m->m_nextpkt, 1, cmp) == 1) {
258 1.1.2.2 wrstuden DPRINT("mbufstrcmp ok");
259 1.1.2.2 wrstuden if (parse_http_version == 0)
260 1.1.2.2 wrstuden soishttpconnected(so, arg, waitflag);
261 1.1.2.2 wrstuden else
262 1.1.2.2 wrstuden soparsehttpvers(so, arg, waitflag);
263 1.1.2.2 wrstuden return;
264 1.1.2.2 wrstuden }
265 1.1.2.2 wrstuden DPRINT("mbufstrcmp bad");
266 1.1.2.2 wrstuden }
267 1.1.2.2 wrstuden
268 1.1.2.2 wrstuden fallout:
269 1.1.2.2 wrstuden DPRINT("fallout");
270 1.1.2.2 wrstuden so->so_upcall = NULL;
271 1.1.2.2 wrstuden so->so_rcv.sb_flags &= ~SB_UPCALL;
272 1.1.2.2 wrstuden soisconnected(so);
273 1.1.2.2 wrstuden return;
274 1.1.2.2 wrstuden }
275 1.1.2.2 wrstuden
276 1.1.2.2 wrstuden static void
277 1.1.2.2 wrstuden soparsehttpvers(struct socket *so, void *arg, int waitflag)
278 1.1.2.2 wrstuden {
279 1.1.2.2 wrstuden struct mbuf *m, *n;
280 1.1.2.2 wrstuden int i, cc, spaces, inspaces;
281 1.1.2.2 wrstuden
282 1.1.2.2 wrstuden if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
283 1.1.2.2 wrstuden goto fallout;
284 1.1.2.2 wrstuden
285 1.1.2.2 wrstuden m = so->so_rcv.sb_mb;
286 1.1.2.2 wrstuden cc = so->so_rcv.sb_cc;
287 1.1.2.2 wrstuden inspaces = spaces = 0;
288 1.1.2.2 wrstuden for (m = so->so_rcv.sb_mb; m; m = n) {
289 1.1.2.2 wrstuden n = m->m_nextpkt;
290 1.1.2.2 wrstuden for (; m; m = m->m_next) {
291 1.1.2.2 wrstuden for (i = 0; i < m->m_len; i++, cc--) {
292 1.1.2.2 wrstuden switch (*(mtod(m, char *) + i)) {
293 1.1.2.2 wrstuden case ' ':
294 1.1.2.2 wrstuden /* tabs? '\t' */
295 1.1.2.2 wrstuden if (!inspaces) {
296 1.1.2.2 wrstuden spaces++;
297 1.1.2.2 wrstuden inspaces = 1;
298 1.1.2.2 wrstuden }
299 1.1.2.2 wrstuden break;
300 1.1.2.2 wrstuden case '\r':
301 1.1.2.2 wrstuden case '\n':
302 1.1.2.2 wrstuden DPRINT("newline");
303 1.1.2.2 wrstuden goto fallout;
304 1.1.2.2 wrstuden default:
305 1.1.2.2 wrstuden if (spaces != 2) {
306 1.1.2.2 wrstuden inspaces = 0;
307 1.1.2.2 wrstuden break;
308 1.1.2.2 wrstuden }
309 1.1.2.2 wrstuden
310 1.1.2.2 wrstuden /*
311 1.1.2.2 wrstuden * if we don't have enough characters
312 1.1.2.2 wrstuden * left (cc < sizeof("HTTP/1.0") - 1)
313 1.1.2.2 wrstuden * then see if the remaining ones
314 1.1.2.2 wrstuden * are a request we can parse.
315 1.1.2.2 wrstuden */
316 1.1.2.2 wrstuden if (cc < sizeof("HTTP/1.0") - 1) {
317 1.1.2.2 wrstuden if (mbufstrncmp(m, n, i, cc,
318 1.1.2.2 wrstuden "HTTP/1.") == 1) {
319 1.1.2.2 wrstuden DPRINT("ok");
320 1.1.2.2 wrstuden goto readmore;
321 1.1.2.2 wrstuden } else {
322 1.1.2.2 wrstuden DPRINT("bad");
323 1.1.2.2 wrstuden goto fallout;
324 1.1.2.2 wrstuden }
325 1.1.2.2 wrstuden } else if (
326 1.1.2.2 wrstuden mbufstrcmp(m, n, i, "HTTP/1.0") ||
327 1.1.2.2 wrstuden mbufstrcmp(m, n, i, "HTTP/1.1")) {
328 1.1.2.2 wrstuden DPRINT("ok");
329 1.1.2.2 wrstuden soishttpconnected(so,
330 1.1.2.2 wrstuden arg, waitflag);
331 1.1.2.2 wrstuden return;
332 1.1.2.2 wrstuden } else {
333 1.1.2.2 wrstuden DPRINT("bad");
334 1.1.2.2 wrstuden goto fallout;
335 1.1.2.2 wrstuden }
336 1.1.2.2 wrstuden }
337 1.1.2.2 wrstuden }
338 1.1.2.2 wrstuden }
339 1.1.2.2 wrstuden }
340 1.1.2.2 wrstuden readmore:
341 1.1.2.2 wrstuden DPRINT("readmore");
342 1.1.2.2 wrstuden /*
343 1.1.2.2 wrstuden * if we hit here we haven't hit something
344 1.1.2.2 wrstuden * we don't understand or a newline, so try again
345 1.1.2.2 wrstuden */
346 1.1.2.2 wrstuden so->so_upcall = soparsehttpvers;
347 1.1.2.2 wrstuden so->so_rcv.sb_flags |= SB_UPCALL;
348 1.1.2.2 wrstuden return;
349 1.1.2.2 wrstuden
350 1.1.2.2 wrstuden fallout:
351 1.1.2.2 wrstuden DPRINT("fallout");
352 1.1.2.2 wrstuden so->so_upcall = NULL;
353 1.1.2.2 wrstuden so->so_rcv.sb_flags &= ~SB_UPCALL;
354 1.1.2.2 wrstuden soisconnected(so);
355 1.1.2.2 wrstuden return;
356 1.1.2.2 wrstuden }
357 1.1.2.2 wrstuden
358 1.1.2.2 wrstuden
359 1.1.2.2 wrstuden #define NCHRS 3
360 1.1.2.2 wrstuden
361 1.1.2.2 wrstuden static void
362 1.1.2.2 wrstuden soishttpconnected(struct socket *so, void *arg, int waitflag)
363 1.1.2.2 wrstuden {
364 1.1.2.2 wrstuden char a, b, c;
365 1.1.2.2 wrstuden struct mbuf *m, *n;
366 1.1.2.2 wrstuden int ccleft, copied;
367 1.1.2.2 wrstuden
368 1.1.2.2 wrstuden DPRINT("start");
369 1.1.2.2 wrstuden if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
370 1.1.2.2 wrstuden goto gotit;
371 1.1.2.2 wrstuden
372 1.1.2.2 wrstuden /*
373 1.1.2.2 wrstuden * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c
374 1.1.2.2 wrstuden * copied - how much we've copied so far
375 1.1.2.2 wrstuden * ccleft - how many bytes remaining in the socketbuffer
376 1.1.2.2 wrstuden * just loop over the mbufs subtracting from 'ccleft' until we only
377 1.1.2.2 wrstuden * have NCHRS left
378 1.1.2.2 wrstuden */
379 1.1.2.2 wrstuden copied = 0;
380 1.1.2.2 wrstuden ccleft = so->so_rcv.sb_cc;
381 1.1.2.2 wrstuden if (ccleft < NCHRS)
382 1.1.2.2 wrstuden goto readmore;
383 1.1.2.2 wrstuden a = b = c = '\0';
384 1.1.2.2 wrstuden for (m = so->so_rcv.sb_mb; m; m = n) {
385 1.1.2.2 wrstuden n = m->m_nextpkt;
386 1.1.2.2 wrstuden for (; m; m = m->m_next) {
387 1.1.2.2 wrstuden ccleft -= m->m_len;
388 1.1.2.2 wrstuden if (ccleft <= NCHRS) {
389 1.1.2.2 wrstuden char *src;
390 1.1.2.2 wrstuden int tocopy;
391 1.1.2.2 wrstuden
392 1.1.2.2 wrstuden tocopy = (NCHRS - ccleft) - copied;
393 1.1.2.2 wrstuden src = mtod(m, char *) + (m->m_len - tocopy);
394 1.1.2.2 wrstuden
395 1.1.2.2 wrstuden while (tocopy--) {
396 1.1.2.2 wrstuden switch (copied++) {
397 1.1.2.2 wrstuden case 0:
398 1.1.2.2 wrstuden a = *src++;
399 1.1.2.2 wrstuden break;
400 1.1.2.2 wrstuden case 1:
401 1.1.2.2 wrstuden b = *src++;
402 1.1.2.2 wrstuden break;
403 1.1.2.2 wrstuden case 2:
404 1.1.2.2 wrstuden c = *src++;
405 1.1.2.2 wrstuden break;
406 1.1.2.2 wrstuden }
407 1.1.2.2 wrstuden }
408 1.1.2.2 wrstuden }
409 1.1.2.2 wrstuden }
410 1.1.2.2 wrstuden }
411 1.1.2.2 wrstuden if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
412 1.1.2.2 wrstuden /* we have all request headers */
413 1.1.2.2 wrstuden goto gotit;
414 1.1.2.2 wrstuden }
415 1.1.2.2 wrstuden
416 1.1.2.2 wrstuden readmore:
417 1.1.2.2 wrstuden so->so_upcall = soishttpconnected;
418 1.1.2.2 wrstuden so->so_rcv.sb_flags |= SB_UPCALL;
419 1.1.2.2 wrstuden return;
420 1.1.2.2 wrstuden
421 1.1.2.2 wrstuden gotit:
422 1.1.2.2 wrstuden so->so_upcall = NULL;
423 1.1.2.2 wrstuden so->so_rcv.sb_flags &= ~SB_UPCALL;
424 1.1.2.2 wrstuden soisconnected(so);
425 1.1.2.2 wrstuden return;
426 1.1.2.2 wrstuden }
427