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 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 * 127 nl7c_addr2portso(void *arg) 128 { 129 nl7c_addr_t *p = (nl7c_addr_t *)arg; 130 131 return (p->listener); 132 } 133 134 void * 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 * 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 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 227 nl7c_addr_add(nl7c_addr_t *p) 228 { 229 p->next = nl7caddrs; 230 nl7caddrs = p; 231 } 232 233 void 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 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 * 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 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 } 336 return (0); 337 } 338 339 /* 340 * Open and read each line from "/etc/nca/ncaport.conf", the syntax of a 341 * ncaport.conf file line is: 342 * 343 * ncaport=IPaddr/Port[/Proxy] 344 * 345 * Where: 346 * 347 * ncaport - the only token recognized. 348 * 349 * IPaddr - an IPv4 numeric dot address (e.g. 192.168.84.71) or '*' for 350 * INADDR_ANY, or an IPv6 numeric address or "::" for IN6ADDR_ANY. 351 * 352 * / - IPaddr/Port separator. 353 * 354 * Port - a TCP decimal port number. 355 * 356 * Note, all other lines will be ignored. 357 */ 358 359 static void 360 ncaportconf_read(void) 361 { 362 int ret; 363 struct vnode *vp; 364 char c; 365 ssize_t resid; 366 char buf[1024]; 367 char *ebp = &buf[sizeof (buf)]; 368 char *bp = ebp; 369 offset_t off = 0; 370 enum parse_e {START, TOK, ADDR, PORT, EOL} parse = START; 371 nl7c_addr_t *addrp = NULL; 372 char *ncaport = "ncaport"; 373 char string[] = "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX"; 374 char *stringp; 375 char *tok; 376 char *portconf = "/etc/nca/ncaport.conf"; 377 378 ret = vn_open(portconf, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0); 379 if (ret == ENOENT) { 380 /* No portconf file, nothing to do */ 381 return; 382 } 383 if (ret != 0) { 384 /* Error of some sort, tell'm about it */ 385 cmn_err(CE_WARN, "%s: open error %d", portconf, ret); 386 return; 387 } 388 /* 389 * Read portconf one buf[] at a time, parse one char at a time. 390 */ 391 for (;;) { 392 if (bp == ebp) { 393 /* Nothing left in buf[], read another */ 394 ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off, 395 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid); 396 if (ret != 0) { 397 /* Error of some sort, tell'm about it */ 398 cmn_err(CE_WARN, "%s: read error %d", 399 portconf, ret); 400 break; 401 } 402 if (resid == sizeof (buf)) { 403 /* EOF, done */ 404 break; 405 } 406 /* Initilize per buf[] state */ 407 bp = buf; 408 ebp = &buf[sizeof (buf) - resid]; 409 off += sizeof (buf) - resid; 410 } 411 c = *bp++; 412 switch (parse) { 413 case START: 414 /* Initilize all per file line state */ 415 if (addrp == NULL) { 416 addrp = kmem_zalloc(sizeof (*addrp), 417 KM_NOSLEEP); 418 } 419 tok = ncaport; 420 stringp = string; 421 parse = TOK; 422 /*FALLTHROUGH*/ 423 case TOK: 424 if (c == '#') { 425 /* Comment through end of line */ 426 parse = EOL; 427 break; 428 } 429 if (isalpha(c)) { 430 if (c != *tok++) { 431 /* Only know one token, skip */ 432 parse = EOL; 433 } 434 } else if (c == '=') { 435 if (*tok != NULL) { 436 /* Only know one token, skip */ 437 parse = EOL; 438 break; 439 } 440 parse = ADDR; 441 } else if (c == '\n') { 442 /* Found EOL, empty line, next line */ 443 parse = START; 444 } else { 445 /* Unexpected char, skip */ 446 parse = EOL; 447 } 448 break; 449 450 case ADDR: 451 if (c == '/') { 452 /* addr/port separator, end of addr */ 453 *stringp = NULL; 454 if (inet_atob(string, addrp)) { 455 /* Bad addr, skip */ 456 parse = EOL; 457 } else { 458 stringp = string; 459 parse = PORT; 460 } 461 } else { 462 /* Save char to string */ 463 if (stringp == 464 &string[sizeof (string) - 1]) { 465 /* Would overflow, skip */ 466 parse = EOL; 467 } else { 468 /* Copy IP addr char */ 469 *stringp++ = c; 470 } 471 } 472 break; 473 474 case PORT: 475 if (isdigit(c)) { 476 /* Save char to string */ 477 if (stringp == 478 &string[sizeof (string) - 1]) { 479 /* Would overflow, skip */ 480 parse = EOL; 481 } else { 482 /* Copy port digit char */ 483 *stringp++ = c; 484 } 485 break; 486 } else if (c == '#' || isspace(c)) { 487 /* End of port number, convert */ 488 *stringp = NULL; 489 addrp->port = ntohs(atou(string)); 490 491 /* End of parse, add entry */ 492 nl7c_addr_add(addrp); 493 addrp = NULL; 494 parse = EOL; 495 } else { 496 /* Unrecognized char, skip */ 497 parse = EOL; 498 break; 499 } 500 if (c == '\n') { 501 /* Found EOL, start on next line */ 502 parse = START; 503 } 504 break; 505 506 case EOL: 507 if (c == '\n') { 508 /* Found EOL, start on next line */ 509 parse = START; 510 } 511 break; 512 } 513 514 } 515 if (addrp != NULL) { 516 kmem_free(addrp, sizeof (*addrp)); 517 } 518 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL); 519 VN_RELE(vp); 520 } 521 522 /* 523 * Open and read each line from "/etc/nca/ncakmod.conf" and parse looking 524 * for the NCA enabled, the syntax is: status=enabled, all other lines will 525 * be ignored. 526 */ 527 528 static void 529 ncakmodconf_read(void) 530 { 531 int ret; 532 struct vnode *vp; 533 char c; 534 ssize_t resid; 535 char buf[1024]; 536 char *ebp = &buf[sizeof (buf)]; 537 char *bp = ebp; 538 offset_t off = 0; 539 enum parse_e {START, TOK, EOL} parse = START; 540 char *status = "status=enabled"; 541 char *tok; 542 char *ncakmod = "/etc/nca/ncakmod.conf"; 543 544 ret = vn_open(ncakmod, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0); 545 if (ret == ENOENT) { 546 /* No ncakmod file, nothing to do */ 547 return; 548 } 549 if (ret != 0) { 550 /* Error of some sort, tell'm about it */ 551 cmn_err(CE_WARN, "%s: open error %d", status, ret); 552 return; 553 } 554 /* 555 * Read ncakmod one buf[] at a time, parse one char at a time. 556 */ 557 for (;;) { 558 if (bp == ebp) { 559 /* Nothing left in buf[], read another */ 560 ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off, 561 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid); 562 if (ret != 0) { 563 /* Error of some sort, tell'm about it */ 564 cmn_err(CE_WARN, "%s: read error %d", 565 status, ret); 566 break; 567 } 568 if (resid == sizeof (buf)) { 569 /* EOF, done */ 570 break; 571 } 572 /* Initilize per buf[] state */ 573 bp = buf; 574 ebp = &buf[sizeof (buf) - resid]; 575 off += sizeof (buf) - resid; 576 } 577 c = *bp++; 578 switch (parse) { 579 case START: 580 /* Initilize all per file line state */ 581 tok = status; 582 parse = TOK; 583 /*FALLTHROUGH*/ 584 case TOK: 585 if (c == '#') { 586 /* Comment through end of line */ 587 parse = EOL; 588 break; 589 } 590 if (isalpha(c) || c == '=') { 591 if (c != *tok++) { 592 /* Only know one token, skip */ 593 parse = EOL; 594 } 595 } else if (c == '\n') { 596 /* 597 * Found EOL, if tok found done, 598 * else start on next-line. 599 */ 600 if (*tok == NULL) { 601 nl7c_enabled = B_TRUE; 602 goto done; 603 } 604 parse = START; 605 } else { 606 /* Unexpected char, skip */ 607 parse = EOL; 608 } 609 break; 610 611 case EOL: 612 if (c == '\n') { 613 /* Found EOL, start on next line */ 614 parse = START; 615 } 616 break; 617 } 618 619 } 620 done: 621 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL); 622 VN_RELE(vp); 623 } 624 625 /* 626 * Open and read each line from "/etc/nca/ncalogd.conf" and parse for 627 * the tokens and token text (i.e. key and value ncalogd.conf(4)): 628 * 629 * status=enabled 630 * 631 * logd_file_size=[0-9]+ 632 * 633 * logd_file_name=["]filename( filename)*["] 634 */ 635 636 static int file_size = 1000000; 637 static caddr_t fnv[NCA_FIOV_SZ]; 638 639 static void 640 ncalogdconf_read(void) 641 { 642 int ret; 643 struct vnode *vp; 644 char c; 645 int sz; 646 ssize_t resid; 647 char buf[1024]; 648 char *ebp = &buf[sizeof (buf)]; 649 char *bp = ebp; 650 offset_t off = 0; 651 enum parse_e {START, TOK, TEXT, EOL} parse = START; 652 char *tokstatus = "status\0enabled"; 653 char *toksize = "logd_file_size"; 654 char *tokfile = "logd_path_name"; 655 char *tokstatusp; 656 char *toksizep; 657 char *tokfilep; 658 char *tok; 659 int tokdelim = 0; 660 char *ncalogd = "/etc/nca/ncalogd.conf"; 661 char *ncadeflog = "/var/nca/log"; 662 char file[TYPICALMAXPATHLEN] = {0}; 663 char *fp = file; 664 caddr_t *fnvp = fnv; 665 666 ret = vn_open(ncalogd, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0); 667 if (ret == ENOENT) { 668 /* No ncalogd file, nothing to do */ 669 return; 670 } 671 if (ret != 0) { 672 /* Error of some sort, tell'm about it */ 673 cmn_err(CE_WARN, "ncalogdconf_read: %s: open error(%d).", 674 ncalogd, ret); 675 return; 676 } 677 /* 678 * Read ncalogd.conf one buf[] at a time, parse one char at a time. 679 */ 680 for (;;) { 681 if (bp == ebp) { 682 /* Nothing left in buf[], read another */ 683 ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off, 684 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid); 685 if (ret != 0) { 686 /* Error of some sort, tell'm about it */ 687 cmn_err(CE_WARN, "%s: read error %d", 688 ncalogd, ret); 689 break; 690 } 691 if (resid == sizeof (buf)) { 692 /* EOF, done */ 693 break; 694 } 695 /* Initilize per buf[] state */ 696 bp = buf; 697 ebp = &buf[sizeof (buf) - resid]; 698 off += sizeof (buf) - resid; 699 } 700 c = *bp++; 701 switch (parse) { 702 case START: 703 /* Initilize all per file line state */ 704 tokstatusp = tokstatus; 705 toksizep = toksize; 706 tokfilep = tokfile; 707 tok = NULL; 708 parse = TOK; 709 sz = 0; 710 /*FALLTHROUGH*/ 711 case TOK: 712 if (isalpha(c) || c == '_') { 713 /* 714 * Found a valid tok char, if matches 715 * any of the tokens continue else NULL 716 * then string pointer. 717 */ 718 if (tokstatusp != NULL && c != *tokstatusp++) 719 tokstatusp = NULL; 720 if (toksizep != NULL && c != *toksizep++) 721 toksizep = NULL; 722 if (tokfilep != NULL && c != *tokfilep++) 723 tokfilep = NULL; 724 725 if (tokstatusp == NULL && 726 toksizep == NULL && 727 tokfilep == NULL) { 728 /* 729 * All tok string pointers are NULL 730 * so skip rest of line. 731 */ 732 parse = EOL; 733 } 734 } else if (c == '=') { 735 /* 736 * Found tok separator, if tok found get 737 * tok text, else skip rest of line. 738 */ 739 if (tokstatusp != NULL && *tokstatusp == NULL) 740 tok = tokstatus; 741 else if (toksizep != NULL && *toksizep == NULL) 742 tok = toksize; 743 else if (tokfilep != NULL && *tokfilep == NULL) 744 tok = tokfile; 745 if (tok != NULL) 746 parse = TEXT; 747 else 748 parse = EOL; 749 } else if (c == '\n') { 750 /* Found EOL, start on next line */ 751 parse = START; 752 } else { 753 /* Comment or unknown char, skip rest of line */ 754 parse = EOL; 755 } 756 break; 757 case TEXT: 758 if (c == '\n') { 759 /* 760 * Found EOL, finish up tok text processing 761 * (if any) and start on next line. 762 */ 763 if (tok == tokstatus) { 764 if (*++tokstatusp == NULL) 765 nl7c_logd_enabled = B_TRUE; 766 } else if (tok == toksize) { 767 file_size = sz; 768 } else if (tok == tokfile) { 769 if (tokdelim == 0) { 770 /* Non delimited path name */ 771 *fnvp++ = strdup(file); 772 } else if (fp != file) { 773 /* No closing delimiter */ 774 /*EMPTY*/; 775 } 776 } 777 parse = START; 778 } else if (tok == tokstatus) { 779 if (! isalpha(c) || *++tokstatusp == NULL || 780 c != *tokstatusp) { 781 /* Not enabled, skip line */ 782 parse = EOL; 783 } 784 } else if (tok == toksize) { 785 if (isdigit(c)) { 786 sz *= 10; 787 sz += c - '0'; 788 } else { 789 /* Not a decimal digit, skip line */ 790 parse = EOL; 791 } 792 } else { 793 /* File name */ 794 if (c == '"' && tokdelim++ == 0) { 795 /* Opening delimiter, skip */ 796 /*EMPTY*/; 797 } else if (c == '"' || c == ' ') { 798 /* List delim or filename separator */ 799 *fnvp++ = strdup(file); 800 fp = file; 801 } else if (fp < &file[sizeof (file) - 1]) { 802 /* Filename char */ 803 *fp++ = c; 804 } else { 805 /* Filename to long, skip line */ 806 parse = EOL; 807 } 808 } 809 break; 810 811 case EOL: 812 if (c == '\n') { 813 /* Found EOL, start on next line */ 814 parse = START; 815 } 816 break; 817 } 818 819 } 820 done: 821 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL); 822 VN_RELE(vp); 823 824 if (nl7c_logd_enabled) { 825 if (fnvp == fnv) { 826 /* 827 * No logfile was specified and found so 828 * so use defualt NCA log file path. 829 */ 830 *fnvp++ = strdup(ncadeflog); 831 } 832 if (fnvp < &fnv[NCA_FIOV_SZ]) { 833 /* NULL terminate list */ 834 *fnvp = NULL; 835 } 836 } 837 } 838 839 void 840 nl7clogd_startup(void) 841 { 842 static kmutex_t startup; 843 844 /* 845 * Called on the first log() attempt, have to wait until then to 846 * initialize logd as at logdconf_read() the root fs is read-only. 847 */ 848 mutex_enter(&startup); 849 if (nl7c_logd_started) { 850 /* Lost the race, nothing todo */ 851 mutex_exit(&startup); 852 return; 853 } 854 nl7c_logd_started = B_TRUE; 855 if (! nl7c_logd_init(file_size, fnv)) { 856 /* Failure, disable logging */ 857 nl7c_logd_enabled = B_FALSE; 858 cmn_err(CE_WARN, "nl7clogd_startup: failed, disabling loggin"); 859 mutex_exit(&startup); 860 return; 861 } 862 mutex_exit(&startup); 863 } 864 865 866 void 867 nl7c_startup() 868 { 869 /* 870 * Open, read, and parse the NCA logd configuration file, 871 * then initialize URI processing and NCA compat. 872 */ 873 ncalogdconf_read(); 874 nl7c_uri_init(); 875 nl7c_nca_init(); 876 } 877 878 void 879 nl7c_init() 880 { 881 /* Open, read, and parse the NCA kmod configuration file */ 882 ncakmodconf_read(); 883 884 if (nl7c_enabled) { 885 /* 886 * NL7C is enabled so open, read, and parse 887 * the NCA address/port configuration file 888 * and call startup() to finish config/init. 889 */ 890 ncaportconf_read(); 891 nl7c_startup(); 892 } 893 } 894 895 /* 896 * The main processing function called by accept() on a newly created 897 * socket prior to returning it to the caller of accept(). 898 * 899 * Here data is read from the socket until a completed L7 request parse 900 * is completed. Data will be read in the context of the user thread 901 * which called accept(), when parse has been completed either B_TRUE 902 * or B_FALSE will be returned. 903 * 904 * If NL7C successfully process the L7 protocol request, i.e. generates 905 * a response, B_TRUE will be returned. 906 * 907 * Else, B_FALSE will be returned if NL7C can't process the request: 908 * 909 * 1) Couldn't locate a URI within the request. 910 * 911 * 2) URI scheme not reqcognized. 912 * 913 * 3) A request which can't be processed. 914 * 915 * 4) A request which could be processed but NL7C dosen't currently have 916 * the response data. In which case NL7C will parse the returned response 917 * from the application for possible caching for subsequent request(s). 918 */ 919 920 volatile uint64_t nl7c_proc_cnt = 0; 921 volatile uint64_t nl7c_proc_error = 0; 922 volatile uint64_t nl7c_proc_ETIME = 0; 923 volatile uint64_t nl7c_proc_again = 0; 924 volatile uint64_t nl7c_proc_next = 0; 925 volatile uint64_t nl7c_proc_rcv = 0; 926 volatile uint64_t nl7c_proc_noLRI = 0; 927 volatile uint64_t nl7c_proc_nodata = 0; 928 volatile uint64_t nl7c_proc_parse = 0; 929 930 boolean_t 931 nl7c_process(struct sonode *so, boolean_t nonblocking) 932 { 933 vnode_t *vp = SOTOV(so); 934 sotpi_info_t *sti = SOTOTPI(so); 935 mblk_t *rmp = sti->sti_nl7c_rcv_mp; 936 clock_t timout; 937 rval_t rval; 938 uchar_t pri; 939 int pflag; 940 int error; 941 boolean_t more; 942 boolean_t ret = B_FALSE; 943 boolean_t first = B_TRUE; 944 boolean_t pollin = (sti->sti_nl7c_flags & NL7C_POLLIN); 945 946 nl7c_proc_cnt++; 947 948 /* Caller has so_lock enter()ed */ 949 error = so_lock_read_intr(so, nonblocking ? FNDELAY|FNONBLOCK : 0); 950 if (error) { 951 /* Couldn't read lock, pass on this socket */ 952 sti->sti_nl7c_flags = 0; 953 nl7c_proc_noLRI++; 954 return (B_FALSE); 955 } 956 /* Exit so_lock for now, will be reenter()ed prior to return */ 957 mutex_exit(&so->so_lock); 958 959 if (pollin) 960 sti->sti_nl7c_flags &= ~NL7C_POLLIN; 961 962 /* Initialize some kstrgetmsg() constants */ 963 pflag = MSG_ANY | MSG_DELAYERROR; 964 pri = 0; 965 if (nonblocking) { 966 /* Non blocking so don't block */ 967 timout = 0; 968 } else if (sti->sti_nl7c_flags & NL7C_SOPERSIST) { 969 /* 2nd or more time(s) here so use keep-alive value */ 970 timout = nca_http_keep_alive_timeout; 971 } else { 972 /* 1st time here so use connection value */ 973 timout = nca_http_timeout; 974 } 975 976 rval.r_vals = 0; 977 do { 978 /* 979 * First time through, if no data left over from a previous 980 * kstrgetmsg() then try to get some, else just process it. 981 * 982 * Thereafter, rmp = NULL after the successful kstrgetmsg() 983 * so try to get some new data and append to list (i.e. until 984 * enough fragments are collected for a successful parse). 985 */ 986 if (rmp == NULL) { 987 988 error = kstrgetmsg(vp, &rmp, NULL, &pri, &pflag, 989 timout, &rval); 990 if (error) { 991 if (error == ETIME) { 992 /* Timeout */ 993 nl7c_proc_ETIME++; 994 } else if (error != EWOULDBLOCK) { 995 /* Error of some sort */ 996 nl7c_proc_error++; 997 rval.r_v.r_v2 = error; 998 sti->sti_nl7c_flags = 0; 999 break; 1000 } 1001 error = 0; 1002 } 1003 if (rmp != NULL) { 1004 mblk_t *mp = sti->sti_nl7c_rcv_mp; 1005 1006 1007 if (mp == NULL) { 1008 /* Just new data, common case */ 1009 sti->sti_nl7c_rcv_mp = rmp; 1010 } else { 1011 /* Add new data to tail */ 1012 while (mp->b_cont != NULL) 1013 mp = mp->b_cont; 1014 mp->b_cont = rmp; 1015 } 1016 } 1017 if (sti->sti_nl7c_rcv_mp == NULL) { 1018 /* No data */ 1019 nl7c_proc_nodata++; 1020 if (timout > 0 || (first && pollin)) { 1021 /* Expected data so EOF */ 1022 ret = B_TRUE; 1023 } else if (sti->sti_nl7c_flags & 1024 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 && (sti->sti_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 (sti->sti_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 (sti->sti_nl7c_rcv_mp) { 1065 nl7c_proc_rcv++; 1066 } 1067 sti->sti_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