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