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