1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/strsubr.h> 30*0Sstevel@tonic-gate #include <sys/strsun.h> 31*0Sstevel@tonic-gate #include <sys/param.h> 32*0Sstevel@tonic-gate #include <sys/sysmacros.h> 33*0Sstevel@tonic-gate #include <vm/seg_map.h> 34*0Sstevel@tonic-gate #include <vm/seg_kpm.h> 35*0Sstevel@tonic-gate #include <sys/condvar_impl.h> 36*0Sstevel@tonic-gate #include <sys/promif.h> 37*0Sstevel@tonic-gate #include <sys/sendfile.h> 38*0Sstevel@tonic-gate #include <fs/sockfs/nl7c.h> 39*0Sstevel@tonic-gate #include <fs/sockfs/nl7curi.h> 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate /* 42*0Sstevel@tonic-gate * Some externs: 43*0Sstevel@tonic-gate */ 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate extern boolean_t nl7c_logd_enabled; 46*0Sstevel@tonic-gate extern void nl7c_logd_log(uri_desc_t *, uri_desc_t *, time_t, ipaddr_t); 47*0Sstevel@tonic-gate boolean_t nl7c_close_addr(struct sonode *); 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate /* 50*0Sstevel@tonic-gate * Various global tuneables: 51*0Sstevel@tonic-gate */ 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate clock_t nl7c_uri_ttl = -1; /* TTL in seconds (-1 == infinite) */ 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate boolean_t nl7c_use_kmem = B_FALSE; /* Force use of kmem (no segmap) */ 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate uint64_t nl7c_file_prefetch = 1; /* File cache prefetch pages */ 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate uint64_t nl7c_uri_max = 0; /* Maximum bytes (0 == infinite) */ 60*0Sstevel@tonic-gate uint64_t nl7c_uri_bytes = 0; /* Bytes of kmem used by URIs */ 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate /* 63*0Sstevel@tonic-gate * Counters that need to move to kstat and/or be removed: 64*0Sstevel@tonic-gate */ 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_request = 0; 67*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_hit = 0; 68*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass = 0; 69*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_miss = 0; 70*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_temp = 0; 71*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_more = 0; 72*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_data = 0; 73*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_sendfilev = 0; 74*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_reclaim_calls = 0; 75*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_reclaim_cnt = 0; 76*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_urifail = 0; 77*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_dupbfail = 0; 78*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_more_get = 0; 79*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_getnot = 0; 80*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_option = 0; 81*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_more_eol = 0; 82*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_more_http = 0; 83*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_http = 0; 84*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_addfail = 0; 85*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_pass_temp = 0; 86*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_expire = 0; 87*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_NULL1 = 0; 88*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_NULL2 = 0; 89*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_close = 0; 90*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_temp_close = 0; 91*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_free = 0; 92*0Sstevel@tonic-gate volatile uint64_t nl7c_uri_temp_free = 0; 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* 95*0Sstevel@tonic-gate * Various kmem_cache_t's: 96*0Sstevel@tonic-gate */ 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate static kmem_cache_t *uri_kmc; 99*0Sstevel@tonic-gate static kmem_cache_t *uri_rd_kmc; 100*0Sstevel@tonic-gate static kmem_cache_t *uri_desb_kmc; 101*0Sstevel@tonic-gate static kmem_cache_t *uri_segmap_kmc; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate static void uri_kmc_reclaim(void *); 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate static void nl7c_uri_reclaim(void); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* 108*0Sstevel@tonic-gate * The URI hash is a dynamically sized A/B bucket hash, when the current 109*0Sstevel@tonic-gate * hash's average bucket chain length exceeds URI_HASH_AVRG a new hash of 110*0Sstevel@tonic-gate * the next P2Ps[] size is created. 111*0Sstevel@tonic-gate * 112*0Sstevel@tonic-gate * All lookups are done in the current hash then the new hash (if any), 113*0Sstevel@tonic-gate * if there is a new has then when a current hash bucket chain is examined 114*0Sstevel@tonic-gate * any uri_desc_t members will be migrated to the new hash and when the 115*0Sstevel@tonic-gate * last uri_desc_t has been migrated then the new hash will become the 116*0Sstevel@tonic-gate * current and the previous current hash will be freed leaving a single 117*0Sstevel@tonic-gate * hash. 118*0Sstevel@tonic-gate * 119*0Sstevel@tonic-gate * uri_hash_t - hash bucket (chain) type, contained in the uri_hash_ab[] 120*0Sstevel@tonic-gate * and can be accessed only after aquiring the uri_hash_access lock (for 121*0Sstevel@tonic-gate * READER or WRITER) then acquiring the lock uri_hash_t.lock, the uri_hash_t 122*0Sstevel@tonic-gate * and all linked uri_desc_t.hash members are protected. Note, a REF_HOLD() 123*0Sstevel@tonic-gate * is placed on all uri_desc_t uri_hash_t list members. 124*0Sstevel@tonic-gate * 125*0Sstevel@tonic-gate * uri_hash_access - rwlock for all uri_hash_* variables, READER for read 126*0Sstevel@tonic-gate * access and WRITER for write access. Note, WRITER is only required for 127*0Sstevel@tonic-gate * hash geometry changes. 128*0Sstevel@tonic-gate * 129*0Sstevel@tonic-gate * uri_hash_which - which uri_hash_ab[] is the current hash. 130*0Sstevel@tonic-gate * 131*0Sstevel@tonic-gate * uri_hash_n[] - the P2Ps[] index for each uri_hash_ab[]. 132*0Sstevel@tonic-gate * 133*0Sstevel@tonic-gate * uri_hash_sz[] - the size for each uri_hash_ab[]. 134*0Sstevel@tonic-gate * 135*0Sstevel@tonic-gate * uri_hash_cnt[] - the total uri_desc_t members for each uri_hash_ab[]. 136*0Sstevel@tonic-gate * 137*0Sstevel@tonic-gate * uri_hash_overflow[] - the uri_hash_cnt[] for each uri_hash_ab[] when 138*0Sstevel@tonic-gate * a new uri_hash_ab[] needs to be created. 139*0Sstevel@tonic-gate * 140*0Sstevel@tonic-gate * uri_hash_ab[] - the uri_hash_t entries. 141*0Sstevel@tonic-gate * 142*0Sstevel@tonic-gate * uri_hash_lru[] - the last uri_hash_ab[] walked for lru reclaim. 143*0Sstevel@tonic-gate */ 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate typedef struct uri_hash_s { 146*0Sstevel@tonic-gate struct uri_desc_s *list; /* List of uri_t(s) */ 147*0Sstevel@tonic-gate kmutex_t lock; 148*0Sstevel@tonic-gate } uri_hash_t; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate #define URI_HASH_AVRG 5 /* Desired average hash chain length */ 151*0Sstevel@tonic-gate #define URI_HASH_N_INIT 9 /* P2Ps[] initial index */ 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate static krwlock_t uri_hash_access; 154*0Sstevel@tonic-gate static uint32_t uri_hash_which = 0; 155*0Sstevel@tonic-gate static uint32_t uri_hash_n[2] = {URI_HASH_N_INIT, 0}; 156*0Sstevel@tonic-gate static uint32_t uri_hash_sz[2] = {0, 0}; 157*0Sstevel@tonic-gate static uint32_t uri_hash_cnt[2] = {0, 0}; 158*0Sstevel@tonic-gate static uint32_t uri_hash_overflow[2] = {0, 0}; 159*0Sstevel@tonic-gate static uri_hash_t *uri_hash_ab[2] = {NULL, NULL}; 160*0Sstevel@tonic-gate static uri_hash_t *uri_hash_lru[2] = {NULL, NULL}; 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate /* 163*0Sstevel@tonic-gate * Primes for N of 3 - 24 where P is first prime less then (2^(N-1))+(2^(N-2)) 164*0Sstevel@tonic-gate * these primes have been foud to be useful for prime sized hash tables. 165*0Sstevel@tonic-gate */ 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate static const int P2Ps[] = { 168*0Sstevel@tonic-gate 0, 0, 0, 5, 11, 23, 47, 89, 191, 383, 761, 1531, 3067, 169*0Sstevel@tonic-gate 6143, 12281, 24571, 49139, 98299, 196597, 393209, 170*0Sstevel@tonic-gate 786431, 1572853, 3145721, 6291449, 12582893, 0}; 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate /* 173*0Sstevel@tonic-gate * Hash macros: 174*0Sstevel@tonic-gate * 175*0Sstevel@tonic-gate * H2A(char *cp, char *ep, char c) - convert the escaped octet (ASCII) 176*0Sstevel@tonic-gate * hex multichar of the format "%HH" pointeded to by *cp to a char and 177*0Sstevel@tonic-gate * return in c, *ep points to past end of (char *), on return *cp will 178*0Sstevel@tonic-gate * point to the last char consumed. 179*0Sstevel@tonic-gate * 180*0Sstevel@tonic-gate * URI_HASH(unsigned hix, char *cp, char *ep) - hash the char(s) from 181*0Sstevel@tonic-gate * *cp to *ep to the unsigned hix, cp nor ep are modified. 182*0Sstevel@tonic-gate * 183*0Sstevel@tonic-gate * URI_HASH_STR(unsigned hix, str_t *sp) - hash the str_t *sp. 184*0Sstevel@tonic-gate * 185*0Sstevel@tonic-gate * URI_HASH_IX(unsigned hix, int hsz) - convert the hash value hix to 186*0Sstevel@tonic-gate * a hash index 0 - hsz. 187*0Sstevel@tonic-gate * 188*0Sstevel@tonic-gate * URI_HASH_DESC(uri_desc_t *uri, int which, unsigned hix) - hash the 189*0Sstevel@tonic-gate * uri_desc_t *uri's str_t path member, 190*0Sstevel@tonic-gate * 191*0Sstevel@tonic-gate * URI_HASH_MIGRATE(from, hp, to) - migrate the uri_hash_t *hp list 192*0Sstevel@tonic-gate * uri_desc_t members from hash from to hash to. 193*0Sstevel@tonic-gate * 194*0Sstevel@tonic-gate * URI_HASH_UNLINK(cur, new, hp, puri, uri) - unlink the uri_desc_t 195*0Sstevel@tonic-gate * *uri which is a member of the uri_hash_t *hp list with a previous 196*0Sstevel@tonic-gate * list member of *puri for the uri_hash_ab[] cur. After unlinking 197*0Sstevel@tonic-gate * check for cur hash empty, if so make new cur. Note, as this macro 198*0Sstevel@tonic-gate * can change a hash chain it needs to be run under hash_access as 199*0Sstevel@tonic-gate * RW_WRITER, futher as it can change the new hash to cur any access 200*0Sstevel@tonic-gate * to the hash state must be done after either dropping locks and 201*0Sstevel@tonic-gate * starting over or making sure the global state is consistent after 202*0Sstevel@tonic-gate * as before. 203*0Sstevel@tonic-gate */ 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate #define H2A(cp, ep, c) { \ 206*0Sstevel@tonic-gate int _h = 2; \ 207*0Sstevel@tonic-gate int _n = 0; \ 208*0Sstevel@tonic-gate char _hc; \ 209*0Sstevel@tonic-gate \ 210*0Sstevel@tonic-gate while (_h > 0 && ++(cp) < (ep)) { \ 211*0Sstevel@tonic-gate if (_h == 1) \ 212*0Sstevel@tonic-gate _n *= 0x10; \ 213*0Sstevel@tonic-gate _hc = *(cp); \ 214*0Sstevel@tonic-gate if (_hc >= '0' && _hc <= '9') \ 215*0Sstevel@tonic-gate _n += _hc - '0'; \ 216*0Sstevel@tonic-gate else if (_hc >= 'a' || _hc <= 'f') \ 217*0Sstevel@tonic-gate _n += _hc - 'W'; \ 218*0Sstevel@tonic-gate else if (_hc >= 'A' || _hc <= 'F') \ 219*0Sstevel@tonic-gate _n += _hc - '7'; \ 220*0Sstevel@tonic-gate _h--; \ 221*0Sstevel@tonic-gate } \ 222*0Sstevel@tonic-gate (c) = _n; \ 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate #define URI_HASH(hv, cp, ep) { \ 226*0Sstevel@tonic-gate char *_s = (cp); \ 227*0Sstevel@tonic-gate char _c; \ 228*0Sstevel@tonic-gate \ 229*0Sstevel@tonic-gate while (_s < (ep)) { \ 230*0Sstevel@tonic-gate if ((_c = *_s) == '%') { \ 231*0Sstevel@tonic-gate H2A(_s, (ep), _c); \ 232*0Sstevel@tonic-gate } \ 233*0Sstevel@tonic-gate (hv) = ((hv) << 5) + (hv) + _c; \ 234*0Sstevel@tonic-gate (hv) &= 0x7FFFFFFF; \ 235*0Sstevel@tonic-gate _s++; \ 236*0Sstevel@tonic-gate } \ 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate #define URI_HASH_STR(hix, sp) URI_HASH(hix, (sp)->cp, (sp)->ep) 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate #define URI_HASH_IX(hix, hsz) (hix) = (hix) % (hsz) 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate #define URI_HASH_DESC(uri, which, hix) { \ 244*0Sstevel@tonic-gate (hix) = 0; \ 245*0Sstevel@tonic-gate URI_HASH_STR((hix), &(uri)->path); \ 246*0Sstevel@tonic-gate if ((uri)->auth.cp != NULL) { \ 247*0Sstevel@tonic-gate URI_HASH_STR((hix), &(uri)->auth); \ 248*0Sstevel@tonic-gate } \ 249*0Sstevel@tonic-gate URI_HASH_IX((hix), uri_hash_sz[(which)]); \ 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate #define URI_HASH_MIGRATE(from, hp, to) { \ 253*0Sstevel@tonic-gate uri_desc_t *_nuri; \ 254*0Sstevel@tonic-gate uint32_t _nhix; \ 255*0Sstevel@tonic-gate uri_hash_t *_nhp; \ 256*0Sstevel@tonic-gate \ 257*0Sstevel@tonic-gate mutex_enter(&(hp)->lock); \ 258*0Sstevel@tonic-gate while ((_nuri = (hp)->list) != NULL) { \ 259*0Sstevel@tonic-gate (hp)->list = _nuri->hash; \ 260*0Sstevel@tonic-gate atomic_add_32(&uri_hash_cnt[(from)], -1); \ 261*0Sstevel@tonic-gate atomic_add_32(&uri_hash_cnt[(to)], 1); \ 262*0Sstevel@tonic-gate URI_HASH_DESC(_nuri, (to), _nhix); \ 263*0Sstevel@tonic-gate _nhp = &uri_hash_ab[(to)][_nhix]; \ 264*0Sstevel@tonic-gate mutex_enter(&_nhp->lock); \ 265*0Sstevel@tonic-gate _nuri->hash = _nhp->list; \ 266*0Sstevel@tonic-gate _nhp->list = _nuri; \ 267*0Sstevel@tonic-gate _nuri->hit = 0; \ 268*0Sstevel@tonic-gate mutex_exit(&_nhp->lock); \ 269*0Sstevel@tonic-gate } \ 270*0Sstevel@tonic-gate mutex_exit(&(hp)->lock); \ 271*0Sstevel@tonic-gate } 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate #define URI_HASH_UNLINK(cur, new, hp, puri, uri) { \ 274*0Sstevel@tonic-gate if ((puri) != NULL) { \ 275*0Sstevel@tonic-gate (puri)->hash = (uri)->hash; \ 276*0Sstevel@tonic-gate } else { \ 277*0Sstevel@tonic-gate (hp)->list = (uri)->hash; \ 278*0Sstevel@tonic-gate } \ 279*0Sstevel@tonic-gate if (atomic_add_32_nv(&uri_hash_cnt[(cur)], -1) == 0 && \ 280*0Sstevel@tonic-gate uri_hash_ab[(new)] != NULL) { \ 281*0Sstevel@tonic-gate kmem_free(uri_hash_ab[cur], \ 282*0Sstevel@tonic-gate sizeof (uri_hash_t) * uri_hash_sz[cur]); \ 283*0Sstevel@tonic-gate uri_hash_ab[(cur)] = NULL; \ 284*0Sstevel@tonic-gate uri_hash_lru[(cur)] = NULL; \ 285*0Sstevel@tonic-gate uri_hash_which = (new); \ 286*0Sstevel@tonic-gate } else { \ 287*0Sstevel@tonic-gate uri_hash_lru[(cur)] = (hp); \ 288*0Sstevel@tonic-gate } \ 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate #define URI_RD_ADD(uri, rdp, size, offset) { \ 292*0Sstevel@tonic-gate if ((uri)->tail == NULL) { \ 293*0Sstevel@tonic-gate (rdp) = &(uri)->response; \ 294*0Sstevel@tonic-gate } else { \ 295*0Sstevel@tonic-gate (rdp) = kmem_cache_alloc(uri_rd_kmc, KM_SLEEP); \ 296*0Sstevel@tonic-gate (uri)->tail->next = (rdp); \ 297*0Sstevel@tonic-gate } \ 298*0Sstevel@tonic-gate (rdp)->sz = size; \ 299*0Sstevel@tonic-gate (rdp)->off = offset; \ 300*0Sstevel@tonic-gate (rdp)->next = NULL; \ 301*0Sstevel@tonic-gate (uri)->tail = rdp; \ 302*0Sstevel@tonic-gate (uri)->count += size; \ 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate void 306*0Sstevel@tonic-gate nl7c_uri_init(void) 307*0Sstevel@tonic-gate { 308*0Sstevel@tonic-gate uint32_t cur = uri_hash_which; 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate rw_init(&uri_hash_access, NULL, RW_DEFAULT, NULL); 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate uri_hash_sz[cur] = P2Ps[URI_HASH_N_INIT]; 313*0Sstevel@tonic-gate uri_hash_overflow[cur] = P2Ps[URI_HASH_N_INIT] * URI_HASH_AVRG; 314*0Sstevel@tonic-gate uri_hash_ab[cur] = kmem_zalloc(sizeof (uri_hash_t) * uri_hash_sz[cur], 315*0Sstevel@tonic-gate KM_SLEEP); 316*0Sstevel@tonic-gate uri_hash_lru[cur] = uri_hash_ab[cur]; 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate uri_kmc = kmem_cache_create("NL7C_uri_kmc", sizeof (uri_desc_t), 0, 319*0Sstevel@tonic-gate NULL, NULL, uri_kmc_reclaim, NULL, NULL, 0); 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate uri_rd_kmc = kmem_cache_create("NL7C_uri_rd_kmc", sizeof (uri_rd_t), 0, 322*0Sstevel@tonic-gate NULL, NULL, NULL, NULL, NULL, 0); 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate uri_desb_kmc = kmem_cache_create("NL7C_uri_desb_kmc", 325*0Sstevel@tonic-gate sizeof (uri_desb_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate uri_segmap_kmc = kmem_cache_create("NL7C_uri_segmap_kmc", 328*0Sstevel@tonic-gate sizeof (uri_segmap_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate nl7c_http_init(); 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * The uri_desc_t ref_t inactive function called on the last REF_RELE(), 335*0Sstevel@tonic-gate * free all resources contained in the uri_desc_t. Note, the uri_desc_t 336*0Sstevel@tonic-gate * will be freed by REF_RELE() on return. 337*0Sstevel@tonic-gate */ 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate static void 340*0Sstevel@tonic-gate uri_inactive(uri_desc_t *uri) 341*0Sstevel@tonic-gate { 342*0Sstevel@tonic-gate int64_t bytes = 0; 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate if (uri->tail) { 345*0Sstevel@tonic-gate uri_rd_t *rdp = &uri->response; 346*0Sstevel@tonic-gate uri_rd_t *free = NULL; 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate while (rdp) { 349*0Sstevel@tonic-gate if (rdp->off == -1) { 350*0Sstevel@tonic-gate bytes += rdp->sz; 351*0Sstevel@tonic-gate kmem_free(rdp->data.kmem, rdp->sz); 352*0Sstevel@tonic-gate } else { 353*0Sstevel@tonic-gate VN_RELE(rdp->data.vnode); 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate rdp = rdp->next; 356*0Sstevel@tonic-gate if (free != NULL) { 357*0Sstevel@tonic-gate kmem_cache_free(uri_rd_kmc, free); 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate free = rdp; 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate if (bytes) { 363*0Sstevel@tonic-gate atomic_add_64(&nl7c_uri_bytes, -bytes); 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate if (uri->scheme != NULL) { 366*0Sstevel@tonic-gate nl7c_http_free(uri->scheme); 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate if (uri->reqmp) { 369*0Sstevel@tonic-gate freeb(uri->reqmp); 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate /* 374*0Sstevel@tonic-gate * The reclaim is called by the kmem subsystem when kmem is running 375*0Sstevel@tonic-gate * low. More work is needed to determine the best reclaim policy, for 376*0Sstevel@tonic-gate * now we just manipulate the nl7c_uri_max global maximum bytes threshold 377*0Sstevel@tonic-gate * value using a simple arithmetic backoff of the value every time this 378*0Sstevel@tonic-gate * function is called then call uri_reclaim() to enforce it. 379*0Sstevel@tonic-gate * 380*0Sstevel@tonic-gate * Note, this value remains in place and enforced for all subsequent 381*0Sstevel@tonic-gate * URI request/response processing. 382*0Sstevel@tonic-gate * 383*0Sstevel@tonic-gate * Note, nl7c_uri_max is currently initialized to 0 or infinite such that 384*0Sstevel@tonic-gate * the first call here set it to the current uri_bytes value then backoff 385*0Sstevel@tonic-gate * from there. 386*0Sstevel@tonic-gate * 387*0Sstevel@tonic-gate * XXX how do we determine when to increase nl7c_uri_max ??? 388*0Sstevel@tonic-gate */ 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate /*ARGSUSED*/ 391*0Sstevel@tonic-gate static void 392*0Sstevel@tonic-gate uri_kmc_reclaim(void *arg) 393*0Sstevel@tonic-gate { 394*0Sstevel@tonic-gate uint64_t new_max; 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate if ((new_max = nl7c_uri_max) == 0) { 397*0Sstevel@tonic-gate /* Currently infinite, initialize to current bytes used */ 398*0Sstevel@tonic-gate nl7c_uri_max = nl7c_uri_bytes; 399*0Sstevel@tonic-gate new_max = nl7c_uri_bytes; 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate if (new_max > 1) { 402*0Sstevel@tonic-gate /* Lower max_bytes to 93% of current value */ 403*0Sstevel@tonic-gate new_max >>= 1; /* 50% */ 404*0Sstevel@tonic-gate new_max += (new_max >> 1); /* 75% */ 405*0Sstevel@tonic-gate new_max += (new_max >> 2); /* 93% */ 406*0Sstevel@tonic-gate if (new_max < nl7c_uri_max) 407*0Sstevel@tonic-gate nl7c_uri_max = new_max; 408*0Sstevel@tonic-gate else 409*0Sstevel@tonic-gate nl7c_uri_max = 1; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate nl7c_uri_reclaim(); 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate /* 415*0Sstevel@tonic-gate * Delete a uri_desc_t from the URI hash. 416*0Sstevel@tonic-gate */ 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate static void 419*0Sstevel@tonic-gate uri_delete(uri_desc_t *del) 420*0Sstevel@tonic-gate { 421*0Sstevel@tonic-gate uint32_t hash = 0; 422*0Sstevel@tonic-gate uint32_t hix; 423*0Sstevel@tonic-gate uri_hash_t *hp; 424*0Sstevel@tonic-gate uri_desc_t *uri; 425*0Sstevel@tonic-gate uri_desc_t *puri; 426*0Sstevel@tonic-gate uint32_t cur; 427*0Sstevel@tonic-gate uint32_t new; 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate URI_HASH_STR(hash, &(del->path)); 430*0Sstevel@tonic-gate if (del->auth.cp != NULL) { 431*0Sstevel@tonic-gate /* Calculate hash for request authority */ 432*0Sstevel@tonic-gate URI_HASH(hash, del->auth.cp, del->auth.ep); 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate rw_enter(&uri_hash_access, RW_WRITER); 435*0Sstevel@tonic-gate cur = uri_hash_which; 436*0Sstevel@tonic-gate new = cur ? 0 : 1; 437*0Sstevel@tonic-gate next: 438*0Sstevel@tonic-gate puri = NULL; 439*0Sstevel@tonic-gate hix = hash; 440*0Sstevel@tonic-gate URI_HASH_IX(hix, uri_hash_sz[cur]); 441*0Sstevel@tonic-gate hp = &uri_hash_ab[cur][hix]; 442*0Sstevel@tonic-gate for (uri = hp->list; uri != NULL; uri = uri->hash) { 443*0Sstevel@tonic-gate if (uri != del) { 444*0Sstevel@tonic-gate puri = uri; 445*0Sstevel@tonic-gate continue; 446*0Sstevel@tonic-gate } 447*0Sstevel@tonic-gate /* 448*0Sstevel@tonic-gate * Found the URI, unlink from the hash chain, 449*0Sstevel@tonic-gate * drop locks, ref release it. 450*0Sstevel@tonic-gate */ 451*0Sstevel@tonic-gate URI_HASH_UNLINK(cur, new, hp, puri, uri); 452*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 453*0Sstevel@tonic-gate REF_RELE(uri); 454*0Sstevel@tonic-gate return; 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate if (cur != new && uri_hash_ab[new] != NULL) { 457*0Sstevel@tonic-gate /* 458*0Sstevel@tonic-gate * Not found in current hash and have a new hash so 459*0Sstevel@tonic-gate * check the new hash next. 460*0Sstevel@tonic-gate */ 461*0Sstevel@tonic-gate cur = new; 462*0Sstevel@tonic-gate goto next; 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate /* 468*0Sstevel@tonic-gate * Add a uri_desc_t to the URI hash. 469*0Sstevel@tonic-gate */ 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate static void 472*0Sstevel@tonic-gate uri_add(uri_desc_t *uri, krw_t rwlock, boolean_t nonblocking) 473*0Sstevel@tonic-gate { 474*0Sstevel@tonic-gate uint32_t hix; 475*0Sstevel@tonic-gate uri_hash_t *hp; 476*0Sstevel@tonic-gate uint32_t cur = uri_hash_which; 477*0Sstevel@tonic-gate uint32_t new = cur ? 0 : 1; 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate /* 480*0Sstevel@tonic-gate * Caller of uri_add() must hold the uri_hash_access rwlock. 481*0Sstevel@tonic-gate */ 482*0Sstevel@tonic-gate ASSERT((rwlock == RW_READER && RW_READ_HELD(&uri_hash_access)) || 483*0Sstevel@tonic-gate (rwlock == RW_WRITER && RW_WRITE_HELD(&uri_hash_access))); 484*0Sstevel@tonic-gate /* 485*0Sstevel@tonic-gate * uri_add() always succeeds so add a hash ref to the URI now. 486*0Sstevel@tonic-gate */ 487*0Sstevel@tonic-gate REF_HOLD(uri); 488*0Sstevel@tonic-gate again: 489*0Sstevel@tonic-gate URI_HASH_DESC(uri, cur, hix); 490*0Sstevel@tonic-gate if (uri_hash_ab[new] == NULL && 491*0Sstevel@tonic-gate uri_hash_cnt[cur] < uri_hash_overflow[cur]) { 492*0Sstevel@tonic-gate /* 493*0Sstevel@tonic-gate * Easy case, no new hash and current hasn't overflowed, 494*0Sstevel@tonic-gate * add URI to current hash and return. 495*0Sstevel@tonic-gate * 496*0Sstevel@tonic-gate * Note, the check for uri_hash_cnt[] above aren't done 497*0Sstevel@tonic-gate * atomictally, i.e. multiple threads can be in this code 498*0Sstevel@tonic-gate * as RW_READER and update the cnt[], this isn't a problem 499*0Sstevel@tonic-gate * as the check is only advisory. 500*0Sstevel@tonic-gate */ 501*0Sstevel@tonic-gate fast: 502*0Sstevel@tonic-gate atomic_add_32(&uri_hash_cnt[cur], 1); 503*0Sstevel@tonic-gate hp = &uri_hash_ab[cur][hix]; 504*0Sstevel@tonic-gate mutex_enter(&hp->lock); 505*0Sstevel@tonic-gate uri->hash = hp->list; 506*0Sstevel@tonic-gate hp->list = uri; 507*0Sstevel@tonic-gate mutex_exit(&hp->lock); 508*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 509*0Sstevel@tonic-gate return; 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate if (uri_hash_ab[new] == NULL) { 512*0Sstevel@tonic-gate /* 513*0Sstevel@tonic-gate * Need a new a or b hash, if not already RW_WRITER 514*0Sstevel@tonic-gate * try to upgrade our lock to writer. 515*0Sstevel@tonic-gate */ 516*0Sstevel@tonic-gate if (rwlock != RW_WRITER && ! rw_tryupgrade(&uri_hash_access)) { 517*0Sstevel@tonic-gate /* 518*0Sstevel@tonic-gate * Upgrade failed, we can't simple exit and reenter 519*0Sstevel@tonic-gate * the lock as after the exit and before the reenter 520*0Sstevel@tonic-gate * the whole world can change so just wait for writer 521*0Sstevel@tonic-gate * then do everything again. 522*0Sstevel@tonic-gate */ 523*0Sstevel@tonic-gate if (nonblocking) { 524*0Sstevel@tonic-gate /* 525*0Sstevel@tonic-gate * Can't block, use fast-path above. 526*0Sstevel@tonic-gate * 527*0Sstevel@tonic-gate * XXX should have a background thread to 528*0Sstevel@tonic-gate * handle new ab[] in this case so as to 529*0Sstevel@tonic-gate * not overflow the cur hash to much. 530*0Sstevel@tonic-gate */ 531*0Sstevel@tonic-gate goto fast; 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 534*0Sstevel@tonic-gate rwlock = RW_WRITER; 535*0Sstevel@tonic-gate rw_enter(&uri_hash_access, rwlock); 536*0Sstevel@tonic-gate cur = uri_hash_which; 537*0Sstevel@tonic-gate new = cur ? 0 : 1; 538*0Sstevel@tonic-gate goto again; 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate rwlock = RW_WRITER; 541*0Sstevel@tonic-gate if (uri_hash_ab[new] == NULL) { 542*0Sstevel@tonic-gate /* 543*0Sstevel@tonic-gate * Still need a new hash, allocate and initialize 544*0Sstevel@tonic-gate * the new hash. 545*0Sstevel@tonic-gate */ 546*0Sstevel@tonic-gate uri_hash_n[new] = uri_hash_n[cur] + 1; 547*0Sstevel@tonic-gate if (uri_hash_n[new] == 0) { 548*0Sstevel@tonic-gate /* 549*0Sstevel@tonic-gate * No larger P2Ps[] value so use current, 550*0Sstevel@tonic-gate * i.e. 2 of the largest are better than 1 ? 551*0Sstevel@tonic-gate */ 552*0Sstevel@tonic-gate uri_hash_n[new] = uri_hash_n[cur]; 553*0Sstevel@tonic-gate cmn_err(CE_NOTE, "NL7C: hash index overflow"); 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate uri_hash_sz[new] = P2Ps[uri_hash_n[new]]; 556*0Sstevel@tonic-gate ASSERT(uri_hash_cnt[new] == 0); 557*0Sstevel@tonic-gate uri_hash_overflow[new] = uri_hash_sz[new] * 558*0Sstevel@tonic-gate URI_HASH_AVRG; 559*0Sstevel@tonic-gate uri_hash_ab[new] = kmem_zalloc(sizeof (uri_hash_t) * 560*0Sstevel@tonic-gate uri_hash_sz[new], nonblocking ? KM_NOSLEEP : 561*0Sstevel@tonic-gate KM_SLEEP); 562*0Sstevel@tonic-gate if (uri_hash_ab[new] == NULL) { 563*0Sstevel@tonic-gate /* 564*0Sstevel@tonic-gate * Alloc failed, use fast-path above. 565*0Sstevel@tonic-gate * 566*0Sstevel@tonic-gate * XXX should have a background thread to 567*0Sstevel@tonic-gate * handle new ab[] in this case so as to 568*0Sstevel@tonic-gate * not overflow the cur hash to much. 569*0Sstevel@tonic-gate */ 570*0Sstevel@tonic-gate goto fast; 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate uri_hash_lru[new] = uri_hash_ab[new]; 573*0Sstevel@tonic-gate } 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate /* 576*0Sstevel@tonic-gate * Hashed against current hash so migrate any current hash chain 577*0Sstevel@tonic-gate * members, if any. 578*0Sstevel@tonic-gate * 579*0Sstevel@tonic-gate * Note, the hash chain list can be checked for a non empty list 580*0Sstevel@tonic-gate * outside of the hash chain list lock as the hash chain struct 581*0Sstevel@tonic-gate * can't be destroyed while in the uri_hash_access rwlock, worst 582*0Sstevel@tonic-gate * case is that a non empty list is found and after acquiring the 583*0Sstevel@tonic-gate * lock another thread beats us to it (i.e. migrated the list). 584*0Sstevel@tonic-gate */ 585*0Sstevel@tonic-gate hp = &uri_hash_ab[cur][hix]; 586*0Sstevel@tonic-gate if (hp->list != NULL) { 587*0Sstevel@tonic-gate URI_HASH_MIGRATE(cur, hp, new); 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate /* 590*0Sstevel@tonic-gate * If new hash has overflowed before current hash has been 591*0Sstevel@tonic-gate * completely migrated then walk all current hash chains and 592*0Sstevel@tonic-gate * migrate list members now. 593*0Sstevel@tonic-gate */ 594*0Sstevel@tonic-gate if (atomic_add_32_nv(&uri_hash_cnt[new], 1) >= uri_hash_overflow[new]) { 595*0Sstevel@tonic-gate for (hix = 0; hix < uri_hash_sz[cur]; hix++) { 596*0Sstevel@tonic-gate hp = &uri_hash_ab[cur][hix]; 597*0Sstevel@tonic-gate if (hp->list != NULL) { 598*0Sstevel@tonic-gate URI_HASH_MIGRATE(cur, hp, new); 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate } 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate /* 603*0Sstevel@tonic-gate * Add URI to new hash. 604*0Sstevel@tonic-gate */ 605*0Sstevel@tonic-gate URI_HASH_DESC(uri, new, hix); 606*0Sstevel@tonic-gate hp = &uri_hash_ab[new][hix]; 607*0Sstevel@tonic-gate mutex_enter(&hp->lock); 608*0Sstevel@tonic-gate uri->hash = hp->list; 609*0Sstevel@tonic-gate hp->list = uri; 610*0Sstevel@tonic-gate mutex_exit(&hp->lock); 611*0Sstevel@tonic-gate /* 612*0Sstevel@tonic-gate * Last, check to see if last cur hash chain has been 613*0Sstevel@tonic-gate * migrated, if so free cur hash and make new hash cur. 614*0Sstevel@tonic-gate */ 615*0Sstevel@tonic-gate if (uri_hash_cnt[cur] == 0) { 616*0Sstevel@tonic-gate /* 617*0Sstevel@tonic-gate * If we don't already hold the uri_hash_access rwlock for 618*0Sstevel@tonic-gate * RW_WRITE try to upgrade to RW_WRITE and if successful 619*0Sstevel@tonic-gate * check again and to see if still need to do the free. 620*0Sstevel@tonic-gate */ 621*0Sstevel@tonic-gate if ((rwlock == RW_WRITER || rw_tryupgrade(&uri_hash_access)) && 622*0Sstevel@tonic-gate uri_hash_cnt[cur] == 0 && uri_hash_ab[new] != 0) { 623*0Sstevel@tonic-gate kmem_free(uri_hash_ab[cur], 624*0Sstevel@tonic-gate sizeof (uri_hash_t) * uri_hash_sz[cur]); 625*0Sstevel@tonic-gate uri_hash_ab[cur] = NULL; 626*0Sstevel@tonic-gate uri_hash_lru[cur] = NULL; 627*0Sstevel@tonic-gate uri_hash_which = new; 628*0Sstevel@tonic-gate } 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 631*0Sstevel@tonic-gate } 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate /* 634*0Sstevel@tonic-gate * Lookup a uri_desc_t in the URI hash, if found free the request uri_desc_t 635*0Sstevel@tonic-gate * and return the found uri_desc_t with a REF_HOLD() placed on it. Else, use 636*0Sstevel@tonic-gate * the request URI to create a new hash entry. 637*0Sstevel@tonic-gate */ 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate static uri_desc_t * 640*0Sstevel@tonic-gate uri_lookup(uri_desc_t *ruri, boolean_t add, boolean_t nonblocking) 641*0Sstevel@tonic-gate { 642*0Sstevel@tonic-gate uint32_t hash = 0; 643*0Sstevel@tonic-gate uint32_t hix; 644*0Sstevel@tonic-gate uri_hash_t *hp; 645*0Sstevel@tonic-gate uri_desc_t *uri; 646*0Sstevel@tonic-gate uri_desc_t *puri; 647*0Sstevel@tonic-gate uint32_t cur; 648*0Sstevel@tonic-gate uint32_t new; 649*0Sstevel@tonic-gate char *rcp = ruri->path.cp; 650*0Sstevel@tonic-gate char *rep = ruri->path.ep; 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate /* Calculate hash for request path */ 653*0Sstevel@tonic-gate URI_HASH(hash, rcp, rep); 654*0Sstevel@tonic-gate if (ruri->auth.cp != NULL) { 655*0Sstevel@tonic-gate /* Calculate hash for request authority */ 656*0Sstevel@tonic-gate URI_HASH(hash, ruri->auth.cp, ruri->auth.ep); 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate again: 659*0Sstevel@tonic-gate rw_enter(&uri_hash_access, RW_READER); 660*0Sstevel@tonic-gate cur = uri_hash_which; 661*0Sstevel@tonic-gate new = cur ? 0 : 1; 662*0Sstevel@tonic-gate nexthash: 663*0Sstevel@tonic-gate puri = NULL; 664*0Sstevel@tonic-gate hix = hash; 665*0Sstevel@tonic-gate URI_HASH_IX(hix, uri_hash_sz[cur]); 666*0Sstevel@tonic-gate hp = &uri_hash_ab[cur][hix]; 667*0Sstevel@tonic-gate mutex_enter(&hp->lock); 668*0Sstevel@tonic-gate for (uri = hp->list; uri != NULL; uri = uri->hash) { 669*0Sstevel@tonic-gate char *ap = uri->path.cp; 670*0Sstevel@tonic-gate char *bp = rcp; 671*0Sstevel@tonic-gate char a, b; 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate /* Compare paths */ 674*0Sstevel@tonic-gate while (bp < rep && ap < uri->path.ep) { 675*0Sstevel@tonic-gate if ((a = *ap) == '%') { 676*0Sstevel@tonic-gate /* Escaped hex multichar, convert it */ 677*0Sstevel@tonic-gate H2A(ap, uri->path.ep, a); 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate if ((b = *bp) == '%') { 680*0Sstevel@tonic-gate /* Escaped hex multichar, convert it */ 681*0Sstevel@tonic-gate H2A(bp, rep, b); 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate if (a != b) { 684*0Sstevel@tonic-gate /* Char's don't match */ 685*0Sstevel@tonic-gate goto nexturi; 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate ap++; 688*0Sstevel@tonic-gate bp++; 689*0Sstevel@tonic-gate } 690*0Sstevel@tonic-gate if (bp != rep || ap != uri->path.ep) { 691*0Sstevel@tonic-gate /* Not same length */ 692*0Sstevel@tonic-gate goto nexturi; 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate ap = uri->auth.cp; 695*0Sstevel@tonic-gate bp = ruri->auth.cp; 696*0Sstevel@tonic-gate if (ap != NULL) { 697*0Sstevel@tonic-gate if (bp == NULL) { 698*0Sstevel@tonic-gate /* URI has auth request URI doesn't */ 699*0Sstevel@tonic-gate goto nexturi; 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate while (bp < ruri->auth.ep && ap < uri->auth.ep) { 702*0Sstevel@tonic-gate if ((a = *ap) == '%') { 703*0Sstevel@tonic-gate /* Escaped hex multichar, convert it */ 704*0Sstevel@tonic-gate H2A(ap, uri->path.ep, a); 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate if ((b = *bp) == '%') { 707*0Sstevel@tonic-gate /* Escaped hex multichar, convert it */ 708*0Sstevel@tonic-gate H2A(bp, rep, b); 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate if (a != b) { 711*0Sstevel@tonic-gate /* Char's don't match */ 712*0Sstevel@tonic-gate goto nexturi; 713*0Sstevel@tonic-gate } 714*0Sstevel@tonic-gate ap++; 715*0Sstevel@tonic-gate bp++; 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate if (bp != ruri->auth.ep || ap != uri->auth.ep) { 718*0Sstevel@tonic-gate /* Not same length */ 719*0Sstevel@tonic-gate goto nexturi; 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate } else if (bp != NULL) { 722*0Sstevel@tonic-gate /* URI doesn't have auth and request URI does */ 723*0Sstevel@tonic-gate goto nexturi; 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate if (uri->scheme != NULL) { 726*0Sstevel@tonic-gate if (ruri->scheme == NULL) { 727*0Sstevel@tonic-gate /* 728*0Sstevel@tonic-gate * URI has scheme private qualifiers, 729*0Sstevel@tonic-gate * request URI doesn't. 730*0Sstevel@tonic-gate */ 731*0Sstevel@tonic-gate goto nexturi; 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate if (! nl7c_http_cmp(uri->scheme, ruri->scheme)) { 734*0Sstevel@tonic-gate /* No match */ 735*0Sstevel@tonic-gate goto nexturi; 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate } else if (ruri->scheme != NULL) { 738*0Sstevel@tonic-gate /* 739*0Sstevel@tonic-gate * URI doesn't have scheme private qualifiers, 740*0Sstevel@tonic-gate * request URI does. 741*0Sstevel@tonic-gate */ 742*0Sstevel@tonic-gate goto nexturi; 743*0Sstevel@tonic-gate } 744*0Sstevel@tonic-gate /* 745*0Sstevel@tonic-gate * Have a match, check for expire or request no cache. 746*0Sstevel@tonic-gate */ 747*0Sstevel@tonic-gate if (uri->expire >= 0 && uri->expire <= lbolt || ruri->nocache) { 748*0Sstevel@tonic-gate /* 749*0Sstevel@tonic-gate * URI has expired or request specified to not use 750*0Sstevel@tonic-gate * the cached version, unlink the URI from the hash 751*0Sstevel@tonic-gate * chain, release all locks, release the hash ref 752*0Sstevel@tonic-gate * on the URI, and last look it up again. 753*0Sstevel@tonic-gate */ 754*0Sstevel@tonic-gate if (puri != NULL) { 755*0Sstevel@tonic-gate puri->hash = uri->hash; 756*0Sstevel@tonic-gate } else { 757*0Sstevel@tonic-gate hp->list = uri->hash; 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate mutex_exit(&hp->lock); 760*0Sstevel@tonic-gate atomic_add_32(&uri_hash_cnt[cur], -1); 761*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 762*0Sstevel@tonic-gate nl7c_uri_expire++; 763*0Sstevel@tonic-gate REF_RELE(uri); 764*0Sstevel@tonic-gate goto again; 765*0Sstevel@tonic-gate } 766*0Sstevel@tonic-gate /* 767*0Sstevel@tonic-gate * Ready URI for return, put a reference hold on the URI, 768*0Sstevel@tonic-gate * if this URI is currently being processed (i.e. filled) 769*0Sstevel@tonic-gate * then wait for the processing to be completed first, free 770*0Sstevel@tonic-gate * up the request URI and return the matched URI. 771*0Sstevel@tonic-gate */ 772*0Sstevel@tonic-gate REF_HOLD(uri); 773*0Sstevel@tonic-gate mutex_enter(&uri->proclock); 774*0Sstevel@tonic-gate if (uri->proc != NULL) { 775*0Sstevel@tonic-gate /* The URI is being processed, wait for completion */ 776*0Sstevel@tonic-gate mutex_exit(&hp->lock); 777*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 778*0Sstevel@tonic-gate if (! nonblocking && 779*0Sstevel@tonic-gate cv_wait_sig(&uri->waiting, &uri->proclock)) { 780*0Sstevel@tonic-gate /* 781*0Sstevel@tonic-gate * URI has been processed but things may 782*0Sstevel@tonic-gate * have changed while we were away so do 783*0Sstevel@tonic-gate * most everything again. 784*0Sstevel@tonic-gate */ 785*0Sstevel@tonic-gate mutex_exit(&uri->proclock); 786*0Sstevel@tonic-gate REF_RELE(uri); 787*0Sstevel@tonic-gate goto again; 788*0Sstevel@tonic-gate } else { 789*0Sstevel@tonic-gate /* 790*0Sstevel@tonic-gate * A nonblocking socket or an interrupted 791*0Sstevel@tonic-gate * cv_wait_sig() in the first case can't 792*0Sstevel@tonic-gate * block waiting for the processing of the 793*0Sstevel@tonic-gate * uri hash hit uri to complete, in both 794*0Sstevel@tonic-gate * cases just return failure to lookup. 795*0Sstevel@tonic-gate */ 796*0Sstevel@tonic-gate mutex_exit(&uri->proclock); 797*0Sstevel@tonic-gate REF_RELE(uri); 798*0Sstevel@tonic-gate REF_RELE(ruri); 799*0Sstevel@tonic-gate return (NULL); 800*0Sstevel@tonic-gate } 801*0Sstevel@tonic-gate } else { 802*0Sstevel@tonic-gate mutex_exit(&uri->proclock); 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate uri->hit++; 805*0Sstevel@tonic-gate mutex_exit(&hp->lock); 806*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 807*0Sstevel@tonic-gate REF_RELE(ruri); 808*0Sstevel@tonic-gate return (uri); 809*0Sstevel@tonic-gate nexturi: 810*0Sstevel@tonic-gate puri = uri; 811*0Sstevel@tonic-gate } 812*0Sstevel@tonic-gate mutex_exit(&hp->lock); 813*0Sstevel@tonic-gate if (cur != new && uri_hash_ab[new] != NULL) { 814*0Sstevel@tonic-gate /* 815*0Sstevel@tonic-gate * Not found in current hash and have a new hash so 816*0Sstevel@tonic-gate * check the new hash next. 817*0Sstevel@tonic-gate */ 818*0Sstevel@tonic-gate cur = new; 819*0Sstevel@tonic-gate goto nexthash; 820*0Sstevel@tonic-gate } 821*0Sstevel@tonic-gate add: 822*0Sstevel@tonic-gate if (! add) { 823*0Sstevel@tonic-gate /* 824*0Sstevel@tonic-gate * Lookup only so free the 825*0Sstevel@tonic-gate * request URI and return. 826*0Sstevel@tonic-gate */ 827*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 828*0Sstevel@tonic-gate REF_RELE(ruri); 829*0Sstevel@tonic-gate return (NULL); 830*0Sstevel@tonic-gate } 831*0Sstevel@tonic-gate /* 832*0Sstevel@tonic-gate * URI not hashed, finish intialization of the 833*0Sstevel@tonic-gate * request URI, add it to the hash, return it. 834*0Sstevel@tonic-gate */ 835*0Sstevel@tonic-gate ruri->hit = 0; 836*0Sstevel@tonic-gate ruri->expire = -1; 837*0Sstevel@tonic-gate ruri->response.sz = 0; 838*0Sstevel@tonic-gate cv_init(&ruri->waiting, NULL, CV_DEFAULT, NULL); 839*0Sstevel@tonic-gate mutex_init(&ruri->proclock, NULL, MUTEX_DEFAULT, NULL); 840*0Sstevel@tonic-gate uri_add(ruri, RW_READER, nonblocking); 841*0Sstevel@tonic-gate /* uri_add() has done rw_exit(&uri_hash_access) */ 842*0Sstevel@tonic-gate return (ruri); 843*0Sstevel@tonic-gate } 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate /* 846*0Sstevel@tonic-gate * Reclaim URIs until max cache size threshold has been reached. 847*0Sstevel@tonic-gate * 848*0Sstevel@tonic-gate * A CLOCK based reclaim modified with a history (hit counter) counter. 849*0Sstevel@tonic-gate */ 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate static void 852*0Sstevel@tonic-gate nl7c_uri_reclaim(void) 853*0Sstevel@tonic-gate { 854*0Sstevel@tonic-gate uri_hash_t *hp, *start, *pend; 855*0Sstevel@tonic-gate uri_desc_t *uri; 856*0Sstevel@tonic-gate uri_desc_t *puri; 857*0Sstevel@tonic-gate uint32_t cur; 858*0Sstevel@tonic-gate uint32_t new; 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate nl7c_uri_reclaim_calls++; 861*0Sstevel@tonic-gate again: 862*0Sstevel@tonic-gate rw_enter(&uri_hash_access, RW_WRITER); 863*0Sstevel@tonic-gate cur = uri_hash_which; 864*0Sstevel@tonic-gate new = cur ? 0 : 1; 865*0Sstevel@tonic-gate next: 866*0Sstevel@tonic-gate hp = uri_hash_lru[cur]; 867*0Sstevel@tonic-gate start = hp; 868*0Sstevel@tonic-gate pend = &uri_hash_ab[cur][uri_hash_sz[cur]]; 869*0Sstevel@tonic-gate while (nl7c_uri_bytes > nl7c_uri_max) { 870*0Sstevel@tonic-gate puri = NULL; 871*0Sstevel@tonic-gate for (uri = hp->list; uri != NULL; uri = uri->hash) { 872*0Sstevel@tonic-gate if (uri->hit != 0) { 873*0Sstevel@tonic-gate /* 874*0Sstevel@tonic-gate * Decrement URI activity counter and skip. 875*0Sstevel@tonic-gate */ 876*0Sstevel@tonic-gate uri->hit--; 877*0Sstevel@tonic-gate puri = uri; 878*0Sstevel@tonic-gate continue; 879*0Sstevel@tonic-gate } 880*0Sstevel@tonic-gate if (uri->proc != NULL) { 881*0Sstevel@tonic-gate /* 882*0Sstevel@tonic-gate * Currently being processed by a socket, skip. 883*0Sstevel@tonic-gate */ 884*0Sstevel@tonic-gate continue; 885*0Sstevel@tonic-gate } 886*0Sstevel@tonic-gate /* 887*0Sstevel@tonic-gate * Found a candidate, no hit(s) since added or last 888*0Sstevel@tonic-gate * reclaim pass, unlink from it's hash chain, update 889*0Sstevel@tonic-gate * lru scan pointer, drop lock, ref release it. 890*0Sstevel@tonic-gate */ 891*0Sstevel@tonic-gate URI_HASH_UNLINK(cur, new, hp, puri, uri); 892*0Sstevel@tonic-gate if (cur == uri_hash_which) { 893*0Sstevel@tonic-gate if (++hp == pend) { 894*0Sstevel@tonic-gate /* Wrap pointer */ 895*0Sstevel@tonic-gate hp = uri_hash_ab[cur]; 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate uri_hash_lru[cur] = hp; 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 900*0Sstevel@tonic-gate REF_RELE(uri); 901*0Sstevel@tonic-gate nl7c_uri_reclaim_cnt++; 902*0Sstevel@tonic-gate goto again; 903*0Sstevel@tonic-gate } 904*0Sstevel@tonic-gate if (++hp == pend) { 905*0Sstevel@tonic-gate /* Wrap pointer */ 906*0Sstevel@tonic-gate hp = uri_hash_ab[cur]; 907*0Sstevel@tonic-gate } 908*0Sstevel@tonic-gate if (hp == start) { 909*0Sstevel@tonic-gate if (cur != new && uri_hash_ab[new] != NULL) { 910*0Sstevel@tonic-gate /* 911*0Sstevel@tonic-gate * Done with the current hash and have a 912*0Sstevel@tonic-gate * new hash so check the new hash next. 913*0Sstevel@tonic-gate */ 914*0Sstevel@tonic-gate cur = new; 915*0Sstevel@tonic-gate goto next; 916*0Sstevel@tonic-gate } 917*0Sstevel@tonic-gate } 918*0Sstevel@tonic-gate } 919*0Sstevel@tonic-gate rw_exit(&uri_hash_access); 920*0Sstevel@tonic-gate } 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate /* 923*0Sstevel@tonic-gate * Called for a socket which is being freed prior to close, e.g. errored. 924*0Sstevel@tonic-gate */ 925*0Sstevel@tonic-gate 926*0Sstevel@tonic-gate void 927*0Sstevel@tonic-gate nl7c_urifree(struct sonode *so) 928*0Sstevel@tonic-gate { 929*0Sstevel@tonic-gate uri_desc_t *uri = (uri_desc_t *)so->so_nl7c_uri; 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate so->so_nl7c_uri = NULL; 932*0Sstevel@tonic-gate if (uri->hash != URI_TEMP) { 933*0Sstevel@tonic-gate uri_delete(uri); 934*0Sstevel@tonic-gate mutex_enter(&uri->proclock); 935*0Sstevel@tonic-gate uri->proc = NULL; 936*0Sstevel@tonic-gate if (CV_HAS_WAITERS(&uri->waiting)) { 937*0Sstevel@tonic-gate cv_broadcast(&uri->waiting); 938*0Sstevel@tonic-gate } 939*0Sstevel@tonic-gate mutex_exit(&uri->proclock); 940*0Sstevel@tonic-gate nl7c_uri_free++; 941*0Sstevel@tonic-gate } else { 942*0Sstevel@tonic-gate /* No proclock as uri exclusively owned by so */ 943*0Sstevel@tonic-gate uri->proc = NULL; 944*0Sstevel@tonic-gate nl7c_uri_temp_free++; 945*0Sstevel@tonic-gate } 946*0Sstevel@tonic-gate REF_RELE(uri); 947*0Sstevel@tonic-gate } 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate /* 950*0Sstevel@tonic-gate * Called to copy some application response data. 951*0Sstevel@tonic-gate */ 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate volatile uint64_t nl7c_data_pfail = 0; 954*0Sstevel@tonic-gate volatile uint64_t nl7c_data_ntemp = 0; 955*0Sstevel@tonic-gate volatile uint64_t nl7c_data_ncntl = 0; 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate void 958*0Sstevel@tonic-gate nl7c_data(struct sonode *so, uio_t *uiop) 959*0Sstevel@tonic-gate { 960*0Sstevel@tonic-gate uri_desc_t *uri = (uri_desc_t *)so->so_nl7c_uri; 961*0Sstevel@tonic-gate iovec_t *iovp = uiop->uio_iov; 962*0Sstevel@tonic-gate int resid = uiop->uio_resid; 963*0Sstevel@tonic-gate int sz, len, cnt; 964*0Sstevel@tonic-gate char *alloc; 965*0Sstevel@tonic-gate char *data; 966*0Sstevel@tonic-gate char *bp; 967*0Sstevel@tonic-gate uri_rd_t *rdp; 968*0Sstevel@tonic-gate int error = 0; 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate nl7c_uri_data++; 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate if (uri == NULL) { 973*0Sstevel@tonic-gate /* Socket & NL7C out of sync, disable NL7C */ 974*0Sstevel@tonic-gate so->so_nl7c_flags = 0; 975*0Sstevel@tonic-gate nl7c_uri_NULL1++; 976*0Sstevel@tonic-gate return; 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate if (so->so_nl7c_flags & NL7C_WAITWRITE) 980*0Sstevel@tonic-gate so->so_nl7c_flags &= ~NL7C_WAITWRITE; 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate if (uri->hash == URI_TEMP) { 983*0Sstevel@tonic-gate if (uri->resplen == -1) 984*0Sstevel@tonic-gate sz = MIN(resid, URI_TEMP_PARSE_SZ); 985*0Sstevel@tonic-gate else 986*0Sstevel@tonic-gate sz = 0; 987*0Sstevel@tonic-gate } else { 988*0Sstevel@tonic-gate sz = resid; 989*0Sstevel@tonic-gate } 990*0Sstevel@tonic-gate if (sz > 0) { 991*0Sstevel@tonic-gate alloc = kmem_alloc(sz, KM_SLEEP); 992*0Sstevel@tonic-gate } else { 993*0Sstevel@tonic-gate alloc = NULL; 994*0Sstevel@tonic-gate } 995*0Sstevel@tonic-gate if (uri->hash == URI_TEMP) { 996*0Sstevel@tonic-gate uri->count += resid; 997*0Sstevel@tonic-gate data = alloc; 998*0Sstevel@tonic-gate } else { 999*0Sstevel@tonic-gate URI_RD_ADD(uri, rdp, sz, -1); 1000*0Sstevel@tonic-gate if (rdp == NULL) 1001*0Sstevel@tonic-gate goto fail; 1002*0Sstevel@tonic-gate rdp->data.kmem = alloc; 1003*0Sstevel@tonic-gate data = alloc; 1004*0Sstevel@tonic-gate alloc = NULL; 1005*0Sstevel@tonic-gate } 1006*0Sstevel@tonic-gate bp = data; 1007*0Sstevel@tonic-gate for (len = sz; len > 0; len -= cnt) { 1008*0Sstevel@tonic-gate cnt = MIN(len, iovp->iov_len); 1009*0Sstevel@tonic-gate error = xcopyin(iovp->iov_base, bp, cnt); 1010*0Sstevel@tonic-gate if (error) { 1011*0Sstevel@tonic-gate goto fail; 1012*0Sstevel@tonic-gate } 1013*0Sstevel@tonic-gate bp += cnt; 1014*0Sstevel@tonic-gate iovp++; 1015*0Sstevel@tonic-gate } 1016*0Sstevel@tonic-gate bp = data; 1017*0Sstevel@tonic-gate if (uri->resplen == -1 && 1018*0Sstevel@tonic-gate ! nl7c_http_response(&bp, &bp[sz], uri, so) && 1019*0Sstevel@tonic-gate (bp == NULL || uri->hash != URI_TEMP || uri->resplen == -1)) { 1020*0Sstevel@tonic-gate /* 1021*0Sstevel@tonic-gate * Parse not complete and parse failed or not TEMP 1022*0Sstevel@tonic-gate * partial parse or TEMP partial parse and no resplen. 1023*0Sstevel@tonic-gate */ 1024*0Sstevel@tonic-gate if (bp == NULL) 1025*0Sstevel@tonic-gate nl7c_data_pfail++; 1026*0Sstevel@tonic-gate else if (uri->hash != URI_TEMP) 1027*0Sstevel@tonic-gate nl7c_data_ntemp++; 1028*0Sstevel@tonic-gate else if (uri->resplen == -1) 1029*0Sstevel@tonic-gate nl7c_data_ncntl++; 1030*0Sstevel@tonic-gate goto fail; 1031*0Sstevel@tonic-gate } 1032*0Sstevel@tonic-gate if (uri->resplen != -1 && uri->count >= uri->resplen) { 1033*0Sstevel@tonic-gate /* Got the response data, close the uri */ 1034*0Sstevel@tonic-gate nl7c_close(so); 1035*0Sstevel@tonic-gate } 1036*0Sstevel@tonic-gate if (alloc != NULL) { 1037*0Sstevel@tonic-gate kmem_free(alloc, sz); 1038*0Sstevel@tonic-gate } else { 1039*0Sstevel@tonic-gate atomic_add_64(&nl7c_uri_bytes, sz); 1040*0Sstevel@tonic-gate } 1041*0Sstevel@tonic-gate return; 1042*0Sstevel@tonic-gate 1043*0Sstevel@tonic-gate fail: 1044*0Sstevel@tonic-gate if (alloc != NULL) { 1045*0Sstevel@tonic-gate kmem_free(alloc, sz); 1046*0Sstevel@tonic-gate } 1047*0Sstevel@tonic-gate so->so_nl7c_flags = 0; 1048*0Sstevel@tonic-gate nl7c_urifree(so); 1049*0Sstevel@tonic-gate } 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate /* 1052*0Sstevel@tonic-gate * Called to read data from file "*fp" at offset "*off" of length "*len" 1053*0Sstevel@tonic-gate * for a maximum of "*max_rem" bytes. 1054*0Sstevel@tonic-gate * 1055*0Sstevel@tonic-gate * On success a pointer to the kmem_alloc()ed file data is returned, "*off" 1056*0Sstevel@tonic-gate * and "*len" are updated for the acutal number of bytes read and "*max_rem" 1057*0Sstevel@tonic-gate * is updated with the number of bytes remaining to be read. 1058*0Sstevel@tonic-gate * 1059*0Sstevel@tonic-gate * Else, "NULL" is returned. 1060*0Sstevel@tonic-gate */ 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate static char * 1063*0Sstevel@tonic-gate nl7c_readfile(file_t *fp, u_offset_t *off, int *len, int *max_rem) 1064*0Sstevel@tonic-gate { 1065*0Sstevel@tonic-gate vnode_t *vp = fp->f_vnode; 1066*0Sstevel@tonic-gate int flg = 0; 1067*0Sstevel@tonic-gate size_t size = MIN(*len, *max_rem); 1068*0Sstevel@tonic-gate char *data; 1069*0Sstevel@tonic-gate int error; 1070*0Sstevel@tonic-gate uio_t uio; 1071*0Sstevel@tonic-gate iovec_t iov; 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate (void) VOP_RWLOCK(vp, flg, NULL); 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate if (*off > MAXOFFSET_T) { 1076*0Sstevel@tonic-gate VOP_RWUNLOCK(vp, flg, NULL); 1077*0Sstevel@tonic-gate return (NULL); 1078*0Sstevel@tonic-gate } 1079*0Sstevel@tonic-gate 1080*0Sstevel@tonic-gate if (*off + size > MAXOFFSET_T) 1081*0Sstevel@tonic-gate size = (ssize32_t)(MAXOFFSET_T - *off); 1082*0Sstevel@tonic-gate 1083*0Sstevel@tonic-gate data = kmem_alloc(size, KM_SLEEP); 1084*0Sstevel@tonic-gate 1085*0Sstevel@tonic-gate iov.iov_base = data; 1086*0Sstevel@tonic-gate iov.iov_len = size; 1087*0Sstevel@tonic-gate uio.uio_loffset = *off; 1088*0Sstevel@tonic-gate uio.uio_iov = &iov; 1089*0Sstevel@tonic-gate uio.uio_iovcnt = 1; 1090*0Sstevel@tonic-gate uio.uio_resid = size; 1091*0Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 1092*0Sstevel@tonic-gate uio.uio_llimit = MAXOFFSET_T; 1093*0Sstevel@tonic-gate uio.uio_fmode = fp->f_flag; 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate error = VOP_READ(vp, &uio, fp->f_flag, fp->f_cred, NULL); 1096*0Sstevel@tonic-gate VOP_RWUNLOCK(vp, flg, NULL); 1097*0Sstevel@tonic-gate if (error) { 1098*0Sstevel@tonic-gate kmem_free(data, size); 1099*0Sstevel@tonic-gate return (NULL); 1100*0Sstevel@tonic-gate } 1101*0Sstevel@tonic-gate *max_rem = *len - size; 1102*0Sstevel@tonic-gate *len = size; 1103*0Sstevel@tonic-gate *off += size; 1104*0Sstevel@tonic-gate return (data); 1105*0Sstevel@tonic-gate } 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate /* 1108*0Sstevel@tonic-gate * Called to copy application response sendfilev. 1109*0Sstevel@tonic-gate * 1110*0Sstevel@tonic-gate * Note, the value of kmem_bytes is a segmap max sized value greater 1111*0Sstevel@tonic-gate * than or equal to TCP's tcp_slow_start_initial, there are several 1112*0Sstevel@tonic-gate * issues with this scheme least of which is assuming that TCP is the 1113*0Sstevel@tonic-gate * only IP transport we care about or that we hardcode the TCP value 1114*0Sstevel@tonic-gate * but until ... 1115*0Sstevel@tonic-gate */ 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate void 1118*0Sstevel@tonic-gate nl7c_sendfilev(struct sonode *so, u_offset_t off, sendfilevec_t *sfvp, int sfvc) 1119*0Sstevel@tonic-gate { 1120*0Sstevel@tonic-gate uri_desc_t *uri = (uri_desc_t *)so->so_nl7c_uri; 1121*0Sstevel@tonic-gate file_t *fp = NULL; 1122*0Sstevel@tonic-gate vnode_t *vp = NULL; 1123*0Sstevel@tonic-gate char *data = NULL; 1124*0Sstevel@tonic-gate int len; 1125*0Sstevel@tonic-gate int count; 1126*0Sstevel@tonic-gate int total_count = 0; 1127*0Sstevel@tonic-gate char *bp; 1128*0Sstevel@tonic-gate uri_rd_t *rdp; 1129*0Sstevel@tonic-gate int max_rem; 1130*0Sstevel@tonic-gate int error = 0; 1131*0Sstevel@tonic-gate 1132*0Sstevel@tonic-gate nl7c_uri_sendfilev++; 1133*0Sstevel@tonic-gate 1134*0Sstevel@tonic-gate if (uri == NULL) { 1135*0Sstevel@tonic-gate /* Socket & NL7C out of sync, disable NL7C */ 1136*0Sstevel@tonic-gate so->so_nl7c_flags = 0; 1137*0Sstevel@tonic-gate nl7c_uri_NULL2++; 1138*0Sstevel@tonic-gate return; 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate if (so->so_nl7c_flags & NL7C_WAITWRITE) 1142*0Sstevel@tonic-gate so->so_nl7c_flags &= ~NL7C_WAITWRITE; 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate while (sfvc-- > 0) { 1145*0Sstevel@tonic-gate /* 1146*0Sstevel@tonic-gate * off - the current sfv read file offset or user address. 1147*0Sstevel@tonic-gate * 1148*0Sstevel@tonic-gate * len - the current sfv kmem_alloc()ed buffer length, note 1149*0Sstevel@tonic-gate * may be less than the actual sfv size. 1150*0Sstevel@tonic-gate * 1151*0Sstevel@tonic-gate * count - the actual current sfv size in bytes. 1152*0Sstevel@tonic-gate * 1153*0Sstevel@tonic-gate * data - the kmem_alloc()ed buffer of size "len". 1154*0Sstevel@tonic-gate * 1155*0Sstevel@tonic-gate * fp - the current sfv file_t pointer. 1156*0Sstevel@tonic-gate * 1157*0Sstevel@tonic-gate * vp - the current "*vp" vnode_t pointer. 1158*0Sstevel@tonic-gate * 1159*0Sstevel@tonic-gate * Note, for "data" and "fp" and "vp" a NULL value is used 1160*0Sstevel@tonic-gate * when not allocated such that the common failure path "fail" 1161*0Sstevel@tonic-gate * is used. 1162*0Sstevel@tonic-gate */ 1163*0Sstevel@tonic-gate off = sfvp->sfv_off; 1164*0Sstevel@tonic-gate len = sfvp->sfv_len; 1165*0Sstevel@tonic-gate count = len; 1166*0Sstevel@tonic-gate if (uri->hash == URI_TEMP) { 1167*0Sstevel@tonic-gate if (uri->resplen == -1) 1168*0Sstevel@tonic-gate len = MIN(len, URI_TEMP_PARSE_SZ); 1169*0Sstevel@tonic-gate else 1170*0Sstevel@tonic-gate len = 0; 1171*0Sstevel@tonic-gate } 1172*0Sstevel@tonic-gate if (len == 0) { 1173*0Sstevel@tonic-gate /* 1174*0Sstevel@tonic-gate * TEMP uri with no data to sink, just count bytes. 1175*0Sstevel@tonic-gate */ 1176*0Sstevel@tonic-gate uri->count += count; 1177*0Sstevel@tonic-gate } else if (sfvp->sfv_fd == SFV_FD_SELF) { 1178*0Sstevel@tonic-gate /* 1179*0Sstevel@tonic-gate * Process user memory, copyin(). 1180*0Sstevel@tonic-gate */ 1181*0Sstevel@tonic-gate data = kmem_alloc(len, KM_SLEEP); 1182*0Sstevel@tonic-gate 1183*0Sstevel@tonic-gate error = xcopyin((caddr_t)(uintptr_t)off, data, len); 1184*0Sstevel@tonic-gate if (error) 1185*0Sstevel@tonic-gate goto fail; 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate bp = data; 1188*0Sstevel@tonic-gate if (uri->resplen == -1 && 1189*0Sstevel@tonic-gate ! nl7c_http_response(&bp, &bp[len], uri, so) && 1190*0Sstevel@tonic-gate (bp == NULL || uri->hash != URI_TEMP || 1191*0Sstevel@tonic-gate (uri->hash == URI_TEMP && uri->resplen == -1))) { 1192*0Sstevel@tonic-gate /* 1193*0Sstevel@tonic-gate * Parse not complete and parse failed or 1194*0Sstevel@tonic-gate * not TEMP partial parse or TEMP partial 1195*0Sstevel@tonic-gate * parse and no resplen. 1196*0Sstevel@tonic-gate */ 1197*0Sstevel@tonic-gate goto fail; 1198*0Sstevel@tonic-gate } 1199*0Sstevel@tonic-gate 1200*0Sstevel@tonic-gate if (uri->hash == URI_TEMP) { 1201*0Sstevel@tonic-gate uri->count += len; 1202*0Sstevel@tonic-gate kmem_free(data, len); 1203*0Sstevel@tonic-gate data = NULL; 1204*0Sstevel@tonic-gate } else { 1205*0Sstevel@tonic-gate URI_RD_ADD(uri, rdp, len, -1); 1206*0Sstevel@tonic-gate if (rdp == NULL) 1207*0Sstevel@tonic-gate goto fail; 1208*0Sstevel@tonic-gate rdp->data.kmem = data; 1209*0Sstevel@tonic-gate data = NULL; 1210*0Sstevel@tonic-gate total_count += len; 1211*0Sstevel@tonic-gate } 1212*0Sstevel@tonic-gate } else { 1213*0Sstevel@tonic-gate /* 1214*0Sstevel@tonic-gate * File descriptor, prefetch some bytes, 1215*0Sstevel@tonic-gate * save vnode_t if any bytes left. 1216*0Sstevel@tonic-gate */ 1217*0Sstevel@tonic-gate if ((fp = getf(sfvp->sfv_fd)) == NULL) 1218*0Sstevel@tonic-gate goto fail; 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate if ((fp->f_flag & FREAD) == 0) 1221*0Sstevel@tonic-gate goto fail; 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate vp = fp->f_vnode; 1224*0Sstevel@tonic-gate if (vp->v_type != VREG) 1225*0Sstevel@tonic-gate goto fail; 1226*0Sstevel@tonic-gate VN_HOLD(vp); 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate /* Read max_rem bytes from file for prefetch */ 1229*0Sstevel@tonic-gate if (nl7c_use_kmem) { 1230*0Sstevel@tonic-gate max_rem = len; 1231*0Sstevel@tonic-gate } else { 1232*0Sstevel@tonic-gate max_rem = MAXBSIZE * nl7c_file_prefetch; 1233*0Sstevel@tonic-gate } 1234*0Sstevel@tonic-gate data = nl7c_readfile(fp, &off, &len, &max_rem); 1235*0Sstevel@tonic-gate if (data == NULL) 1236*0Sstevel@tonic-gate goto fail; 1237*0Sstevel@tonic-gate 1238*0Sstevel@tonic-gate releasef(sfvp->sfv_fd); 1239*0Sstevel@tonic-gate fp = NULL; 1240*0Sstevel@tonic-gate 1241*0Sstevel@tonic-gate bp = data; 1242*0Sstevel@tonic-gate if (uri->resplen == -1 && 1243*0Sstevel@tonic-gate ! nl7c_http_response(&bp, &bp[len], uri, so) && 1244*0Sstevel@tonic-gate (bp == NULL || uri->hash != URI_TEMP || 1245*0Sstevel@tonic-gate uri->resplen == -1)) { 1246*0Sstevel@tonic-gate /* 1247*0Sstevel@tonic-gate * Parse not complete and parse failed or 1248*0Sstevel@tonic-gate * not TEMP partial parse or TEMP partial 1249*0Sstevel@tonic-gate * parse and no resplen. 1250*0Sstevel@tonic-gate */ 1251*0Sstevel@tonic-gate goto fail; 1252*0Sstevel@tonic-gate } 1253*0Sstevel@tonic-gate 1254*0Sstevel@tonic-gate if (uri->hash == URI_TEMP) { 1255*0Sstevel@tonic-gate /* 1256*0Sstevel@tonic-gate * Temp uri, account for all sfv bytes and 1257*0Sstevel@tonic-gate * free up any resources allocated above. 1258*0Sstevel@tonic-gate */ 1259*0Sstevel@tonic-gate uri->count += count; 1260*0Sstevel@tonic-gate kmem_free(data, len); 1261*0Sstevel@tonic-gate data = NULL; 1262*0Sstevel@tonic-gate VN_RELE(vp); 1263*0Sstevel@tonic-gate vp = NULL; 1264*0Sstevel@tonic-gate } else { 1265*0Sstevel@tonic-gate /* 1266*0Sstevel@tonic-gate * Setup an uri_rd_t for the prefetch and 1267*0Sstevel@tonic-gate * if any sfv data remains setup an another 1268*0Sstevel@tonic-gate * uri_rd_t to map it, last free up any 1269*0Sstevel@tonic-gate * resources allocated above. 1270*0Sstevel@tonic-gate */ 1271*0Sstevel@tonic-gate URI_RD_ADD(uri, rdp, len, -1); 1272*0Sstevel@tonic-gate if (rdp == NULL) 1273*0Sstevel@tonic-gate goto fail; 1274*0Sstevel@tonic-gate rdp->data.kmem = data; 1275*0Sstevel@tonic-gate data = NULL; 1276*0Sstevel@tonic-gate if (max_rem > 0) { 1277*0Sstevel@tonic-gate /* More file data so add it */ 1278*0Sstevel@tonic-gate URI_RD_ADD(uri, rdp, max_rem, off); 1279*0Sstevel@tonic-gate if (rdp == NULL) 1280*0Sstevel@tonic-gate goto fail; 1281*0Sstevel@tonic-gate rdp->data.vnode = vp; 1282*0Sstevel@tonic-gate } else { 1283*0Sstevel@tonic-gate /* All file data fit in the prefetch */ 1284*0Sstevel@tonic-gate VN_RELE(vp); 1285*0Sstevel@tonic-gate } 1286*0Sstevel@tonic-gate vp = NULL; 1287*0Sstevel@tonic-gate /* Only account for the kmem_alloc()ed bytes */ 1288*0Sstevel@tonic-gate total_count += len; 1289*0Sstevel@tonic-gate } 1290*0Sstevel@tonic-gate } 1291*0Sstevel@tonic-gate sfvp++; 1292*0Sstevel@tonic-gate } 1293*0Sstevel@tonic-gate if (total_count > 0) { 1294*0Sstevel@tonic-gate atomic_add_64(&nl7c_uri_bytes, total_count); 1295*0Sstevel@tonic-gate } 1296*0Sstevel@tonic-gate if (uri->resplen != -1 && uri->count >= uri->resplen) { 1297*0Sstevel@tonic-gate /* Got the response data, close the uri */ 1298*0Sstevel@tonic-gate nl7c_close(so); 1299*0Sstevel@tonic-gate } 1300*0Sstevel@tonic-gate return; 1301*0Sstevel@tonic-gate 1302*0Sstevel@tonic-gate fail: 1303*0Sstevel@tonic-gate if (data != NULL) 1304*0Sstevel@tonic-gate kmem_free(data, len); 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate if (vp != NULL) 1307*0Sstevel@tonic-gate VN_RELE(vp); 1308*0Sstevel@tonic-gate 1309*0Sstevel@tonic-gate if (fp != NULL) 1310*0Sstevel@tonic-gate releasef(sfvp->sfv_fd); 1311*0Sstevel@tonic-gate 1312*0Sstevel@tonic-gate if (total_count > 0) { 1313*0Sstevel@tonic-gate atomic_add_64(&nl7c_uri_bytes, total_count); 1314*0Sstevel@tonic-gate } 1315*0Sstevel@tonic-gate so->so_nl7c_flags = 0; 1316*0Sstevel@tonic-gate nl7c_urifree(so); 1317*0Sstevel@tonic-gate } 1318*0Sstevel@tonic-gate 1319*0Sstevel@tonic-gate /* 1320*0Sstevel@tonic-gate * Called for a socket which is closing or when an application has 1321*0Sstevel@tonic-gate * completed sending all the response data (i.e. for a persistent 1322*0Sstevel@tonic-gate * connection called once for each completed application response). 1323*0Sstevel@tonic-gate */ 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate void 1326*0Sstevel@tonic-gate nl7c_close(struct sonode *so) 1327*0Sstevel@tonic-gate { 1328*0Sstevel@tonic-gate uri_desc_t *uri = (uri_desc_t *)so->so_nl7c_uri; 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate if (uri == NULL) { 1331*0Sstevel@tonic-gate /* 1332*0Sstevel@tonic-gate * No URI being processed so might be a listen()er 1333*0Sstevel@tonic-gate * if so do any cleanup, else nothing more to do. 1334*0Sstevel@tonic-gate */ 1335*0Sstevel@tonic-gate if (so->so_state & SS_ACCEPTCONN) { 1336*0Sstevel@tonic-gate (void) nl7c_close_addr(so); 1337*0Sstevel@tonic-gate } 1338*0Sstevel@tonic-gate return; 1339*0Sstevel@tonic-gate } 1340*0Sstevel@tonic-gate so->so_nl7c_uri = NULL; 1341*0Sstevel@tonic-gate if (uri->hash != URI_TEMP) { 1342*0Sstevel@tonic-gate mutex_enter(&uri->proclock); 1343*0Sstevel@tonic-gate uri->proc = NULL; 1344*0Sstevel@tonic-gate if (CV_HAS_WAITERS(&uri->waiting)) { 1345*0Sstevel@tonic-gate cv_broadcast(&uri->waiting); 1346*0Sstevel@tonic-gate } 1347*0Sstevel@tonic-gate mutex_exit(&uri->proclock); 1348*0Sstevel@tonic-gate nl7c_uri_close++; 1349*0Sstevel@tonic-gate } else { 1350*0Sstevel@tonic-gate /* No proclock as uri exclusively owned by so */ 1351*0Sstevel@tonic-gate uri->proc = NULL; 1352*0Sstevel@tonic-gate nl7c_uri_temp_close++; 1353*0Sstevel@tonic-gate } 1354*0Sstevel@tonic-gate REF_RELE(uri); 1355*0Sstevel@tonic-gate if (nl7c_uri_max > 0 && nl7c_uri_bytes > nl7c_uri_max) { 1356*0Sstevel@tonic-gate nl7c_uri_reclaim(); 1357*0Sstevel@tonic-gate } 1358*0Sstevel@tonic-gate } 1359*0Sstevel@tonic-gate 1360*0Sstevel@tonic-gate /* 1361*0Sstevel@tonic-gate * The uri_segmap_t ref_t inactive function called on the last REF_RELE(), 1362*0Sstevel@tonic-gate * release the segmap mapping. Note, the uri_segmap_t will be freed by 1363*0Sstevel@tonic-gate * REF_RELE() on return. 1364*0Sstevel@tonic-gate */ 1365*0Sstevel@tonic-gate 1366*0Sstevel@tonic-gate void 1367*0Sstevel@tonic-gate uri_segmap_inactive(uri_segmap_t *smp) 1368*0Sstevel@tonic-gate { 1369*0Sstevel@tonic-gate if (!segmap_kpm) { 1370*0Sstevel@tonic-gate (void) segmap_fault(kas.a_hat, segkmap, smp->base, 1371*0Sstevel@tonic-gate smp->len, F_SOFTUNLOCK, S_OTHER); 1372*0Sstevel@tonic-gate } 1373*0Sstevel@tonic-gate (void) segmap_release(segkmap, smp->base, SM_DONTNEED); 1374*0Sstevel@tonic-gate VN_RELE(smp->vp); 1375*0Sstevel@tonic-gate } 1376*0Sstevel@tonic-gate 1377*0Sstevel@tonic-gate /* 1378*0Sstevel@tonic-gate * The call-back for desballoc()ed mblk_t's, if a segmap mapped mblk_t 1379*0Sstevel@tonic-gate * release the reference, one per deballoc() of a segmap page, release 1380*0Sstevel@tonic-gate * the reference of the URI containing the uri_rd_t, last free kmem 1381*0Sstevel@tonic-gate * free the uri_desb_t. 1382*0Sstevel@tonic-gate */ 1383*0Sstevel@tonic-gate 1384*0Sstevel@tonic-gate static void 1385*0Sstevel@tonic-gate uri_desb_free(uri_desb_t *desb) 1386*0Sstevel@tonic-gate { 1387*0Sstevel@tonic-gate if (desb->segmap != NULL) { 1388*0Sstevel@tonic-gate REF_RELE(desb->segmap); 1389*0Sstevel@tonic-gate } 1390*0Sstevel@tonic-gate REF_RELE(desb->uri); 1391*0Sstevel@tonic-gate kmem_cache_free(uri_desb_kmc, desb); 1392*0Sstevel@tonic-gate } 1393*0Sstevel@tonic-gate 1394*0Sstevel@tonic-gate /* 1395*0Sstevel@tonic-gate * Segmap map up to a page of a uri_rd_t file descriptor. 1396*0Sstevel@tonic-gate */ 1397*0Sstevel@tonic-gate 1398*0Sstevel@tonic-gate uri_segmap_t * 1399*0Sstevel@tonic-gate uri_segmap_map(uri_rd_t *rdp, int bytes) 1400*0Sstevel@tonic-gate { 1401*0Sstevel@tonic-gate uri_segmap_t *segmap = kmem_cache_alloc(uri_segmap_kmc, KM_SLEEP); 1402*0Sstevel@tonic-gate int len = MIN(rdp->sz, MAXBSIZE); 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate if (len > bytes) 1405*0Sstevel@tonic-gate len = bytes; 1406*0Sstevel@tonic-gate 1407*0Sstevel@tonic-gate REF_INIT(segmap, 1, uri_segmap_inactive, uri_segmap_kmc); 1408*0Sstevel@tonic-gate segmap->len = len; 1409*0Sstevel@tonic-gate VN_HOLD(rdp->data.vnode); 1410*0Sstevel@tonic-gate segmap->vp = rdp->data.vnode; 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gate segmap->base = segmap_getmapflt(segkmap, segmap->vp, rdp->off, len, 1413*0Sstevel@tonic-gate segmap_kpm ? SM_FAULT : 0, S_READ); 1414*0Sstevel@tonic-gate 1415*0Sstevel@tonic-gate if (segmap_fault(kas.a_hat, segkmap, segmap->base, len, 1416*0Sstevel@tonic-gate F_SOFTLOCK, S_READ) != 0) { 1417*0Sstevel@tonic-gate REF_RELE(segmap); 1418*0Sstevel@tonic-gate return (NULL); 1419*0Sstevel@tonic-gate } 1420*0Sstevel@tonic-gate return (segmap); 1421*0Sstevel@tonic-gate } 1422*0Sstevel@tonic-gate 1423*0Sstevel@tonic-gate /* 1424*0Sstevel@tonic-gate * Chop up the kernel virtual memory area *data of size *sz bytes for 1425*0Sstevel@tonic-gate * a maximum of *bytes bytes into an besballoc()ed mblk_t chain using 1426*0Sstevel@tonic-gate * the given template uri_desb_t *temp of max_mblk bytes per. 1427*0Sstevel@tonic-gate * 1428*0Sstevel@tonic-gate * The values of *data, *sz, and *bytes are updated on return, the 1429*0Sstevel@tonic-gate * mblk_t chain is returned. 1430*0Sstevel@tonic-gate */ 1431*0Sstevel@tonic-gate 1432*0Sstevel@tonic-gate static mblk_t * 1433*0Sstevel@tonic-gate uri_desb_chop( 1434*0Sstevel@tonic-gate char **data, 1435*0Sstevel@tonic-gate size_t *sz, 1436*0Sstevel@tonic-gate int *bytes, 1437*0Sstevel@tonic-gate uri_desb_t *temp, 1438*0Sstevel@tonic-gate int max_mblk, 1439*0Sstevel@tonic-gate char *eoh, 1440*0Sstevel@tonic-gate mblk_t *persist 1441*0Sstevel@tonic-gate ) 1442*0Sstevel@tonic-gate { 1443*0Sstevel@tonic-gate char *ldata = *data; 1444*0Sstevel@tonic-gate size_t lsz = *sz; 1445*0Sstevel@tonic-gate int lbytes = bytes ? *bytes : lsz; 1446*0Sstevel@tonic-gate uri_desb_t *desb; 1447*0Sstevel@tonic-gate mblk_t *mp = NULL; 1448*0Sstevel@tonic-gate mblk_t *nmp, *tmp, *pmp = NULL; 1449*0Sstevel@tonic-gate int msz; 1450*0Sstevel@tonic-gate 1451*0Sstevel@tonic-gate if (lbytes == 0 && lsz == 0) 1452*0Sstevel@tonic-gate return (NULL); 1453*0Sstevel@tonic-gate 1454*0Sstevel@tonic-gate while (lbytes > 0 && lsz > 0) { 1455*0Sstevel@tonic-gate msz = MIN(lbytes, max_mblk); 1456*0Sstevel@tonic-gate msz = MIN(msz, lsz); 1457*0Sstevel@tonic-gate if (persist && eoh >= ldata && eoh < &ldata[msz]) { 1458*0Sstevel@tonic-gate msz = (eoh - ldata); 1459*0Sstevel@tonic-gate pmp = persist; 1460*0Sstevel@tonic-gate persist = NULL; 1461*0Sstevel@tonic-gate } 1462*0Sstevel@tonic-gate desb = kmem_cache_alloc(uri_desb_kmc, KM_SLEEP); 1463*0Sstevel@tonic-gate REF_HOLD(temp->uri); 1464*0Sstevel@tonic-gate if (temp->segmap) { 1465*0Sstevel@tonic-gate REF_HOLD(temp->segmap); 1466*0Sstevel@tonic-gate } 1467*0Sstevel@tonic-gate bcopy(temp, desb, sizeof (*desb)); 1468*0Sstevel@tonic-gate desb->frtn.free_arg = (caddr_t)desb; 1469*0Sstevel@tonic-gate nmp = desballoc((uchar_t *)ldata, msz, BPRI_HI, &desb->frtn); 1470*0Sstevel@tonic-gate if (nmp == NULL) { 1471*0Sstevel@tonic-gate if (temp->segmap) { 1472*0Sstevel@tonic-gate REF_RELE(temp->segmap); 1473*0Sstevel@tonic-gate } 1474*0Sstevel@tonic-gate REF_RELE(temp->uri); 1475*0Sstevel@tonic-gate if (mp != NULL) { 1476*0Sstevel@tonic-gate freemsg(mp); 1477*0Sstevel@tonic-gate } 1478*0Sstevel@tonic-gate return (NULL); 1479*0Sstevel@tonic-gate } 1480*0Sstevel@tonic-gate nmp->b_wptr += msz; 1481*0Sstevel@tonic-gate if (mp != NULL) { 1482*0Sstevel@tonic-gate /*LINTED*/ 1483*0Sstevel@tonic-gate ASSERT(tmp->b_cont == NULL); 1484*0Sstevel@tonic-gate /*LINTED*/ 1485*0Sstevel@tonic-gate tmp->b_cont = nmp; 1486*0Sstevel@tonic-gate } else { 1487*0Sstevel@tonic-gate mp = nmp; 1488*0Sstevel@tonic-gate } 1489*0Sstevel@tonic-gate tmp = nmp; 1490*0Sstevel@tonic-gate ldata += msz; 1491*0Sstevel@tonic-gate lsz -= msz; 1492*0Sstevel@tonic-gate lbytes -= msz; 1493*0Sstevel@tonic-gate if (pmp) { 1494*0Sstevel@tonic-gate tmp->b_cont = pmp; 1495*0Sstevel@tonic-gate tmp = pmp; 1496*0Sstevel@tonic-gate pmp = NULL; 1497*0Sstevel@tonic-gate } 1498*0Sstevel@tonic-gate } 1499*0Sstevel@tonic-gate *data = ldata; 1500*0Sstevel@tonic-gate *sz = lsz; 1501*0Sstevel@tonic-gate if (bytes) 1502*0Sstevel@tonic-gate *bytes = lbytes; 1503*0Sstevel@tonic-gate mp->b_next = tmp; 1504*0Sstevel@tonic-gate return (mp); 1505*0Sstevel@tonic-gate } 1506*0Sstevel@tonic-gate 1507*0Sstevel@tonic-gate /* 1508*0Sstevel@tonic-gate * Experimential noqwait (i.e. no canput()/qwait() checks), just send 1509*0Sstevel@tonic-gate * the entire mblk_t chain down without flow-control checks. 1510*0Sstevel@tonic-gate */ 1511*0Sstevel@tonic-gate 1512*0Sstevel@tonic-gate static int 1513*0Sstevel@tonic-gate kstrwritempnoqwait(struct vnode *vp, mblk_t *mp) 1514*0Sstevel@tonic-gate { 1515*0Sstevel@tonic-gate struct stdata *stp; 1516*0Sstevel@tonic-gate int error = 0; 1517*0Sstevel@tonic-gate 1518*0Sstevel@tonic-gate ASSERT(vp->v_stream); 1519*0Sstevel@tonic-gate stp = vp->v_stream; 1520*0Sstevel@tonic-gate 1521*0Sstevel@tonic-gate /* Fast check of flags before acquiring the lock */ 1522*0Sstevel@tonic-gate if (stp->sd_flag & (STWRERR|STRHUP|STPLEX)) { 1523*0Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 1524*0Sstevel@tonic-gate error = strgeterr(stp, STWRERR|STRHUP|STPLEX, 0); 1525*0Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 1526*0Sstevel@tonic-gate if (error != 0) { 1527*0Sstevel@tonic-gate if (!(stp->sd_flag & STPLEX) && 1528*0Sstevel@tonic-gate (stp->sd_wput_opt & SW_SIGPIPE)) { 1529*0Sstevel@tonic-gate tsignal(curthread, SIGPIPE); 1530*0Sstevel@tonic-gate error = EPIPE; 1531*0Sstevel@tonic-gate } 1532*0Sstevel@tonic-gate return (error); 1533*0Sstevel@tonic-gate } 1534*0Sstevel@tonic-gate } 1535*0Sstevel@tonic-gate putnext(stp->sd_wrq, mp); 1536*0Sstevel@tonic-gate return (0); 1537*0Sstevel@tonic-gate } 1538*0Sstevel@tonic-gate 1539*0Sstevel@tonic-gate /* 1540*0Sstevel@tonic-gate * Send the URI response uri_desc_t *uri out the socket_t *so. 1541*0Sstevel@tonic-gate */ 1542*0Sstevel@tonic-gate 1543*0Sstevel@tonic-gate static void 1544*0Sstevel@tonic-gate uri_response(struct sonode *so, uri_desc_t *uri, int max_mblk) 1545*0Sstevel@tonic-gate { 1546*0Sstevel@tonic-gate uri_rd_t *rdp = &uri->response; 1547*0Sstevel@tonic-gate vnode_t *vp = SOTOV(so); 1548*0Sstevel@tonic-gate int wsz; 1549*0Sstevel@tonic-gate mblk_t *mp, *wmp, *persist; 1550*0Sstevel@tonic-gate int write_bytes; 1551*0Sstevel@tonic-gate uri_rd_t rd = {0}; 1552*0Sstevel@tonic-gate uri_desb_t desb; 1553*0Sstevel@tonic-gate uri_segmap_t *segmap = NULL; 1554*0Sstevel@tonic-gate char *segmap_data; 1555*0Sstevel@tonic-gate size_t segmap_sz; 1556*0Sstevel@tonic-gate boolean_t first = B_TRUE; 1557*0Sstevel@tonic-gate 1558*0Sstevel@tonic-gate /* For first kstrwrite() enough data to get things going */ 1559*0Sstevel@tonic-gate write_bytes = P2ROUNDUP((max_mblk * 4), MAXBSIZE * nl7c_file_prefetch); 1560*0Sstevel@tonic-gate 1561*0Sstevel@tonic-gate /* Initialize template uri_desb_t */ 1562*0Sstevel@tonic-gate desb.frtn.free_func = uri_desb_free; 1563*0Sstevel@tonic-gate desb.frtn.free_arg = NULL; 1564*0Sstevel@tonic-gate desb.uri = uri; 1565*0Sstevel@tonic-gate 1566*0Sstevel@tonic-gate do { 1567*0Sstevel@tonic-gate wmp = NULL; 1568*0Sstevel@tonic-gate wsz = write_bytes; 1569*0Sstevel@tonic-gate do { 1570*0Sstevel@tonic-gate if (rd.sz == 0) { 1571*0Sstevel@tonic-gate bcopy(rdp, &rd, sizeof (rd)); 1572*0Sstevel@tonic-gate rdp = rdp->next; 1573*0Sstevel@tonic-gate } 1574*0Sstevel@tonic-gate if (rd.off == -1) { 1575*0Sstevel@tonic-gate if (uri->eoh >= rd.data.kmem && 1576*0Sstevel@tonic-gate uri->eoh < &rd.data.kmem[rd.sz]) { 1577*0Sstevel@tonic-gate persist = nl7c_http_persist(so); 1578*0Sstevel@tonic-gate } else { 1579*0Sstevel@tonic-gate persist = NULL; 1580*0Sstevel@tonic-gate } 1581*0Sstevel@tonic-gate desb.segmap = NULL; 1582*0Sstevel@tonic-gate mp = uri_desb_chop(&rd.data.kmem, &rd.sz, 1583*0Sstevel@tonic-gate &wsz, &desb, max_mblk, uri->eoh, persist); 1584*0Sstevel@tonic-gate if (mp == NULL) 1585*0Sstevel@tonic-gate goto invalidate; 1586*0Sstevel@tonic-gate } else { 1587*0Sstevel@tonic-gate if (segmap == NULL) { 1588*0Sstevel@tonic-gate segmap = uri_segmap_map(&rd, 1589*0Sstevel@tonic-gate write_bytes); 1590*0Sstevel@tonic-gate if (segmap == NULL) 1591*0Sstevel@tonic-gate goto invalidate; 1592*0Sstevel@tonic-gate desb.segmap = segmap; 1593*0Sstevel@tonic-gate segmap_data = segmap->base; 1594*0Sstevel@tonic-gate segmap_sz = segmap->len; 1595*0Sstevel@tonic-gate } 1596*0Sstevel@tonic-gate mp = uri_desb_chop(&segmap_data, &segmap_sz, 1597*0Sstevel@tonic-gate &wsz, &desb, max_mblk, NULL, NULL); 1598*0Sstevel@tonic-gate if (mp == NULL) 1599*0Sstevel@tonic-gate goto invalidate; 1600*0Sstevel@tonic-gate if (segmap_sz == 0) { 1601*0Sstevel@tonic-gate rd.sz -= segmap->len; 1602*0Sstevel@tonic-gate rd.off += segmap->len; 1603*0Sstevel@tonic-gate REF_RELE(segmap); 1604*0Sstevel@tonic-gate segmap = NULL; 1605*0Sstevel@tonic-gate } 1606*0Sstevel@tonic-gate } 1607*0Sstevel@tonic-gate if (wmp == NULL) { 1608*0Sstevel@tonic-gate wmp = mp; 1609*0Sstevel@tonic-gate } else { 1610*0Sstevel@tonic-gate wmp->b_next->b_cont = mp; 1611*0Sstevel@tonic-gate wmp->b_next = mp->b_next; 1612*0Sstevel@tonic-gate mp->b_next = NULL; 1613*0Sstevel@tonic-gate } 1614*0Sstevel@tonic-gate } while (wsz > 0 && (rd.sz > 0 || rdp != NULL)); 1615*0Sstevel@tonic-gate 1616*0Sstevel@tonic-gate wmp->b_next = NULL; 1617*0Sstevel@tonic-gate if (first) { 1618*0Sstevel@tonic-gate /* First kstrwrite(), use noqwait */ 1619*0Sstevel@tonic-gate if (kstrwritempnoqwait(vp, wmp) != 0) 1620*0Sstevel@tonic-gate goto invalidate; 1621*0Sstevel@tonic-gate /* 1622*0Sstevel@tonic-gate * For the rest of the kstrwrite()s use SO_SNDBUF 1623*0Sstevel@tonic-gate * worth of data at a time, note these kstrwrite()s 1624*0Sstevel@tonic-gate * may (will) block one or more times. 1625*0Sstevel@tonic-gate */ 1626*0Sstevel@tonic-gate first = B_FALSE; 1627*0Sstevel@tonic-gate if ((write_bytes = so->so_sndbuf) == 0) 1628*0Sstevel@tonic-gate write_bytes = vp->v_stream->sd_qn_maxpsz; 1629*0Sstevel@tonic-gate ASSERT(write_bytes > 0); 1630*0Sstevel@tonic-gate write_bytes = P2ROUNDUP(write_bytes, MAXBSIZE); 1631*0Sstevel@tonic-gate } else { 1632*0Sstevel@tonic-gate if (kstrwritemp(vp, wmp, 0) != 0) 1633*0Sstevel@tonic-gate goto invalidate; 1634*0Sstevel@tonic-gate } 1635*0Sstevel@tonic-gate } while (rd.sz > 0 || rdp != NULL); 1636*0Sstevel@tonic-gate 1637*0Sstevel@tonic-gate return; 1638*0Sstevel@tonic-gate 1639*0Sstevel@tonic-gate invalidate: 1640*0Sstevel@tonic-gate if (segmap) { 1641*0Sstevel@tonic-gate REF_RELE(segmap); 1642*0Sstevel@tonic-gate } 1643*0Sstevel@tonic-gate if (wmp) 1644*0Sstevel@tonic-gate freemsg(wmp); 1645*0Sstevel@tonic-gate uri_delete(uri); 1646*0Sstevel@tonic-gate } 1647*0Sstevel@tonic-gate 1648*0Sstevel@tonic-gate /* 1649*0Sstevel@tonic-gate * The pchars[] array is indexed by a char to determine if it's a 1650*0Sstevel@tonic-gate * valid URI path component chararcter where: 1651*0Sstevel@tonic-gate * 1652*0Sstevel@tonic-gate * pchar = unreserved | escaped | 1653*0Sstevel@tonic-gate * ":" | "@" | "&" | "=" | "+" | "$" | "," 1654*0Sstevel@tonic-gate * 1655*0Sstevel@tonic-gate * unreserved = alphanum | mark 1656*0Sstevel@tonic-gate * 1657*0Sstevel@tonic-gate * alphanum = alpha | digit 1658*0Sstevel@tonic-gate * 1659*0Sstevel@tonic-gate * alpha = lowalpha | upalpha 1660*0Sstevel@tonic-gate * 1661*0Sstevel@tonic-gate * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | 1662*0Sstevel@tonic-gate * "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | 1663*0Sstevel@tonic-gate * "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | 1664*0Sstevel@tonic-gate * "y" | "z" 1665*0Sstevel@tonic-gate * 1666*0Sstevel@tonic-gate * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | 1667*0Sstevel@tonic-gate * "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | 1668*0Sstevel@tonic-gate * "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | 1669*0Sstevel@tonic-gate * "Y" | "Z" 1670*0Sstevel@tonic-gate * 1671*0Sstevel@tonic-gate * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | 1672*0Sstevel@tonic-gate * "8" | "9" 1673*0Sstevel@tonic-gate * 1674*0Sstevel@tonic-gate * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" 1675*0Sstevel@tonic-gate * 1676*0Sstevel@tonic-gate * escaped = "%" hex hex 1677*0Sstevel@tonic-gate * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | 1678*0Sstevel@tonic-gate * "a" | "b" | "c" | "d" | "e" | "f" 1679*0Sstevel@tonic-gate */ 1680*0Sstevel@tonic-gate 1681*0Sstevel@tonic-gate static char pchars[] = { 1682*0Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x07 */ 1683*0Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08 - 0x0F */ 1684*0Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x17 */ 1685*0Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 0, 0, /* 0x18 - 0x1F */ 1686*0Sstevel@tonic-gate 0, 1, 0, 0, 1, 1, 1, 1, /* 0x20 - 0x27 */ 1687*0Sstevel@tonic-gate 0, 0, 1, 1, 1, 1, 1, 1, /* 0x28 - 0x2F */ 1688*0Sstevel@tonic-gate 1, 1, 1, 1, 1, 1, 1, 1, /* 0x30 - 0x37 */ 1689*0Sstevel@tonic-gate 1, 1, 1, 0, 0, 1, 0, 0, /* 0x38 - 0x3F */ 1690*0Sstevel@tonic-gate 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x47 */ 1691*0Sstevel@tonic-gate 1, 1, 1, 1, 1, 1, 1, 1, /* 0x48 - 0x4F */ 1692*0Sstevel@tonic-gate 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x57 */ 1693*0Sstevel@tonic-gate 1, 1, 1, 0, 0, 0, 0, 1, /* 0x58 - 0x5F */ 1694*0Sstevel@tonic-gate 0, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x67 */ 1695*0Sstevel@tonic-gate 1, 1, 1, 1, 1, 1, 1, 1, /* 0x68 - 0x6F */ 1696*0Sstevel@tonic-gate 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x77 */ 1697*0Sstevel@tonic-gate 1, 1, 1, 0, 0, 0, 1, 0 /* 0x78 - 0x7F */ 1698*0Sstevel@tonic-gate }; 1699*0Sstevel@tonic-gate 1700*0Sstevel@tonic-gate #define PCHARS_MASK 0x7F 1701*0Sstevel@tonic-gate 1702*0Sstevel@tonic-gate /* 1703*0Sstevel@tonic-gate * This is the main L7 request message parse, we are called each time 1704*0Sstevel@tonic-gate * new data is availble for a socket, each time a single buffer of the 1705*0Sstevel@tonic-gate * entire message to date is given. 1706*0Sstevel@tonic-gate * 1707*0Sstevel@tonic-gate * Here we parse the request looking for the URI, parse it, and if a 1708*0Sstevel@tonic-gate * supported scheme call the scheme parser to commplete the parse of any 1709*0Sstevel@tonic-gate * headers which may further qualify the identity of the requested object 1710*0Sstevel@tonic-gate * then lookup it up in the URI hash. 1711*0Sstevel@tonic-gate * 1712*0Sstevel@tonic-gate * Return B_TRUE for more processing. 1713*0Sstevel@tonic-gate * 1714*0Sstevel@tonic-gate * Note, at this time the parser supports the generic message format as 1715*0Sstevel@tonic-gate * specified in RFC 822 with potentional limitations as specified in RFC 1716*0Sstevel@tonic-gate * 2616 for HTTP messages. 1717*0Sstevel@tonic-gate * 1718*0Sstevel@tonic-gate * Note, the caller supports an mblk_t chain, for now the parser(s) 1719*0Sstevel@tonic-gate * require the complete header in a single mblk_t. This is the common 1720*0Sstevel@tonic-gate * case and certainly for high performance environments, if at a future 1721*0Sstevel@tonic-gate * date mblk_t chains are important the parse can be reved to process 1722*0Sstevel@tonic-gate * mblk_t chains. 1723*0Sstevel@tonic-gate */ 1724*0Sstevel@tonic-gate 1725*0Sstevel@tonic-gate boolean_t 1726*0Sstevel@tonic-gate nl7c_parse(struct sonode *so, boolean_t nonblocking, boolean_t *ret, 1727*0Sstevel@tonic-gate int max_mblk) 1728*0Sstevel@tonic-gate { 1729*0Sstevel@tonic-gate char *cp = (char *)so->so_nl7c_rcv_mp->b_rptr; 1730*0Sstevel@tonic-gate char *ep = (char *)so->so_nl7c_rcv_mp->b_wptr; 1731*0Sstevel@tonic-gate char *get = "GET "; 1732*0Sstevel@tonic-gate char c; 1733*0Sstevel@tonic-gate char *uris; 1734*0Sstevel@tonic-gate uri_desc_t *uri; 1735*0Sstevel@tonic-gate uri_desc_t *ruri = NULL; 1736*0Sstevel@tonic-gate 1737*0Sstevel@tonic-gate /* 1738*0Sstevel@tonic-gate * Allocate and initialize minimumal state for the request 1739*0Sstevel@tonic-gate * uri_desc_t, in the cache hit case this uri_desc_t will 1740*0Sstevel@tonic-gate * be freed. 1741*0Sstevel@tonic-gate */ 1742*0Sstevel@tonic-gate uri = kmem_cache_alloc(uri_kmc, KM_SLEEP); 1743*0Sstevel@tonic-gate REF_INIT(uri, 1, uri_inactive, uri_kmc); 1744*0Sstevel@tonic-gate uri->hash = NULL; 1745*0Sstevel@tonic-gate uri->tail = NULL; 1746*0Sstevel@tonic-gate uri->scheme = NULL; 1747*0Sstevel@tonic-gate uri->count = 0; 1748*0Sstevel@tonic-gate if ((uri->reqmp = dupb(so->so_nl7c_rcv_mp)) == NULL) { 1749*0Sstevel@tonic-gate nl7c_uri_pass_dupbfail++; 1750*0Sstevel@tonic-gate goto pass; 1751*0Sstevel@tonic-gate } 1752*0Sstevel@tonic-gate /* 1753*0Sstevel@tonic-gate * Set request time to current time. 1754*0Sstevel@tonic-gate */ 1755*0Sstevel@tonic-gate so->so_nl7c_rtime = gethrestime_sec(); 1756*0Sstevel@tonic-gate /* 1757*0Sstevel@tonic-gate * Parse the Request-Line for the URI. 1758*0Sstevel@tonic-gate * 1759*0Sstevel@tonic-gate * For backwards HTTP version compatable reasons skip any leading 1760*0Sstevel@tonic-gate * CRLF (or CR or LF) line terminator(s) preceding Request-Line. 1761*0Sstevel@tonic-gate */ 1762*0Sstevel@tonic-gate while (cp < ep && (*cp == '\r' || *cp == '\n')) { 1763*0Sstevel@tonic-gate cp++; 1764*0Sstevel@tonic-gate } 1765*0Sstevel@tonic-gate while (cp < ep && *get == *cp) { 1766*0Sstevel@tonic-gate get++; 1767*0Sstevel@tonic-gate cp++; 1768*0Sstevel@tonic-gate } 1769*0Sstevel@tonic-gate if (*get != 0) { 1770*0Sstevel@tonic-gate if (cp == ep) { 1771*0Sstevel@tonic-gate nl7c_uri_more_get++; 1772*0Sstevel@tonic-gate goto more; 1773*0Sstevel@tonic-gate } 1774*0Sstevel@tonic-gate nl7c_uri_pass_getnot++; 1775*0Sstevel@tonic-gate goto pass; 1776*0Sstevel@tonic-gate } 1777*0Sstevel@tonic-gate /* 1778*0Sstevel@tonic-gate * Skip over URI path char(s) and save start and past end pointers. 1779*0Sstevel@tonic-gate */ 1780*0Sstevel@tonic-gate uris = cp; 1781*0Sstevel@tonic-gate while (cp < ep && (c = *cp) != ' ' && c != '\r') { 1782*0Sstevel@tonic-gate if (c == '?') { 1783*0Sstevel@tonic-gate /* Don't cache but still may want to parse */ 1784*0Sstevel@tonic-gate uri->hash = URI_TEMP; 1785*0Sstevel@tonic-gate } 1786*0Sstevel@tonic-gate cp++; 1787*0Sstevel@tonic-gate } 1788*0Sstevel@tonic-gate if (c != '\r' && cp == ep) { 1789*0Sstevel@tonic-gate nl7c_uri_more_eol++; 1790*0Sstevel@tonic-gate goto more; 1791*0Sstevel@tonic-gate } 1792*0Sstevel@tonic-gate /* 1793*0Sstevel@tonic-gate * Request-Line URI parsed, pass the rest of the request on 1794*0Sstevel@tonic-gate * to the the http scheme parse. 1795*0Sstevel@tonic-gate */ 1796*0Sstevel@tonic-gate uri->path.cp = uris; 1797*0Sstevel@tonic-gate uri->path.ep = cp; 1798*0Sstevel@tonic-gate if (! nl7c_http_request(&cp, ep, uri, so)) { 1799*0Sstevel@tonic-gate /* 1800*0Sstevel@tonic-gate * Parse not successful, the pointer to the parse pointer 1801*0Sstevel@tonic-gate * "cp" is overloaded such that ! NULL for more data and 1802*0Sstevel@tonic-gate * NULL for pass on request. 1803*0Sstevel@tonic-gate */ 1804*0Sstevel@tonic-gate if (cp != NULL) { 1805*0Sstevel@tonic-gate nl7c_uri_more_http++; 1806*0Sstevel@tonic-gate goto more; 1807*0Sstevel@tonic-gate } 1808*0Sstevel@tonic-gate nl7c_uri_pass_http++; 1809*0Sstevel@tonic-gate goto pass; 1810*0Sstevel@tonic-gate } 1811*0Sstevel@tonic-gate if (uri->hash == URI_TEMP) { 1812*0Sstevel@tonic-gate if (so->so_nl7c_flags & NL7C_SOPERSIST) { 1813*0Sstevel@tonic-gate /* Temporary URI so skip hash processing */ 1814*0Sstevel@tonic-gate nl7c_uri_request++; 1815*0Sstevel@tonic-gate nl7c_uri_temp++; 1816*0Sstevel@tonic-gate goto temp; 1817*0Sstevel@tonic-gate } 1818*0Sstevel@tonic-gate /* Not persistent so not interested in the response */ 1819*0Sstevel@tonic-gate nl7c_uri_pass_temp++; 1820*0Sstevel@tonic-gate goto pass; 1821*0Sstevel@tonic-gate } 1822*0Sstevel@tonic-gate /* 1823*0Sstevel@tonic-gate * If logging enabled save the request uri pointer and place 1824*0Sstevel@tonic-gate * an additional reference on it for logging use after lookup(). 1825*0Sstevel@tonic-gate */ 1826*0Sstevel@tonic-gate if (nl7c_logd_enabled) { 1827*0Sstevel@tonic-gate ruri = uri; 1828*0Sstevel@tonic-gate REF_HOLD(ruri); 1829*0Sstevel@tonic-gate } 1830*0Sstevel@tonic-gate /* 1831*0Sstevel@tonic-gate * Check the URI hash for a cached response. 1832*0Sstevel@tonic-gate */ 1833*0Sstevel@tonic-gate if ((uri = uri_lookup(uri, B_TRUE, nonblocking)) == NULL) { 1834*0Sstevel@tonic-gate /* 1835*0Sstevel@tonic-gate * Failed to lookup due to nonblocking wait required, 1836*0Sstevel@tonic-gate * interrupted cv_wait_sig(), KM_NOSLEEP memory alloc 1837*0Sstevel@tonic-gate * failure, ... Just pass on this request. 1838*0Sstevel@tonic-gate */ 1839*0Sstevel@tonic-gate nl7c_uri_pass_addfail++; 1840*0Sstevel@tonic-gate goto pass; 1841*0Sstevel@tonic-gate } 1842*0Sstevel@tonic-gate nl7c_uri_request++; 1843*0Sstevel@tonic-gate if (uri->response.sz > 0) { 1844*0Sstevel@tonic-gate /* 1845*0Sstevel@tonic-gate * We have the response cached, update recv mblk rptr 1846*0Sstevel@tonic-gate * to reflect the data consumed above, send the response 1847*0Sstevel@tonic-gate * out the socket, release reference on uri from the 1848*0Sstevel@tonic-gate * call to lookup_add(), set the *ret value to B_TRUE 1849*0Sstevel@tonic-gate * for socket close and return B_FALSE to indcate no 1850*0Sstevel@tonic-gate * more data needed. 1851*0Sstevel@tonic-gate */ 1852*0Sstevel@tonic-gate mblk_t *mp = so->so_nl7c_rcv_mp; 1853*0Sstevel@tonic-gate 1854*0Sstevel@tonic-gate /* If a saved ruri set above then log request */ 1855*0Sstevel@tonic-gate if (ruri != NULL) { 1856*0Sstevel@tonic-gate ipaddr_t faddr; 1857*0Sstevel@tonic-gate 1858*0Sstevel@tonic-gate if (so->so_family == AF_INET) { 1859*0Sstevel@tonic-gate /* Only support IPv4 addrs */ 1860*0Sstevel@tonic-gate faddr = ((struct sockaddr_in *) 1861*0Sstevel@tonic-gate so->so_faddr_sa) ->sin_addr.s_addr; 1862*0Sstevel@tonic-gate } else { 1863*0Sstevel@tonic-gate faddr = 0; 1864*0Sstevel@tonic-gate } 1865*0Sstevel@tonic-gate nl7c_logd_log(ruri, uri, so->so_nl7c_rtime, faddr); 1866*0Sstevel@tonic-gate REF_RELE(ruri); 1867*0Sstevel@tonic-gate } 1868*0Sstevel@tonic-gate nl7c_uri_hit++; 1869*0Sstevel@tonic-gate if (cp == (char *)mp->b_wptr) { 1870*0Sstevel@tonic-gate so->so_nl7c_rcv_mp = mp->b_cont; 1871*0Sstevel@tonic-gate mp->b_cont = NULL; 1872*0Sstevel@tonic-gate freeb(mp); 1873*0Sstevel@tonic-gate } else { 1874*0Sstevel@tonic-gate mp->b_rptr = (unsigned char *)cp; 1875*0Sstevel@tonic-gate } 1876*0Sstevel@tonic-gate uri_response(so, uri, max_mblk); 1877*0Sstevel@tonic-gate REF_RELE(uri); 1878*0Sstevel@tonic-gate *ret = B_TRUE; 1879*0Sstevel@tonic-gate return (B_FALSE); 1880*0Sstevel@tonic-gate } 1881*0Sstevel@tonic-gate if (ruri != NULL) { 1882*0Sstevel@tonic-gate REF_RELE(ruri); 1883*0Sstevel@tonic-gate } 1884*0Sstevel@tonic-gate /* 1885*0Sstevel@tonic-gate * Don't have a response cached or may want to cache the 1886*0Sstevel@tonic-gate * response from the webserver so store the uri pointer in 1887*0Sstevel@tonic-gate * the so subsequent write-side calls ... 1888*0Sstevel@tonic-gate */ 1889*0Sstevel@tonic-gate nl7c_uri_miss++; 1890*0Sstevel@tonic-gate temp: 1891*0Sstevel@tonic-gate uri->proc = so; 1892*0Sstevel@tonic-gate so->so_nl7c_uri = uri; 1893*0Sstevel@tonic-gate so->so_nl7c_flags |= NL7C_WAITWRITE; 1894*0Sstevel@tonic-gate *ret = B_FALSE; 1895*0Sstevel@tonic-gate return (B_FALSE); 1896*0Sstevel@tonic-gate 1897*0Sstevel@tonic-gate more: 1898*0Sstevel@tonic-gate /* More data is needed, note fragmented recv not supported */ 1899*0Sstevel@tonic-gate nl7c_uri_more++; 1900*0Sstevel@tonic-gate 1901*0Sstevel@tonic-gate pass: 1902*0Sstevel@tonic-gate /* Pass on this request */ 1903*0Sstevel@tonic-gate nl7c_uri_pass++; 1904*0Sstevel@tonic-gate nl7c_uri_request++; 1905*0Sstevel@tonic-gate if (ruri != NULL) { 1906*0Sstevel@tonic-gate REF_RELE(ruri); 1907*0Sstevel@tonic-gate } 1908*0Sstevel@tonic-gate if (uri) { 1909*0Sstevel@tonic-gate REF_RELE(uri); 1910*0Sstevel@tonic-gate } 1911*0Sstevel@tonic-gate so->so_nl7c_flags = 0; 1912*0Sstevel@tonic-gate *ret = B_FALSE; 1913*0Sstevel@tonic-gate return (B_FALSE); 1914*0Sstevel@tonic-gate } 1915