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 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 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 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 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 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 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 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 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 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 }