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