Print this page
inet_pton
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/sockfs/nl7c.c
+++ new/usr/src/uts/common/fs/sockfs/nl7c.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 +/*
26 + * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27 + */
25 28
26 29 /*
27 30 * NL7C (Network Layer 7 Cache) as part of SOCKFS provides an in-kernel
28 31 * gateway cache for the request/response message based L7 protocol HTTP
29 32 * (Hypertext Transfer Protocol, see HTTP/1.1 RFC2616) in a semantically
30 33 * transparent manner.
31 34 *
32 35 * Neither the requesting user agent (client, e.g. web browser) nor the
33 36 * origin server (e.g. webserver) that provided the response cached by
34 37 * NL7C are impacted in any way.
35 38 *
36 39 * Note, currently NL7C only processes HTTP messages via the embedded
37 40 * URI of scheme http (not https nor any other), additional scheme are
38 41 * intended to be supported as is practical such that much of the NL7C
39 42 * framework may appear more general purpose then would be needed just
40 43 * for an HTTP gateway cache.
41 44 *
42 45 * NL7C replaces NCA (Network Cache and Accelerator) and in the future
43 46 * NCAS (NCA/SSL).
44 47 *
45 48 * Further, NL7C uses all NCA configuration files, see "/etc/nca/", the
46 49 * NCA socket API, "AF_NCA", and "ndd /dev/nca" for backwards compatibility.
47 50 */
48 51
49 52 #include <sys/systm.h>
50 53 #include <sys/strsun.h>
51 54 #include <sys/strsubr.h>
52 55 #include <inet/common.h>
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
53 56 #include <inet/led.h>
54 57 #include <inet/mi.h>
55 58 #include <netinet/in.h>
56 59 #include <fs/sockfs/nl7c.h>
57 60 #include <fs/sockfs/nl7curi.h>
58 61 #include <fs/sockfs/socktpi.h>
59 62
60 63 #include <inet/nca/ncadoorhdr.h>
61 64 #include <inet/nca/ncalogd.h>
62 65 #include <inet/nca/ncandd.h>
66 +#include <inet/ip.h>
63 67
64 68 #include <sys/promif.h>
65 69
66 70 /*
67 71 * NL7C, NCA, NL7C logger enabled:
68 72 */
69 73
70 74 boolean_t nl7c_enabled = B_FALSE;
71 75
72 76 boolean_t nl7c_logd_enabled = B_FALSE;
73 77 boolean_t nl7c_logd_started = B_FALSE;
74 78 boolean_t nl7c_logd_cycle = B_TRUE;
75 79
76 80 /*
77 81 * Some externs:
78 82 */
79 -
80 -extern int inet_pton(int, char *, void *);
81 -
82 83 extern void nl7c_uri_init(void);
83 84 extern boolean_t nl7c_logd_init(int, caddr_t *);
84 85 extern void nl7c_nca_init(void);
85 86
86 87 /*
87 88 * nl7c_addr_t - a singly linked grounded list, pointed to by *nl7caddrs,
88 89 * constructed at init time by parsing "/etc/nca/ncaport.conf".
89 90 *
90 91 * This list is searched at bind(3SOCKET) time when an application doesn't
91 92 * explicitly set AF_NCA but instead uses AF_INET, if a match is found then
92 93 * the underlying socket is marked sti_nl7c_flags NL7C_ENABLED.
93 94 */
94 95
95 96 typedef struct nl7c_addr_s {
96 97 struct nl7c_addr_s *next; /* next entry */
97 98 sa_family_t family; /* addr type, only INET and INET6 */
98 99 uint16_t port; /* port */
99 100 union {
100 101 ipaddr_t v4; /* IPv4 address */
101 102 in6_addr_t v6; /* IPv6 address */
102 103 void *align; /* foce alignment */
103 104 } addr; /* address */
104 105
105 106 struct sonode *listener; /* listen()er's sonode */
106 107 boolean_t temp; /* temporary addr via add_addr() ? */
107 108 } nl7c_addr_t;
108 109
109 110 nl7c_addr_t *nl7caddrs = NULL;
110 111
111 112 /*
112 113 * Called for an NL7C_ENABLED listen()er socket for the nl7c_addr_t
113 114 * previously returned by nl7c_lookup_addr().
114 115 */
115 116
116 117 void
117 118 nl7c_listener_addr(void *arg, struct sonode *so)
118 119 {
119 120 nl7c_addr_t *p = (nl7c_addr_t *)arg;
120 121
121 122 if (p->listener == NULL)
122 123 p->listener = so;
123 124 SOTOTPI(so)->sti_nl7c_addr = arg;
124 125 }
125 126
126 127 struct sonode *
127 128 nl7c_addr2portso(void *arg)
128 129 {
129 130 nl7c_addr_t *p = (nl7c_addr_t *)arg;
130 131
131 132 return (p->listener);
132 133 }
133 134
134 135 void *
135 136 nl7c_lookup_addr(void *addr, t_uscalar_t addrlen)
136 137 {
137 138 struct sockaddr *sap = addr;
138 139 struct sockaddr_in *v4p = addr;
139 140 nl7c_addr_t *p = nl7caddrs;
140 141
141 142 if (sap->sa_family != AF_INET || addrlen != sizeof (*v4p)) {
142 143 /* Only support IPv4 */
143 144 return (B_FALSE);
144 145 }
145 146 while (p) {
146 147 if (sap->sa_family == p->family &&
147 148 v4p->sin_port == p->port &&
148 149 (v4p->sin_addr.s_addr == p->addr.v4 ||
149 150 p->addr.v4 == INADDR_ANY)) {
150 151 /* Match */
151 152 return (p);
152 153 }
153 154 p = p->next;
154 155 }
155 156 return (NULL);
156 157 }
157 158
158 159 void *
159 160 nl7c_add_addr(void *addr, t_uscalar_t addrlen)
160 161 {
161 162 struct sockaddr *sap = addr;
162 163 struct sockaddr_in *v4p = addr;
163 164 nl7c_addr_t *new = NULL;
164 165 nl7c_addr_t *old;
165 166 nl7c_addr_t *p;
166 167 boolean_t alloced;
167 168
168 169 if (sap->sa_family != AF_INET || addrlen != sizeof (*v4p)) {
169 170 /* Only support IPv4 */
170 171 return (NULL);
171 172 }
172 173 again:
173 174 p = nl7caddrs;
174 175 while (p) {
175 176 if (new == NULL && p->port == 0)
176 177 new = p;
177 178 if (sap->sa_family == p->family &&
178 179 v4p->sin_port == p->port &&
179 180 (v4p->sin_addr.s_addr == p->addr.v4 ||
180 181 p->addr.v4 == INADDR_ANY)) {
181 182 /* Match */
182 183 return (p);
183 184 }
184 185 p = p->next;
185 186 }
186 187 if (new == NULL) {
187 188 new = kmem_zalloc(sizeof (*new), KM_SLEEP);
188 189 alloced = B_TRUE;
189 190 } else
190 191 alloced = B_FALSE;
191 192
192 193 new->family = sap->sa_family;
193 194 new->port = v4p->sin_port;
194 195 new->addr.v4 = v4p->sin_addr.s_addr;
195 196 new->temp = B_TRUE;
196 197
197 198 if (alloced) {
198 199 old = nl7caddrs;
199 200 new->next = old;
200 201 if (atomic_cas_ptr(&nl7caddrs, old, new) != old) {
201 202 kmem_free(new, sizeof (*new));
202 203 goto again;
203 204 }
204 205 }
205 206
206 207 return (new);
207 208 }
208 209
209 210 boolean_t
210 211 nl7c_close_addr(struct sonode *so)
211 212 {
212 213 nl7c_addr_t *p = nl7caddrs;
213 214
214 215 while (p) {
215 216 if (p->listener == so) {
216 217 if (p->temp)
217 218 p->port = (uint16_t)-1;
218 219 p->listener = NULL;
219 220 return (B_TRUE);
220 221 }
221 222 p = p->next;
222 223 }
223 224 return (B_FALSE);
224 225 }
225 226
226 227 static void
227 228 nl7c_addr_add(nl7c_addr_t *p)
228 229 {
229 230 p->next = nl7caddrs;
230 231 nl7caddrs = p;
231 232 }
232 233
233 234 void
234 235 nl7c_mi_report_addr(mblk_t *mp)
235 236 {
236 237 ipaddr_t ip;
237 238 uint16_t port;
238 239 nl7c_addr_t *p = nl7caddrs;
239 240 struct sonode *so;
240 241 char addr[32];
241 242
242 243 (void) mi_mpprintf(mp, "Door Up-Call-Queue IPaddr:TCPport Listenning");
243 244 while (p) {
244 245 if (p->port != (uint16_t)-1) {
245 246 /* Don't report freed slots */
246 247 ip = ntohl(p->addr.v4);
247 248 port = ntohs(p->port);
248 249
249 250 if (ip == INADDR_ANY) {
250 251 (void) strcpy(addr, "*");
251 252 } else {
252 253 int a1 = (ip >> 24) & 0xFF;
253 254 int a2 = (ip >> 16) & 0xFF;
254 255 int a3 = (ip >> 8) & 0xFF;
255 256 int a4 = ip & 0xFF;
256 257
257 258 (void) mi_sprintf(addr, "%d.%d.%d.%d",
258 259 a1, a2, a3, a4);
259 260 }
260 261 so = p->listener;
261 262 (void) mi_mpprintf(mp, "%p %s:%d %d",
262 263 so ? (void *)strvp2wq(SOTOV(so)) : NULL,
263 264 addr, port, p->listener ? 1 : 0);
264 265 }
265 266 p = p->next;
266 267 }
267 268 }
268 269
269 270 /*
270 271 * ASCII to unsigned.
271 272 *
272 273 * Note, it's assumed that *p is a valid zero byte terminated string.
273 274 */
274 275
275 276 static unsigned
276 277 atou(const char *p)
277 278 {
278 279 int c;
279 280 int v = 0;
280 281
281 282 /* Shift and add digit by digit */
282 283 while ((c = *p++) != NULL && isdigit(c)) {
283 284 v *= 10;
284 285 v += c - '0';
285 286 }
286 287 return (v);
287 288 }
288 289
289 290 /*
290 291 * strdup(), yet another strdup() in the kernel.
291 292 */
292 293
293 294 static char *
294 295 strdup(char *s)
295 296 {
296 297 int len = strlen(s) + 1;
297 298 char *ret = kmem_alloc(len, KM_SLEEP);
298 299
299 300 bcopy(s, ret, len);
300 301
301 302 return (ret);
302 303 }
303 304
304 305 /*
305 306 * Inet ASCII to binary.
306 307 *
307 308 * Note, it's assumed that *s is a valid zero byte terminated string, and
308 309 * that *p is a zero initialized struct (this is important as the value of
309 310 * INADDR_ANY and IN6ADDR_ANY is zero).
310 311 */
311 312
312 313 static int
313 314 inet_atob(char *s, nl7c_addr_t *p)
314 315 {
315 316 if (strcmp(s, "*") == 0) {
316 317 /* INADDR_ANY */
317 318 p->family = AF_INET;
318 319 return (0);
319 320 }
320 321 if (strcmp(s, "::") == 0) {
321 322 /* IN6ADDR_ANY */
322 323 p->family = AF_INET6;
323 324 return (0);
324 325 }
↓ open down ↓ |
233 lines elided |
↑ open up ↑ |
325 326 /* IPv4 address ? */
326 327 if (inet_pton(AF_INET, s, &p->addr.v4) != 1) {
327 328 /* Nop, IPv6 address ? */
328 329 if (inet_pton(AF_INET6, s, &p->addr.v6) != 1) {
329 330 /* Nop, return error */
330 331 return (1);
331 332 }
332 333 p->family = AF_INET6;
333 334 } else {
334 335 p->family = AF_INET;
335 - p->addr.v4 = ntohl(p->addr.v4);
336 336 }
337 +
337 338 return (0);
338 339 }
339 340
340 341 /*
341 342 * Open and read each line from "/etc/nca/ncaport.conf", the syntax of a
342 343 * ncaport.conf file line is:
343 344 *
344 345 * ncaport=IPaddr/Port[/Proxy]
345 346 *
346 347 * Where:
347 348 *
348 349 * ncaport - the only token recognized.
349 350 *
350 351 * IPaddr - an IPv4 numeric dot address (e.g. 192.168.84.71) or '*' for
351 352 * INADDR_ANY, or an IPv6 numeric address or "::" for IN6ADDR_ANY.
352 353 *
353 354 * / - IPaddr/Port separator.
354 355 *
355 356 * Port - a TCP decimal port number.
356 357 *
357 358 * Note, all other lines will be ignored.
358 359 */
359 360
360 361 static void
361 362 ncaportconf_read(void)
362 363 {
363 364 int ret;
364 365 struct vnode *vp;
365 366 char c;
366 367 ssize_t resid;
367 368 char buf[1024];
368 369 char *ebp = &buf[sizeof (buf)];
369 370 char *bp = ebp;
370 371 offset_t off = 0;
371 372 enum parse_e {START, TOK, ADDR, PORT, EOL} parse = START;
372 373 nl7c_addr_t *addrp = NULL;
373 374 char *ncaport = "ncaport";
374 375 char string[] = "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX";
375 376 char *stringp;
376 377 char *tok;
377 378 char *portconf = "/etc/nca/ncaport.conf";
378 379
379 380 ret = vn_open(portconf, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0);
380 381 if (ret == ENOENT) {
381 382 /* No portconf file, nothing to do */
382 383 return;
383 384 }
384 385 if (ret != 0) {
385 386 /* Error of some sort, tell'm about it */
386 387 cmn_err(CE_WARN, "%s: open error %d", portconf, ret);
387 388 return;
388 389 }
389 390 /*
390 391 * Read portconf one buf[] at a time, parse one char at a time.
391 392 */
392 393 for (;;) {
393 394 if (bp == ebp) {
394 395 /* Nothing left in buf[], read another */
395 396 ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off,
396 397 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid);
397 398 if (ret != 0) {
398 399 /* Error of some sort, tell'm about it */
399 400 cmn_err(CE_WARN, "%s: read error %d",
400 401 portconf, ret);
401 402 break;
402 403 }
403 404 if (resid == sizeof (buf)) {
404 405 /* EOF, done */
405 406 break;
406 407 }
407 408 /* Initilize per buf[] state */
408 409 bp = buf;
409 410 ebp = &buf[sizeof (buf) - resid];
410 411 off += sizeof (buf) - resid;
411 412 }
412 413 c = *bp++;
413 414 switch (parse) {
414 415 case START:
415 416 /* Initilize all per file line state */
416 417 if (addrp == NULL) {
417 418 addrp = kmem_zalloc(sizeof (*addrp),
418 419 KM_NOSLEEP);
419 420 }
420 421 tok = ncaport;
421 422 stringp = string;
422 423 parse = TOK;
423 424 /*FALLTHROUGH*/
424 425 case TOK:
425 426 if (c == '#') {
426 427 /* Comment through end of line */
427 428 parse = EOL;
428 429 break;
429 430 }
430 431 if (isalpha(c)) {
431 432 if (c != *tok++) {
432 433 /* Only know one token, skip */
433 434 parse = EOL;
434 435 }
435 436 } else if (c == '=') {
436 437 if (*tok != NULL) {
437 438 /* Only know one token, skip */
438 439 parse = EOL;
439 440 break;
440 441 }
441 442 parse = ADDR;
442 443 } else if (c == '\n') {
443 444 /* Found EOL, empty line, next line */
444 445 parse = START;
445 446 } else {
446 447 /* Unexpected char, skip */
447 448 parse = EOL;
448 449 }
449 450 break;
450 451
451 452 case ADDR:
452 453 if (c == '/') {
453 454 /* addr/port separator, end of addr */
454 455 *stringp = NULL;
455 456 if (inet_atob(string, addrp)) {
456 457 /* Bad addr, skip */
457 458 parse = EOL;
458 459 } else {
459 460 stringp = string;
460 461 parse = PORT;
461 462 }
462 463 } else {
463 464 /* Save char to string */
464 465 if (stringp ==
465 466 &string[sizeof (string) - 1]) {
466 467 /* Would overflow, skip */
467 468 parse = EOL;
468 469 } else {
469 470 /* Copy IP addr char */
470 471 *stringp++ = c;
471 472 }
472 473 }
473 474 break;
474 475
475 476 case PORT:
476 477 if (isdigit(c)) {
477 478 /* Save char to string */
478 479 if (stringp ==
479 480 &string[sizeof (string) - 1]) {
480 481 /* Would overflow, skip */
481 482 parse = EOL;
482 483 } else {
483 484 /* Copy port digit char */
484 485 *stringp++ = c;
485 486 }
486 487 break;
487 488 } else if (c == '#' || isspace(c)) {
488 489 /* End of port number, convert */
489 490 *stringp = NULL;
490 491 addrp->port = ntohs(atou(string));
491 492
492 493 /* End of parse, add entry */
493 494 nl7c_addr_add(addrp);
494 495 addrp = NULL;
495 496 parse = EOL;
496 497 } else {
497 498 /* Unrecognized char, skip */
498 499 parse = EOL;
499 500 break;
500 501 }
501 502 if (c == '\n') {
502 503 /* Found EOL, start on next line */
503 504 parse = START;
504 505 }
505 506 break;
506 507
507 508 case EOL:
508 509 if (c == '\n') {
509 510 /* Found EOL, start on next line */
510 511 parse = START;
511 512 }
512 513 break;
513 514 }
514 515
515 516 }
516 517 if (addrp != NULL) {
517 518 kmem_free(addrp, sizeof (*addrp));
518 519 }
519 520 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
520 521 VN_RELE(vp);
521 522 }
522 523
523 524 /*
524 525 * Open and read each line from "/etc/nca/ncakmod.conf" and parse looking
525 526 * for the NCA enabled, the syntax is: status=enabled, all other lines will
526 527 * be ignored.
527 528 */
528 529
529 530 static void
530 531 ncakmodconf_read(void)
531 532 {
532 533 int ret;
533 534 struct vnode *vp;
534 535 char c;
535 536 ssize_t resid;
536 537 char buf[1024];
537 538 char *ebp = &buf[sizeof (buf)];
538 539 char *bp = ebp;
539 540 offset_t off = 0;
540 541 enum parse_e {START, TOK, EOL} parse = START;
541 542 char *status = "status=enabled";
542 543 char *tok;
543 544 char *ncakmod = "/etc/nca/ncakmod.conf";
544 545
545 546 ret = vn_open(ncakmod, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0);
546 547 if (ret == ENOENT) {
547 548 /* No ncakmod file, nothing to do */
548 549 return;
549 550 }
550 551 if (ret != 0) {
551 552 /* Error of some sort, tell'm about it */
552 553 cmn_err(CE_WARN, "%s: open error %d", status, ret);
553 554 return;
554 555 }
555 556 /*
556 557 * Read ncakmod one buf[] at a time, parse one char at a time.
557 558 */
558 559 for (;;) {
559 560 if (bp == ebp) {
560 561 /* Nothing left in buf[], read another */
561 562 ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off,
562 563 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid);
563 564 if (ret != 0) {
564 565 /* Error of some sort, tell'm about it */
565 566 cmn_err(CE_WARN, "%s: read error %d",
566 567 status, ret);
567 568 break;
568 569 }
569 570 if (resid == sizeof (buf)) {
570 571 /* EOF, done */
571 572 break;
572 573 }
573 574 /* Initilize per buf[] state */
574 575 bp = buf;
575 576 ebp = &buf[sizeof (buf) - resid];
576 577 off += sizeof (buf) - resid;
577 578 }
578 579 c = *bp++;
579 580 switch (parse) {
580 581 case START:
581 582 /* Initilize all per file line state */
582 583 tok = status;
583 584 parse = TOK;
584 585 /*FALLTHROUGH*/
585 586 case TOK:
586 587 if (c == '#') {
587 588 /* Comment through end of line */
588 589 parse = EOL;
589 590 break;
590 591 }
591 592 if (isalpha(c) || c == '=') {
592 593 if (c != *tok++) {
593 594 /* Only know one token, skip */
594 595 parse = EOL;
595 596 }
596 597 } else if (c == '\n') {
597 598 /*
598 599 * Found EOL, if tok found done,
599 600 * else start on next-line.
600 601 */
601 602 if (*tok == NULL) {
602 603 nl7c_enabled = B_TRUE;
603 604 goto done;
604 605 }
605 606 parse = START;
606 607 } else {
607 608 /* Unexpected char, skip */
608 609 parse = EOL;
609 610 }
610 611 break;
611 612
612 613 case EOL:
613 614 if (c == '\n') {
614 615 /* Found EOL, start on next line */
615 616 parse = START;
616 617 }
617 618 break;
618 619 }
619 620
620 621 }
621 622 done:
622 623 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
623 624 VN_RELE(vp);
624 625 }
625 626
626 627 /*
627 628 * Open and read each line from "/etc/nca/ncalogd.conf" and parse for
628 629 * the tokens and token text (i.e. key and value ncalogd.conf(4)):
629 630 *
630 631 * status=enabled
631 632 *
632 633 * logd_file_size=[0-9]+
633 634 *
634 635 * logd_file_name=["]filename( filename)*["]
635 636 */
636 637
637 638 static int file_size = 1000000;
638 639 static caddr_t fnv[NCA_FIOV_SZ];
639 640
640 641 static void
641 642 ncalogdconf_read(void)
642 643 {
643 644 int ret;
644 645 struct vnode *vp;
645 646 char c;
646 647 int sz;
647 648 ssize_t resid;
648 649 char buf[1024];
649 650 char *ebp = &buf[sizeof (buf)];
650 651 char *bp = ebp;
651 652 offset_t off = 0;
652 653 enum parse_e {START, TOK, TEXT, EOL} parse = START;
653 654 char *tokstatus = "status\0enabled";
654 655 char *toksize = "logd_file_size";
655 656 char *tokfile = "logd_path_name";
656 657 char *tokstatusp;
657 658 char *toksizep;
658 659 char *tokfilep;
659 660 char *tok;
660 661 int tokdelim = 0;
661 662 char *ncalogd = "/etc/nca/ncalogd.conf";
662 663 char *ncadeflog = "/var/nca/log";
663 664 char file[TYPICALMAXPATHLEN] = {0};
664 665 char *fp = file;
665 666 caddr_t *fnvp = fnv;
666 667
667 668 ret = vn_open(ncalogd, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0);
668 669 if (ret == ENOENT) {
669 670 /* No ncalogd file, nothing to do */
670 671 return;
671 672 }
672 673 if (ret != 0) {
673 674 /* Error of some sort, tell'm about it */
674 675 cmn_err(CE_WARN, "ncalogdconf_read: %s: open error(%d).",
675 676 ncalogd, ret);
676 677 return;
677 678 }
678 679 /*
679 680 * Read ncalogd.conf one buf[] at a time, parse one char at a time.
680 681 */
681 682 for (;;) {
682 683 if (bp == ebp) {
683 684 /* Nothing left in buf[], read another */
684 685 ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off,
685 686 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid);
686 687 if (ret != 0) {
687 688 /* Error of some sort, tell'm about it */
688 689 cmn_err(CE_WARN, "%s: read error %d",
689 690 ncalogd, ret);
690 691 break;
691 692 }
692 693 if (resid == sizeof (buf)) {
693 694 /* EOF, done */
694 695 break;
695 696 }
696 697 /* Initilize per buf[] state */
697 698 bp = buf;
698 699 ebp = &buf[sizeof (buf) - resid];
699 700 off += sizeof (buf) - resid;
700 701 }
701 702 c = *bp++;
702 703 switch (parse) {
703 704 case START:
704 705 /* Initilize all per file line state */
705 706 tokstatusp = tokstatus;
706 707 toksizep = toksize;
707 708 tokfilep = tokfile;
708 709 tok = NULL;
709 710 parse = TOK;
710 711 sz = 0;
711 712 /*FALLTHROUGH*/
712 713 case TOK:
713 714 if (isalpha(c) || c == '_') {
714 715 /*
715 716 * Found a valid tok char, if matches
716 717 * any of the tokens continue else NULL
717 718 * then string pointer.
718 719 */
719 720 if (tokstatusp != NULL && c != *tokstatusp++)
720 721 tokstatusp = NULL;
721 722 if (toksizep != NULL && c != *toksizep++)
722 723 toksizep = NULL;
723 724 if (tokfilep != NULL && c != *tokfilep++)
724 725 tokfilep = NULL;
725 726
726 727 if (tokstatusp == NULL &&
727 728 toksizep == NULL &&
728 729 tokfilep == NULL) {
729 730 /*
730 731 * All tok string pointers are NULL
731 732 * so skip rest of line.
732 733 */
733 734 parse = EOL;
734 735 }
735 736 } else if (c == '=') {
736 737 /*
737 738 * Found tok separator, if tok found get
738 739 * tok text, else skip rest of line.
739 740 */
740 741 if (tokstatusp != NULL && *tokstatusp == NULL)
741 742 tok = tokstatus;
742 743 else if (toksizep != NULL && *toksizep == NULL)
743 744 tok = toksize;
744 745 else if (tokfilep != NULL && *tokfilep == NULL)
745 746 tok = tokfile;
746 747 if (tok != NULL)
747 748 parse = TEXT;
748 749 else
749 750 parse = EOL;
750 751 } else if (c == '\n') {
751 752 /* Found EOL, start on next line */
752 753 parse = START;
753 754 } else {
754 755 /* Comment or unknown char, skip rest of line */
755 756 parse = EOL;
756 757 }
757 758 break;
758 759 case TEXT:
759 760 if (c == '\n') {
760 761 /*
761 762 * Found EOL, finish up tok text processing
762 763 * (if any) and start on next line.
763 764 */
764 765 if (tok == tokstatus) {
765 766 if (*++tokstatusp == NULL)
766 767 nl7c_logd_enabled = B_TRUE;
767 768 } else if (tok == toksize) {
768 769 file_size = sz;
769 770 } else if (tok == tokfile) {
770 771 if (tokdelim == 0) {
771 772 /* Non delimited path name */
772 773 *fnvp++ = strdup(file);
773 774 } else if (fp != file) {
774 775 /* No closing delimiter */
775 776 /*EMPTY*/;
776 777 }
777 778 }
778 779 parse = START;
779 780 } else if (tok == tokstatus) {
780 781 if (! isalpha(c) || *++tokstatusp == NULL ||
781 782 c != *tokstatusp) {
782 783 /* Not enabled, skip line */
783 784 parse = EOL;
784 785 }
785 786 } else if (tok == toksize) {
786 787 if (isdigit(c)) {
787 788 sz *= 10;
788 789 sz += c - '0';
789 790 } else {
790 791 /* Not a decimal digit, skip line */
791 792 parse = EOL;
792 793 }
793 794 } else {
794 795 /* File name */
795 796 if (c == '"' && tokdelim++ == 0) {
796 797 /* Opening delimiter, skip */
797 798 /*EMPTY*/;
798 799 } else if (c == '"' || c == ' ') {
799 800 /* List delim or filename separator */
800 801 *fnvp++ = strdup(file);
801 802 fp = file;
802 803 } else if (fp < &file[sizeof (file) - 1]) {
803 804 /* Filename char */
804 805 *fp++ = c;
805 806 } else {
806 807 /* Filename to long, skip line */
807 808 parse = EOL;
808 809 }
809 810 }
810 811 break;
811 812
812 813 case EOL:
813 814 if (c == '\n') {
814 815 /* Found EOL, start on next line */
815 816 parse = START;
816 817 }
817 818 break;
818 819 }
819 820
820 821 }
821 822 done:
822 823 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
823 824 VN_RELE(vp);
824 825
825 826 if (nl7c_logd_enabled) {
826 827 if (fnvp == fnv) {
827 828 /*
828 829 * No logfile was specified and found so
829 830 * so use defualt NCA log file path.
830 831 */
831 832 *fnvp++ = strdup(ncadeflog);
832 833 }
833 834 if (fnvp < &fnv[NCA_FIOV_SZ]) {
834 835 /* NULL terminate list */
835 836 *fnvp = NULL;
836 837 }
837 838 }
838 839 }
839 840
840 841 void
841 842 nl7clogd_startup(void)
842 843 {
843 844 static kmutex_t startup;
844 845
845 846 /*
846 847 * Called on the first log() attempt, have to wait until then to
847 848 * initialize logd as at logdconf_read() the root fs is read-only.
848 849 */
849 850 mutex_enter(&startup);
850 851 if (nl7c_logd_started) {
851 852 /* Lost the race, nothing todo */
852 853 mutex_exit(&startup);
853 854 return;
854 855 }
855 856 nl7c_logd_started = B_TRUE;
856 857 if (! nl7c_logd_init(file_size, fnv)) {
857 858 /* Failure, disable logging */
858 859 nl7c_logd_enabled = B_FALSE;
859 860 cmn_err(CE_WARN, "nl7clogd_startup: failed, disabling loggin");
860 861 mutex_exit(&startup);
861 862 return;
862 863 }
863 864 mutex_exit(&startup);
864 865 }
865 866
866 867
867 868 void
868 869 nl7c_startup()
869 870 {
870 871 /*
871 872 * Open, read, and parse the NCA logd configuration file,
872 873 * then initialize URI processing and NCA compat.
873 874 */
874 875 ncalogdconf_read();
875 876 nl7c_uri_init();
876 877 nl7c_nca_init();
877 878 }
878 879
879 880 void
880 881 nl7c_init()
881 882 {
882 883 /* Open, read, and parse the NCA kmod configuration file */
883 884 ncakmodconf_read();
884 885
885 886 if (nl7c_enabled) {
886 887 /*
887 888 * NL7C is enabled so open, read, and parse
888 889 * the NCA address/port configuration file
889 890 * and call startup() to finish config/init.
890 891 */
891 892 ncaportconf_read();
892 893 nl7c_startup();
893 894 }
894 895 }
895 896
896 897 /*
897 898 * The main processing function called by accept() on a newly created
898 899 * socket prior to returning it to the caller of accept().
899 900 *
900 901 * Here data is read from the socket until a completed L7 request parse
901 902 * is completed. Data will be read in the context of the user thread
902 903 * which called accept(), when parse has been completed either B_TRUE
903 904 * or B_FALSE will be returned.
904 905 *
905 906 * If NL7C successfully process the L7 protocol request, i.e. generates
906 907 * a response, B_TRUE will be returned.
907 908 *
908 909 * Else, B_FALSE will be returned if NL7C can't process the request:
909 910 *
910 911 * 1) Couldn't locate a URI within the request.
911 912 *
912 913 * 2) URI scheme not reqcognized.
913 914 *
914 915 * 3) A request which can't be processed.
915 916 *
916 917 * 4) A request which could be processed but NL7C dosen't currently have
917 918 * the response data. In which case NL7C will parse the returned response
918 919 * from the application for possible caching for subsequent request(s).
919 920 */
920 921
921 922 volatile uint64_t nl7c_proc_cnt = 0;
922 923 volatile uint64_t nl7c_proc_error = 0;
923 924 volatile uint64_t nl7c_proc_ETIME = 0;
924 925 volatile uint64_t nl7c_proc_again = 0;
925 926 volatile uint64_t nl7c_proc_next = 0;
926 927 volatile uint64_t nl7c_proc_rcv = 0;
927 928 volatile uint64_t nl7c_proc_noLRI = 0;
928 929 volatile uint64_t nl7c_proc_nodata = 0;
929 930 volatile uint64_t nl7c_proc_parse = 0;
930 931
931 932 boolean_t
932 933 nl7c_process(struct sonode *so, boolean_t nonblocking)
933 934 {
934 935 vnode_t *vp = SOTOV(so);
935 936 sotpi_info_t *sti = SOTOTPI(so);
936 937 mblk_t *rmp = sti->sti_nl7c_rcv_mp;
937 938 clock_t timout;
938 939 rval_t rval;
939 940 uchar_t pri;
940 941 int pflag;
941 942 int error;
942 943 boolean_t more;
943 944 boolean_t ret = B_FALSE;
944 945 boolean_t first = B_TRUE;
945 946 boolean_t pollin = (sti->sti_nl7c_flags & NL7C_POLLIN);
946 947
947 948 nl7c_proc_cnt++;
948 949
949 950 /* Caller has so_lock enter()ed */
950 951 error = so_lock_read_intr(so, nonblocking ? FNDELAY|FNONBLOCK : 0);
951 952 if (error) {
952 953 /* Couldn't read lock, pass on this socket */
953 954 sti->sti_nl7c_flags = 0;
954 955 nl7c_proc_noLRI++;
955 956 return (B_FALSE);
956 957 }
957 958 /* Exit so_lock for now, will be reenter()ed prior to return */
958 959 mutex_exit(&so->so_lock);
959 960
960 961 if (pollin)
961 962 sti->sti_nl7c_flags &= ~NL7C_POLLIN;
962 963
963 964 /* Initialize some kstrgetmsg() constants */
964 965 pflag = MSG_ANY | MSG_DELAYERROR;
965 966 pri = 0;
966 967 if (nonblocking) {
967 968 /* Non blocking so don't block */
968 969 timout = 0;
969 970 } else if (sti->sti_nl7c_flags & NL7C_SOPERSIST) {
970 971 /* 2nd or more time(s) here so use keep-alive value */
971 972 timout = nca_http_keep_alive_timeout;
972 973 } else {
973 974 /* 1st time here so use connection value */
974 975 timout = nca_http_timeout;
975 976 }
976 977
977 978 rval.r_vals = 0;
978 979 do {
979 980 /*
980 981 * First time through, if no data left over from a previous
981 982 * kstrgetmsg() then try to get some, else just process it.
982 983 *
983 984 * Thereafter, rmp = NULL after the successful kstrgetmsg()
984 985 * so try to get some new data and append to list (i.e. until
985 986 * enough fragments are collected for a successful parse).
986 987 */
987 988 if (rmp == NULL) {
988 989
989 990 error = kstrgetmsg(vp, &rmp, NULL, &pri, &pflag,
990 991 timout, &rval);
991 992 if (error) {
992 993 if (error == ETIME) {
993 994 /* Timeout */
994 995 nl7c_proc_ETIME++;
995 996 } else if (error != EWOULDBLOCK) {
996 997 /* Error of some sort */
997 998 nl7c_proc_error++;
998 999 rval.r_v.r_v2 = error;
999 1000 sti->sti_nl7c_flags = 0;
1000 1001 break;
1001 1002 }
1002 1003 error = 0;
1003 1004 }
1004 1005 if (rmp != NULL) {
1005 1006 mblk_t *mp = sti->sti_nl7c_rcv_mp;
1006 1007
1007 1008
1008 1009 if (mp == NULL) {
1009 1010 /* Just new data, common case */
1010 1011 sti->sti_nl7c_rcv_mp = rmp;
1011 1012 } else {
1012 1013 /* Add new data to tail */
1013 1014 while (mp->b_cont != NULL)
1014 1015 mp = mp->b_cont;
1015 1016 mp->b_cont = rmp;
1016 1017 }
1017 1018 }
1018 1019 if (sti->sti_nl7c_rcv_mp == NULL) {
1019 1020 /* No data */
1020 1021 nl7c_proc_nodata++;
1021 1022 if (timout > 0 || (first && pollin)) {
1022 1023 /* Expected data so EOF */
1023 1024 ret = B_TRUE;
1024 1025 } else if (sti->sti_nl7c_flags &
1025 1026 NL7C_SOPERSIST) {
1026 1027 /* Persistent so just checking */
1027 1028 ret = B_FALSE;
1028 1029 }
1029 1030 break;
1030 1031 }
1031 1032 rmp = NULL;
1032 1033 }
1033 1034 first = B_FALSE;
1034 1035 again:
1035 1036 nl7c_proc_parse++;
1036 1037
1037 1038 more = nl7c_parse(so, nonblocking, &ret);
1038 1039
1039 1040 if (ret == B_TRUE && (sti->sti_nl7c_flags & NL7C_SOPERSIST)) {
1040 1041 /*
1041 1042 * Parse complete, cache hit, response on its way,
1042 1043 * socket is persistent so try to process the next
1043 1044 * request.
1044 1045 */
1045 1046 if (nonblocking) {
1046 1047 ret = B_FALSE;
1047 1048 break;
1048 1049 }
1049 1050 if (sti->sti_nl7c_rcv_mp) {
1050 1051 /* More recv-side data, pipelined */
1051 1052 nl7c_proc_again++;
1052 1053 goto again;
1053 1054 }
1054 1055 nl7c_proc_next++;
1055 1056 if (nonblocking)
1056 1057 timout = 0;
1057 1058 else
1058 1059 timout = nca_http_keep_alive_timeout;
1059 1060
1060 1061 more = B_TRUE;
1061 1062 }
1062 1063
1063 1064 } while (more);
1064 1065
1065 1066 if (sti->sti_nl7c_rcv_mp) {
1066 1067 nl7c_proc_rcv++;
1067 1068 }
1068 1069 sti->sti_nl7c_rcv_rval = rval.r_vals;
1069 1070 /* Renter so_lock, caller called with it enter()ed */
1070 1071 mutex_enter(&so->so_lock);
1071 1072 so_unlock_read(so);
1072 1073
1073 1074 return (ret);
1074 1075 }
↓ open down ↓ |
728 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX