/* * Sets up the initial seed for picking a backend according to policy. */ static double vdi_random_init_seed(const struct vdi_random *vs, const struct sess *sp) { const char *p; double retval; switch (vs->criteria) { case c_client: if (sp->client_identity != NULL) p = sp->client_identity; else p = sp->addr; retval = vdi_random_sha(p, strlen(p)); break; case c_hash: AN(sp->digest); retval = vle32dec(sp->digest) / exp2(32); break; case c_random: default: retval = random() / exp2(31); break; } return (retval); }
/* * Applies sha256 using the given context and input/length, and returns * a double in the range [0...1[ based on the hash. */ static double vdi_random_sha(const char *input, ssize_t len) { struct SHA256Context ctx; uint8_t sign[SHA256_LEN]; AN(input); SHA256_Init(&ctx); SHA256_Update(&ctx, input, len); SHA256_Final(sign, &ctx); return (vle32dec(sign) / exp2(32)); }
static void ved_stripgzip(struct req *req, struct busyobj *bo) { ssize_t start, last, stop, lpad; ssize_t l; char *p; uint32_t icrc; uint32_t ilen; uint64_t olen; uint8_t *dbits; uint8_t *pp; uint8_t tailbuf[8]; enum objiter_status ois; void *oi; void *sp; ssize_t sl, ll, dl; struct ecx *ecx; struct req *preq; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC); preq = ecx->preq; if (bo != NULL) VBO_waitstate(bo, BOS_FINISHED); AN(ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED)); /* * This is the interesting case: Deliver all the deflate * blocks, stripping the "LAST" bit of the last one and * padding it, as necessary, to a byte boundary. */ p = ObjGetattr(req->wrk, req->objcore, OA_GZIPBITS, &l); AN(p); assert(l == 32); start = vbe64dec(p); last = vbe64dec(p + 8); stop = vbe64dec(p + 16); olen = ObjGetLen(req->wrk, req->objcore); assert(start > 0 && start < olen * 8); assert(last > 0 && last < olen * 8); assert(stop > 0 && stop < olen * 8); assert(last >= start); assert(last < stop); /* The start bit must be byte aligned. */ AZ(start & 7); /* * XXX: optimize for the case where the 'last' * XXX: bit is in a empty copy block */ memset(tailbuf, 0xdd, sizeof tailbuf); dbits = WS_Alloc(req->ws, 8); AN(dbits); ll = 0; oi = ObjIterBegin(req->wrk, req->objcore); do { ois = ObjIter(req->objcore, oi, &sp, &sl); pp = sp; if (sl > 0) { /* Skip over the GZIP header */ dl = start / 8 - ll; if (dl > 0) { /* Before start, skip */ if (dl > sl) dl = sl; ll += dl; sl -= dl; pp += dl; } } if (sl > 0) { /* The main body of the object */ dl = last / 8 - ll; if (dl > 0) { if (dl > sl) dl = sl; if (ved_bytes(req, preq, VDP_NULL, pp, dl)) break; ll += dl; sl -= dl; pp += dl; } } if (sl > 0 && ll == last / 8) { /* Remove the "LAST" bit */ dbits[0] = *pp; dbits[0] &= ~(1U << (last & 7)); if (ved_bytes(req, preq, VDP_NULL, dbits, 1)) break; ll++; sl--; pp++; } if (sl > 0) { /* Last block */ dl = stop / 8 - ll; if (dl > 0) { if (dl > sl) dl = sl; if (ved_bytes(req, preq, VDP_NULL, pp, dl)) break; ll += dl; sl -= dl; pp += dl; } } if (sl > 0 && (stop & 7) && ll == stop / 8) { /* Add alignment to byte boundary */ dbits[1] = *pp; ll++; sl--; pp++; switch((int)(stop & 7)) { case 1: /* * x000.... * 00000000 00000000 11111111 11111111 */ case 3: /* * xxx000.. * 00000000 00000000 11111111 11111111 */ case 5: /* * xxxxx000 * 00000000 00000000 11111111 11111111 */ dbits[2] = 0x00; dbits[3] = 0x00; dbits[4] = 0xff; dbits[5] = 0xff; lpad = 5; break; case 2: /* xx010000 00000100 00000001 00000000 */ dbits[1] |= 0x08; dbits[2] = 0x20; dbits[3] = 0x80; dbits[4] = 0x00; lpad = 4; break; case 4: /* xxxx0100 00000001 00000000 */ dbits[1] |= 0x20; dbits[2] = 0x80; dbits[3] = 0x00; lpad = 3; break; case 6: /* xxxxxx01 00000000 */ dbits[1] |= 0x80; dbits[2] = 0x00; lpad = 2; break; case 7: /* * xxxxxxx0 * 00...... * 00000000 00000000 11111111 11111111 */ dbits[2] = 0x00; dbits[3] = 0x00; dbits[4] = 0x00; dbits[5] = 0xff; dbits[6] = 0xff; lpad = 6; break; case 0: /* xxxxxxxx */ default: WRONG("compiler must be broken"); } if (ved_bytes(req, preq, VDP_NULL, dbits + 1, lpad)) break; } if (sl > 0) { /* Recover GZIP tail */ dl = olen - ll; assert(dl >= 0); if (dl > sl) dl = sl; if (dl > 0) { assert(dl <= 8); l = ll - (olen - 8); assert(l >= 0); assert(l <= 8); assert(l + dl <= 8); memcpy(tailbuf + l, pp, dl); ll += dl; sl -= dl; pp += dl; } } } while (ois == OIS_DATA || ois == OIS_STREAM); ObjIterEnd(req->objcore, &oi); (void)ved_bytes(req, preq, VDP_FLUSH, NULL, 0); icrc = vle32dec(tailbuf); ilen = vle32dec(tailbuf + 4); ecx->crc = crc32_combine(ecx->crc, icrc, ilen); ecx->l_crc += ilen; }
static void ved_stripgzip(struct req *req, const struct boc *boc) { ssize_t l; char *p; uint32_t icrc; uint32_t ilen; uint8_t *dbits; struct ecx *ecx; struct ved_foo foo; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC); INIT_OBJ(&foo, VED_FOO_MAGIC); foo.req = req; foo.preq = ecx->preq; memset(foo.tailbuf, 0xdd, sizeof foo.tailbuf); /* OA_GZIPBITS is not valid until BOS_FINISHED */ if (boc != NULL) ObjWaitState(req->objcore, BOS_FINISHED); AN(ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED)); /* * This is the interesting case: Deliver all the deflate * blocks, stripping the "LAST" bit of the last one and * padding it, as necessary, to a byte boundary. */ p = ObjGetAttr(req->wrk, req->objcore, OA_GZIPBITS, &l); AN(p); assert(l == 32); foo.start = vbe64dec(p); foo.last = vbe64dec(p + 8); foo.stop = vbe64dec(p + 16); foo.olen = ObjGetLen(req->wrk, req->objcore); assert(foo.start > 0 && foo.start < foo.olen * 8); assert(foo.last > 0 && foo.last < foo.olen * 8); assert(foo.stop > 0 && foo.stop < foo.olen * 8); assert(foo.last >= foo.start); assert(foo.last < foo.stop); /* The start bit must be byte aligned. */ AZ(foo.start & 7); dbits = WS_Alloc(req->ws, 8); AN(dbits); foo.dbits = dbits; (void)ObjIterate(req->wrk, req->objcore, &foo, ved_objiterate); /* XXX: error check ?? */ (void)ved_bytes(req, foo.preq, VDP_FLUSH, NULL, 0); icrc = vle32dec(foo.tailbuf); ilen = vle32dec(foo.tailbuf + 4); ecx->crc = crc32_combine(ecx->crc, icrc, ilen); ecx->l_crc += ilen; }