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 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 /*
29 * NL7C (Network Layer 7 Cache) as part of SOCKFS provides an in-kernel
30 * gateway cache for the request/response message based L7 protocol HTTP
31 * (Hypertext Transfer Protocol, see HTTP/1.1 RFC2616) in a semantically
32 * transparent manner.
33 *
34 * Neither the requesting user agent (client, e.g. web browser) nor the
35 * origin server (e.g. webserver) that provided the response cached by
36 * NL7C are impacted in any way.
37 *
38 * Note, currently NL7C only processes HTTP messages via the embedded
39 * URI of scheme http (not https nor any other), additional scheme are
40 * intended to be supported as is practical such that much of the NL7C
41 * framework may appear more general purpose then would be needed just
42 * for an HTTP gateway cache.
43 *
44 * NL7C replaces NCA (Network Cache and Accelerator) and in the future
45 * NCAS (NCA/SSL).
46 *
47 * Further, NL7C uses all NCA configuration files, see "/etc/nca/", the
48 * NCA socket API, "AF_NCA", and "ndd /dev/nca" for backwards compatibility.
49 */
50
51 #include <sys/systm.h>
52 #include <sys/strsun.h>
53 #include <sys/strsubr.h>
54 #include <inet/common.h>
55 #include <inet/ip.h>
56 #include <inet/led.h>
57 #include <inet/mi.h>
58 #include <netinet/in.h>
59 #include <fs/sockfs/nl7c.h>
60 #include <fs/sockfs/nl7curi.h>
61 #include <fs/sockfs/socktpi.h>
62
63 #include <inet/nca/ncadoorhdr.h>
64 #include <inet/nca/ncalogd.h>
65 #include <inet/nca/ncandd.h>
66
67 #include <sys/promif.h>
68
69 /*
70 * NL7C, NCA, NL7C logger enabled:
71 */
72
73 boolean_t nl7c_enabled = B_FALSE;
74
75 boolean_t nl7c_logd_enabled = B_FALSE;
76 boolean_t nl7c_logd_started = B_FALSE;
77 boolean_t nl7c_logd_cycle = B_TRUE;
78
79 /*
80 * Some externs:
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 * Inet ASCII to binary.
291 *
292 * Note, it's assumed that *s is a valid zero byte terminated string, and
293 * that *p is a zero initialized struct (this is important as the value of
294 * INADDR_ANY and IN6ADDR_ANY is zero).
295 */
296
297 static int
inet_atob(char * s,nl7c_addr_t * p)298 inet_atob(char *s, nl7c_addr_t *p)
299 {
300 if (strcmp(s, "*") == 0) {
301 /* INADDR_ANY */
302 p->family = AF_INET;
303 return (0);
304 }
305 if (strcmp(s, "::") == 0) {
306 /* IN6ADDR_ANY */
307 p->family = AF_INET6;
308 return (0);
309 }
310 /* IPv4 address ? */
311 if (inet_pton(AF_INET, s, &p->addr.v4) != 1) {
312 /* Nop, IPv6 address ? */
313 if (inet_pton(AF_INET6, s, &p->addr.v6) != 1) {
314 /* Nop, return error */
315 return (1);
316 }
317 p->family = AF_INET6;
318 } else {
319 p->family = AF_INET;
320 }
321 return (0);
322 }
323
324 /*
325 * Open and read each line from "/etc/nca/ncaport.conf", the syntax of a
326 * ncaport.conf file line is:
327 *
328 * ncaport=IPaddr/Port[/Proxy]
329 *
330 * Where:
331 *
332 * ncaport - the only token recognized.
333 *
334 * IPaddr - an IPv4 numeric dot address (e.g. 192.168.84.71) or '*' for
335 * INADDR_ANY, or an IPv6 numeric address or "::" for IN6ADDR_ANY.
336 *
337 * / - IPaddr/Port separator.
338 *
339 * Port - a TCP decimal port number.
340 *
341 * Note, all other lines will be ignored.
342 */
343
344 static void
ncaportconf_read(void)345 ncaportconf_read(void)
346 {
347 int ret;
348 struct vnode *vp;
349 char c;
350 ssize_t resid;
351 char buf[1024];
352 char *ebp = &buf[sizeof (buf)];
353 char *bp = ebp;
354 offset_t off = 0;
355 enum parse_e {START, TOK, ADDR, PORT, EOL} parse = START;
356 nl7c_addr_t *addrp = NULL;
357 char *ncaport = "ncaport";
358 char string[] = "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX";
359 char *stringp;
360 char *tok;
361 char *portconf = "/etc/nca/ncaport.conf";
362
363 ret = vn_open(portconf, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0);
364 if (ret == ENOENT) {
365 /* No portconf file, nothing to do */
366 return;
367 }
368 if (ret != 0) {
369 /* Error of some sort, tell'm about it */
370 cmn_err(CE_WARN, "%s: open error %d", portconf, ret);
371 return;
372 }
373 /*
374 * Read portconf one buf[] at a time, parse one char at a time.
375 */
376 for (;;) {
377 if (bp == ebp) {
378 /* Nothing left in buf[], read another */
379 ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off,
380 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid);
381 if (ret != 0) {
382 /* Error of some sort, tell'm about it */
383 cmn_err(CE_WARN, "%s: read error %d",
384 portconf, ret);
385 break;
386 }
387 if (resid == sizeof (buf)) {
388 /* EOF, done */
389 break;
390 }
391 /* Initilize per buf[] state */
392 bp = buf;
393 ebp = &buf[sizeof (buf) - resid];
394 off += sizeof (buf) - resid;
395 }
396 c = *bp++;
397 switch (parse) {
398 case START:
399 /* Initilize all per file line state */
400 if (addrp == NULL) {
401 addrp = kmem_zalloc(sizeof (*addrp),
402 KM_NOSLEEP);
403 }
404 tok = ncaport;
405 stringp = string;
406 parse = TOK;
407 /*FALLTHROUGH*/
408 case TOK:
409 if (c == '#') {
410 /* Comment through end of line */
411 parse = EOL;
412 break;
413 }
414 if (isalpha(c)) {
415 if (c != *tok++) {
416 /* Only know one token, skip */
417 parse = EOL;
418 }
419 } else if (c == '=') {
420 if (*tok != NULL) {
421 /* Only know one token, skip */
422 parse = EOL;
423 break;
424 }
425 parse = ADDR;
426 } else if (c == '\n') {
427 /* Found EOL, empty line, next line */
428 parse = START;
429 } else {
430 /* Unexpected char, skip */
431 parse = EOL;
432 }
433 break;
434
435 case ADDR:
436 if (c == '/') {
437 /* addr/port separator, end of addr */
438 *stringp = NULL;
439 if (inet_atob(string, addrp)) {
440 /* Bad addr, skip */
441 parse = EOL;
442 } else {
443 stringp = string;
444 parse = PORT;
445 }
446 } else {
447 /* Save char to string */
448 if (stringp ==
449 &string[sizeof (string) - 1]) {
450 /* Would overflow, skip */
451 parse = EOL;
452 } else {
453 /* Copy IP addr char */
454 *stringp++ = c;
455 }
456 }
457 break;
458
459 case PORT:
460 if (isdigit(c)) {
461 /* Save char to string */
462 if (stringp ==
463 &string[sizeof (string) - 1]) {
464 /* Would overflow, skip */
465 parse = EOL;
466 } else {
467 /* Copy port digit char */
468 *stringp++ = c;
469 }
470 break;
471 } else if (c == '#' || isspace(c)) {
472 /* End of port number, convert */
473 *stringp = NULL;
474 addrp->port = ntohs(atou(string));
475
476 /* End of parse, add entry */
477 nl7c_addr_add(addrp);
478 addrp = NULL;
479 parse = EOL;
480 } else {
481 /* Unrecognized char, skip */
482 parse = EOL;
483 break;
484 }
485 if (c == '\n') {
486 /* Found EOL, start on next line */
487 parse = START;
488 }
489 break;
490
491 case EOL:
492 if (c == '\n') {
493 /* Found EOL, start on next line */
494 parse = START;
495 }
496 break;
497 }
498
499 }
500 if (addrp != NULL) {
501 kmem_free(addrp, sizeof (*addrp));
502 }
503 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
504 VN_RELE(vp);
505 }
506
507 /*
508 * Open and read each line from "/etc/nca/ncakmod.conf" and parse looking
509 * for the NCA enabled, the syntax is: status=enabled, all other lines will
510 * be ignored.
511 */
512
513 static void
ncakmodconf_read(void)514 ncakmodconf_read(void)
515 {
516 int ret;
517 struct vnode *vp;
518 char c;
519 ssize_t resid;
520 char buf[1024];
521 char *ebp = &buf[sizeof (buf)];
522 char *bp = ebp;
523 offset_t off = 0;
524 enum parse_e {START, TOK, EOL} parse = START;
525 char *status = "status=enabled";
526 char *tok;
527 char *ncakmod = "/etc/nca/ncakmod.conf";
528
529 ret = vn_open(ncakmod, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0);
530 if (ret == ENOENT) {
531 /* No ncakmod file, nothing to do */
532 return;
533 }
534 if (ret != 0) {
535 /* Error of some sort, tell'm about it */
536 cmn_err(CE_WARN, "%s: open error %d", status, ret);
537 return;
538 }
539 /*
540 * Read ncakmod one buf[] at a time, parse one char at a time.
541 */
542 for (;;) {
543 if (bp == ebp) {
544 /* Nothing left in buf[], read another */
545 ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off,
546 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid);
547 if (ret != 0) {
548 /* Error of some sort, tell'm about it */
549 cmn_err(CE_WARN, "%s: read error %d",
550 status, ret);
551 break;
552 }
553 if (resid == sizeof (buf)) {
554 /* EOF, done */
555 break;
556 }
557 /* Initilize per buf[] state */
558 bp = buf;
559 ebp = &buf[sizeof (buf) - resid];
560 off += sizeof (buf) - resid;
561 }
562 c = *bp++;
563 switch (parse) {
564 case START:
565 /* Initilize all per file line state */
566 tok = status;
567 parse = TOK;
568 /*FALLTHROUGH*/
569 case TOK:
570 if (c == '#') {
571 /* Comment through end of line */
572 parse = EOL;
573 break;
574 }
575 if (isalpha(c) || c == '=') {
576 if (c != *tok++) {
577 /* Only know one token, skip */
578 parse = EOL;
579 }
580 } else if (c == '\n') {
581 /*
582 * Found EOL, if tok found done,
583 * else start on next-line.
584 */
585 if (*tok == NULL) {
586 nl7c_enabled = B_TRUE;
587 goto done;
588 }
589 parse = START;
590 } else {
591 /* Unexpected char, skip */
592 parse = EOL;
593 }
594 break;
595
596 case EOL:
597 if (c == '\n') {
598 /* Found EOL, start on next line */
599 parse = START;
600 }
601 break;
602 }
603
604 }
605 done:
606 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
607 VN_RELE(vp);
608 }
609
610 /*
611 * Open and read each line from "/etc/nca/ncalogd.conf" and parse for
612 * the tokens and token text (i.e. key and value ncalogd.conf(4)):
613 *
614 * status=enabled
615 *
616 * logd_file_size=[0-9]+
617 *
618 * logd_file_name=["]filename( filename)*["]
619 */
620
621 static int file_size = 1000000;
622 static caddr_t fnv[NCA_FIOV_SZ];
623
624 static void
ncalogdconf_read(void)625 ncalogdconf_read(void)
626 {
627 int ret;
628 struct vnode *vp;
629 char c;
630 int sz;
631 ssize_t resid;
632 char buf[1024];
633 char *ebp = &buf[sizeof (buf)];
634 char *bp = ebp;
635 offset_t off = 0;
636 enum parse_e {START, TOK, TEXT, EOL} parse = START;
637 char *tokstatus = "status\0enabled";
638 char *toksize = "logd_file_size";
639 char *tokfile = "logd_path_name";
640 char *tokstatusp;
641 char *toksizep;
642 char *tokfilep;
643 char *tok;
644 int tokdelim = 0;
645 char *ncalogd = "/etc/nca/ncalogd.conf";
646 char *ncadeflog = "/var/nca/log";
647 char file[TYPICALMAXPATHLEN] = {0};
648 char *fp = file;
649 caddr_t *fnvp = fnv;
650
651 ret = vn_open(ncalogd, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0);
652 if (ret == ENOENT) {
653 /* No ncalogd file, nothing to do */
654 return;
655 }
656 if (ret != 0) {
657 /* Error of some sort, tell'm about it */
658 cmn_err(CE_WARN, "ncalogdconf_read: %s: open error(%d).",
659 ncalogd, ret);
660 return;
661 }
662 /*
663 * Read ncalogd.conf one buf[] at a time, parse one char at a time.
664 */
665 for (;;) {
666 if (bp == ebp) {
667 /* Nothing left in buf[], read another */
668 ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off,
669 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid);
670 if (ret != 0) {
671 /* Error of some sort, tell'm about it */
672 cmn_err(CE_WARN, "%s: read error %d",
673 ncalogd, ret);
674 break;
675 }
676 if (resid == sizeof (buf)) {
677 /* EOF, done */
678 break;
679 }
680 /* Initilize per buf[] state */
681 bp = buf;
682 ebp = &buf[sizeof (buf) - resid];
683 off += sizeof (buf) - resid;
684 }
685 c = *bp++;
686 switch (parse) {
687 case START:
688 /* Initilize all per file line state */
689 tokstatusp = tokstatus;
690 toksizep = toksize;
691 tokfilep = tokfile;
692 tok = NULL;
693 parse = TOK;
694 sz = 0;
695 /*FALLTHROUGH*/
696 case TOK:
697 if (isalpha(c) || c == '_') {
698 /*
699 * Found a valid tok char, if matches
700 * any of the tokens continue else NULL
701 * then string pointer.
702 */
703 if (tokstatusp != NULL && c != *tokstatusp++)
704 tokstatusp = NULL;
705 if (toksizep != NULL && c != *toksizep++)
706 toksizep = NULL;
707 if (tokfilep != NULL && c != *tokfilep++)
708 tokfilep = NULL;
709
710 if (tokstatusp == NULL &&
711 toksizep == NULL &&
712 tokfilep == NULL) {
713 /*
714 * All tok string pointers are NULL
715 * so skip rest of line.
716 */
717 parse = EOL;
718 }
719 } else if (c == '=') {
720 /*
721 * Found tok separator, if tok found get
722 * tok text, else skip rest of line.
723 */
724 if (tokstatusp != NULL && *tokstatusp == NULL)
725 tok = tokstatus;
726 else if (toksizep != NULL && *toksizep == NULL)
727 tok = toksize;
728 else if (tokfilep != NULL && *tokfilep == NULL)
729 tok = tokfile;
730 if (tok != NULL)
731 parse = TEXT;
732 else
733 parse = EOL;
734 } else if (c == '\n') {
735 /* Found EOL, start on next line */
736 parse = START;
737 } else {
738 /* Comment or unknown char, skip rest of line */
739 parse = EOL;
740 }
741 break;
742 case TEXT:
743 if (c == '\n') {
744 /*
745 * Found EOL, finish up tok text processing
746 * (if any) and start on next line.
747 */
748 if (tok == tokstatus) {
749 if (*++tokstatusp == NULL)
750 nl7c_logd_enabled = B_TRUE;
751 } else if (tok == toksize) {
752 file_size = sz;
753 } else if (tok == tokfile) {
754 if (tokdelim == 0) {
755 /* Non delimited path name */
756 *fnvp++ = strdup(file);
757 } else if (fp != file) {
758 /* No closing delimiter */
759 /*EMPTY*/;
760 }
761 }
762 parse = START;
763 } else if (tok == tokstatus) {
764 if (! isalpha(c) || *++tokstatusp == NULL ||
765 c != *tokstatusp) {
766 /* Not enabled, skip line */
767 parse = EOL;
768 }
769 } else if (tok == toksize) {
770 if (isdigit(c)) {
771 sz *= 10;
772 sz += c - '0';
773 } else {
774 /* Not a decimal digit, skip line */
775 parse = EOL;
776 }
777 } else {
778 /* File name */
779 if (c == '"' && tokdelim++ == 0) {
780 /* Opening delimiter, skip */
781 /*EMPTY*/;
782 } else if (c == '"' || c == ' ') {
783 /* List delim or filename separator */
784 *fnvp++ = strdup(file);
785 fp = file;
786 } else if (fp < &file[sizeof (file) - 1]) {
787 /* Filename char */
788 *fp++ = c;
789 } else {
790 /* Filename to long, skip line */
791 parse = EOL;
792 }
793 }
794 break;
795
796 case EOL:
797 if (c == '\n') {
798 /* Found EOL, start on next line */
799 parse = START;
800 }
801 break;
802 }
803
804 }
805 done:
806 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
807 VN_RELE(vp);
808
809 if (nl7c_logd_enabled) {
810 if (fnvp == fnv) {
811 /*
812 * No logfile was specified and found so
813 * so use defualt NCA log file path.
814 */
815 *fnvp++ = strdup(ncadeflog);
816 }
817 if (fnvp < &fnv[NCA_FIOV_SZ]) {
818 /* NULL terminate list */
819 *fnvp = NULL;
820 }
821 }
822 }
823
824 void
nl7clogd_startup(void)825 nl7clogd_startup(void)
826 {
827 static kmutex_t startup;
828
829 /*
830 * Called on the first log() attempt, have to wait until then to
831 * initialize logd as at logdconf_read() the root fs is read-only.
832 */
833 mutex_enter(&startup);
834 if (nl7c_logd_started) {
835 /* Lost the race, nothing todo */
836 mutex_exit(&startup);
837 return;
838 }
839 nl7c_logd_started = B_TRUE;
840 if (! nl7c_logd_init(file_size, fnv)) {
841 /* Failure, disable logging */
842 nl7c_logd_enabled = B_FALSE;
843 cmn_err(CE_WARN, "nl7clogd_startup: failed, disabling loggin");
844 mutex_exit(&startup);
845 return;
846 }
847 mutex_exit(&startup);
848 }
849
850
851 void
nl7c_startup()852 nl7c_startup()
853 {
854 /*
855 * Open, read, and parse the NCA logd configuration file,
856 * then initialize URI processing and NCA compat.
857 */
858 ncalogdconf_read();
859 nl7c_uri_init();
860 nl7c_nca_init();
861 }
862
863 void
nl7c_init()864 nl7c_init()
865 {
866 /* Open, read, and parse the NCA kmod configuration file */
867 ncakmodconf_read();
868
869 if (nl7c_enabled) {
870 /*
871 * NL7C is enabled so open, read, and parse
872 * the NCA address/port configuration file
873 * and call startup() to finish config/init.
874 */
875 ncaportconf_read();
876 nl7c_startup();
877 }
878 }
879
880 /*
881 * The main processing function called by accept() on a newly created
882 * socket prior to returning it to the caller of accept().
883 *
884 * Here data is read from the socket until a completed L7 request parse
885 * is completed. Data will be read in the context of the user thread
886 * which called accept(), when parse has been completed either B_TRUE
887 * or B_FALSE will be returned.
888 *
889 * If NL7C successfully process the L7 protocol request, i.e. generates
890 * a response, B_TRUE will be returned.
891 *
892 * Else, B_FALSE will be returned if NL7C can't process the request:
893 *
894 * 1) Couldn't locate a URI within the request.
895 *
896 * 2) URI scheme not reqcognized.
897 *
898 * 3) A request which can't be processed.
899 *
900 * 4) A request which could be processed but NL7C dosen't currently have
901 * the response data. In which case NL7C will parse the returned response
902 * from the application for possible caching for subsequent request(s).
903 */
904
905 volatile uint64_t nl7c_proc_cnt = 0;
906 volatile uint64_t nl7c_proc_error = 0;
907 volatile uint64_t nl7c_proc_ETIME = 0;
908 volatile uint64_t nl7c_proc_again = 0;
909 volatile uint64_t nl7c_proc_next = 0;
910 volatile uint64_t nl7c_proc_rcv = 0;
911 volatile uint64_t nl7c_proc_noLRI = 0;
912 volatile uint64_t nl7c_proc_nodata = 0;
913 volatile uint64_t nl7c_proc_parse = 0;
914
915 boolean_t
nl7c_process(struct sonode * so,boolean_t nonblocking)916 nl7c_process(struct sonode *so, boolean_t nonblocking)
917 {
918 vnode_t *vp = SOTOV(so);
919 sotpi_info_t *sti = SOTOTPI(so);
920 mblk_t *rmp = sti->sti_nl7c_rcv_mp;
921 clock_t timout;
922 rval_t rval;
923 uchar_t pri;
924 int pflag;
925 int error;
926 boolean_t more;
927 boolean_t ret = B_FALSE;
928 boolean_t first = B_TRUE;
929 boolean_t pollin = (sti->sti_nl7c_flags & NL7C_POLLIN);
930
931 nl7c_proc_cnt++;
932
933 /* Caller has so_lock enter()ed */
934 error = so_lock_read_intr(so, nonblocking ? FNDELAY|FNONBLOCK : 0);
935 if (error) {
936 /* Couldn't read lock, pass on this socket */
937 sti->sti_nl7c_flags = 0;
938 nl7c_proc_noLRI++;
939 return (B_FALSE);
940 }
941 /* Exit so_lock for now, will be reenter()ed prior to return */
942 mutex_exit(&so->so_lock);
943
944 if (pollin)
945 sti->sti_nl7c_flags &= ~NL7C_POLLIN;
946
947 /* Initialize some kstrgetmsg() constants */
948 pflag = MSG_ANY | MSG_DELAYERROR;
949 pri = 0;
950 if (nonblocking) {
951 /* Non blocking so don't block */
952 timout = 0;
953 } else if (sti->sti_nl7c_flags & NL7C_SOPERSIST) {
954 /* 2nd or more time(s) here so use keep-alive value */
955 timout = nca_http_keep_alive_timeout;
956 } else {
957 /* 1st time here so use connection value */
958 timout = nca_http_timeout;
959 }
960
961 rval.r_vals = 0;
962 do {
963 /*
964 * First time through, if no data left over from a previous
965 * kstrgetmsg() then try to get some, else just process it.
966 *
967 * Thereafter, rmp = NULL after the successful kstrgetmsg()
968 * so try to get some new data and append to list (i.e. until
969 * enough fragments are collected for a successful parse).
970 */
971 if (rmp == NULL) {
972
973 error = kstrgetmsg(vp, &rmp, NULL, &pri, &pflag,
974 timout, &rval);
975 if (error) {
976 if (error == ETIME) {
977 /* Timeout */
978 nl7c_proc_ETIME++;
979 } else if (error != EWOULDBLOCK) {
980 /* Error of some sort */
981 nl7c_proc_error++;
982 rval.r_v.r_v2 = error;
983 sti->sti_nl7c_flags = 0;
984 break;
985 }
986 error = 0;
987 }
988 if (rmp != NULL) {
989 mblk_t *mp = sti->sti_nl7c_rcv_mp;
990
991
992 if (mp == NULL) {
993 /* Just new data, common case */
994 sti->sti_nl7c_rcv_mp = rmp;
995 } else {
996 /* Add new data to tail */
997 while (mp->b_cont != NULL)
998 mp = mp->b_cont;
999 mp->b_cont = rmp;
1000 }
1001 }
1002 if (sti->sti_nl7c_rcv_mp == NULL) {
1003 /* No data */
1004 nl7c_proc_nodata++;
1005 if (timout > 0 || (first && pollin)) {
1006 /* Expected data so EOF */
1007 ret = B_TRUE;
1008 } else if (sti->sti_nl7c_flags &
1009 NL7C_SOPERSIST) {
1010 /* Persistent so just checking */
1011 ret = B_FALSE;
1012 }
1013 break;
1014 }
1015 rmp = NULL;
1016 }
1017 first = B_FALSE;
1018 again:
1019 nl7c_proc_parse++;
1020
1021 more = nl7c_parse(so, nonblocking, &ret);
1022
1023 if (ret == B_TRUE && (sti->sti_nl7c_flags & NL7C_SOPERSIST)) {
1024 /*
1025 * Parse complete, cache hit, response on its way,
1026 * socket is persistent so try to process the next
1027 * request.
1028 */
1029 if (nonblocking) {
1030 ret = B_FALSE;
1031 break;
1032 }
1033 if (sti->sti_nl7c_rcv_mp) {
1034 /* More recv-side data, pipelined */
1035 nl7c_proc_again++;
1036 goto again;
1037 }
1038 nl7c_proc_next++;
1039 if (nonblocking)
1040 timout = 0;
1041 else
1042 timout = nca_http_keep_alive_timeout;
1043
1044 more = B_TRUE;
1045 }
1046
1047 } while (more);
1048
1049 if (sti->sti_nl7c_rcv_mp) {
1050 nl7c_proc_rcv++;
1051 }
1052 sti->sti_nl7c_rcv_rval = rval.r_vals;
1053 /* Renter so_lock, caller called with it enter()ed */
1054 mutex_enter(&so->so_lock);
1055 so_unlock_read(so);
1056
1057 return (ret);
1058 }
1059