void vtc_wait4(struct vtclog *vl, long pid, int expect_status, int expect_signal, int allow_core) { int status, r; struct rusage ru; r = wait4(pid, &status, 0, &ru); if (r < 0) vtc_fatal(vl, "wait4 failed on pid %ld: %s", pid, strerror(errno)); assert(r == pid); vtc_log(vl, 2, "WAIT4 pid=%ld status=0x%04x (user %.6f sys %.6f)", pid, status, ru.ru_utime.tv_sec + 1e-6 * ru.ru_utime.tv_usec, ru.ru_stime.tv_sec + 1e-6 * ru.ru_stime.tv_usec ); if (WIFEXITED(status) && expect_signal <= 0 && WEXITSTATUS(status) == expect_status) return; if (expect_signal < 0) expect_signal = -expect_signal; if (WIFSIGNALED(status) && WCOREDUMP(status) <= allow_core && WTERMSIG(status) == expect_signal) return; vtc_log(vl, 1, "Expected exit: 0x%x signal: %d core: %d", expect_status, expect_signal, allow_core); vtc_fatal(vl, "Bad exit status: 0x%04x exit 0x%x signal %d core %d", status, WEXITSTATUS(status), WIFSIGNALED(status) ? WTERMSIG(status) : 0, WCOREDUMP(status)); }
static void varnish_vcl(struct varnish *v, const char *vcl, enum VCLI_status_e expect) { struct vsb *vsb; enum VCLI_status_e u; if (v->cli_fd < 0) varnish_launch(v); if (vtc_error) return; vsb = VSB_new_auto(); AN(vsb); VSB_printf(vsb, "vcl.inline vcl%d << %s\n%s\n%s\n", ++v->vcl_nbr, NONSENSE, vcl, NONSENSE); AZ(VSB_finish(vsb)); u = varnish_ask_cli(v, VSB_data(vsb), NULL); if (u != expect) { VSB_delete(vsb); vtc_log(v->vl, 0, "VCL compilation got %u expected %u", u, expect); return; } if (u == CLIS_OK) { VSB_clear(vsb); VSB_printf(vsb, "vcl.use vcl%d", v->vcl_nbr); AZ(VSB_finish(vsb)); u = varnish_ask_cli(v, VSB_data(vsb), NULL); assert(u == CLIS_OK); } else { vtc_log(v->vl, 2, "VCL compilation failed (as expected)"); } VSB_delete(vsb); }
static void cmd_http_fatal(CMD_ARGS) { struct http *hp; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); AZ(av[1]); if (!strcmp(av[0], "fatal")) hp->fatal = 0; else if (!strcmp(av[0], "non-fatal")) hp->fatal = -1; else { vtc_log(vl, 0, "XXX: fatal %s", cmd->name); } }
static void cmd_http_loop(CMD_ARGS) { struct http *hp; unsigned n, m; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); AN(av[1]); AN(av[2]); AZ(av[3]); n = strtoul(av[1], NULL, 0); for (m = 1 ; m <= n; m++) { vtc_log(vl, 4, "Loop #%u", m); parse_string(av[2], cmd, hp, vl); } }
static void cmd_http_timeout(CMD_ARGS) { struct http *hp; double d; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); AN(av[1]); AZ(av[2]); d = VNUM(av[1]); if (isnan(d)) vtc_log(vl, 0, "timeout is not a number (%s)", av[1]); hp->timeout = (int)(d * 1000.0); }
static void cmd_varnishtest(CMD_ARGS) { (void)priv; (void)cmd; (void)vl; if (av == NULL) return; assert(!strcmp(av[0], "varnishtest")); vtc_log(vl, 1, "TEST %s", av[1]); AZ(av[2]); vtc_desc = strdup(av[1]); }
static void cmd_http_rxhdrs(CMD_ARGS) { struct http *hp; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); ONLY_SERVER(hp, av); assert(!strcmp(av[0], "rxhdrs")); av++; for(; *av != NULL; av++) vtc_log(hp->vl, 0, "Unknown http rxreq spec: %s\n", *av); http_rxhdr(hp); http_splitheader(hp, 1); }
static void cmd_http_send(CMD_ARGS) { struct http *hp; int i; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); AN(av[1]); AZ(av[2]); vtc_dump(hp->vl, 4, "send", av[1], -1); i = write(hp->fd, av[1], strlen(av[1])); if (i != strlen(av[1])) vtc_log(hp->vl, hp->fatal, "Write error in http_send(): %s", strerror(errno)); }
static void cmd_feature(CMD_ARGS) { int i; (void)priv; (void)cmd; if (av == NULL) return; for (i = 1; av[i] != NULL; i++) { #ifdef SO_RCVTIMEO_WORKS if (!strcmp(av[i], "SO_RCVTIMEO_WORKS")) continue; #endif if (sizeof(void*) == 8 && !strcmp(av[i], "64bit")) continue; if (!strcmp(av[i], "!OSX")) { #if !defined(__APPLE__) || !defined(__MACH__) continue; #endif } if (!strcmp(av[i], "topbuild") && iflg) continue; if (!strcmp(av[i], "root") && !geteuid()) continue; if (!strcmp(av[i], "user_varnish") && getpwnam("varnish") != NULL) continue; if (!strcmp(av[i], "user_vcache") && getpwnam("vcache") != NULL) continue; if (!strcmp(av[i], "group_varnish") && getgrnam("varnish") != NULL) continue; vtc_log(vl, 1, "SKIPPING test, missing feature: %s", av[i]); vtc_stop = 1; return; } }
vtc_log_VAS_Fail(const char *func, const char *file, int line, const char *cond, enum vas_e why) { struct vtclog *vl; (void)why; vl = pthread_getspecific(log_key); if (vl == NULL || vl->act) { fprintf(stderr, "Assert error in %s(), %s line %d:\n" " Condition(%s) not true.\n", func, file, line, cond); } else { vtc_log(vl, 0, "Assert error in %s(), %s line %d:" " Condition(%s) not true.\n", func, file, line, cond); } abort(); }
static void cmd_http_txresp(CMD_ARGS) { struct http *hp; const char *proto = "HTTP/1.1"; const char *status = "200"; const char *msg = "OK"; char* body = NULL; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); ONLY_SERVER(hp, av); AZ(strcmp(av[0], "txresp")); av++; VSB_clear(hp->vsb); for(; *av != NULL; av++) { if (!strcmp(*av, "-proto")) { proto = av[1]; av++; } else if (!strcmp(*av, "-status")) { status = av[1]; av++; } else if (!strcmp(*av, "-msg")) { msg = av[1]; av++; continue; } else break; } VSB_printf(hp->vsb, "%s %s %s%s", proto, status, msg, nl); /* send a "Content-Length: 0" header unless something else happens */ REPLACE(body, ""); av = http_tx_parse_args(av, vl, hp, body); if (*av != NULL) vtc_log(hp->vl, 0, "Unknown http txresp spec: %s\n", *av); http_write(hp, 4, "txresp"); }
static void cmd_http_rxchunk(CMD_ARGS) { struct http *hp; int ll, i; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); ONLY_CLIENT(hp, av); i = http_rxchunk(hp); if (i == 0) { ll = hp->rxbuf + hp->prxbuf - hp->body; hp->bodyl = ll; sprintf(hp->bodylen, "%d", ll); vtc_log(hp->vl, 4, "bodylen = %s", hp->bodylen); } }
static int h_addlog(void *priv, enum VSL_tag_e tag, unsigned fd, unsigned len, unsigned spec, const char *ptr, uint64_t bitmap) { struct varnish *v; int type; (void) bitmap; type = (spec & VSL_S_CLIENT) ? 'c' : (spec & VSL_S_BACKEND) ? 'b' : '-'; CAST_OBJ_NOTNULL(v, priv, VARNISH_MAGIC); v->vsl_tag_count[tag]++; vtc_log(v->vl, 4, "vsl| %5u %-12s %c %.*s", fd, VSL_tags[tag], type, len, ptr); v->vsl_sleep = 100; return (0); }
static struct varnish * varnish_new(const char *name) { struct varnish *v; struct vsb *vsb; char buf[1024]; AN(name); ALLOC_OBJ(v, VARNISH_MAGIC); AN(v); REPLACE(v->name, name); v->vl = vtc_logopen(name); AN(v->vl); bprintf(buf, "${tmpdir}/%s", name); vsb = macro_expand(v->vl, buf); AN(vsb); v->workdir = strdup(VSB_data(vsb)); AN(v->workdir); VSB_delete(vsb); bprintf(buf, "rm -rf %s ; mkdir -p %s ; echo ' %ld' > %s/_S", v->workdir, v->workdir, random(), v->workdir); AZ(system(buf)); if (*v->name != 'v') vtc_log(v->vl, 0, "Varnish name must start with 'v'"); v->args = VSB_new_auto(); v->storage = VSB_new_auto(); VSB_printf(v->storage, "-sfile,%s,10M", v->workdir); AZ(VSB_finish(v->storage)); v->cli_fd = -1; VTAILQ_INSERT_TAIL(&varnishes, v, list); return (v); }
struct vsb * macro_expand(struct vtclog *vl, const char *text) { struct vsb *vsb; const char *p, *q; char *m; vsb = VSB_new_auto(); AN(vsb); while (*text != '\0') { p = strstr(text, "${"); if (p == NULL) { VSB_cat(vsb, text); break; } VSB_bcat(vsb, text, p - text); q = strchr(p, '}'); if (q == NULL) { VSB_cat(vsb, text); break; } assert(p[0] == '$'); assert(p[1] == '{'); assert(q[0] == '}'); p += 2; m = macro_get(p, q); if (m == NULL) { VSB_delete(vsb); vtc_log(vl, 0, "Macro ${%.*s} not found", (int)(q - p), p); return (NULL); } VSB_printf(vsb, "%s", m); free(m); text = q + 1; } AZ(VSB_finish(vsb)); return (vsb); }
static void gzip_body(const struct http *hp, const char *txt, char **body, int *bodylen) { int l, i; z_stream vz; memset(&vz, 0, sizeof vz); l = strlen(txt); *body = calloc(l + OVERHEAD, 1); AN(*body); vz.next_in = TRUST_ME(txt); vz.avail_in = l; vz.next_out = TRUST_ME(*body); vz.avail_out = l + OVERHEAD; assert(Z_OK == deflateInit2(&vz, hp->gziplevel, Z_DEFLATED, 31, 9, Z_DEFAULT_STRATEGY)); assert(Z_STREAM_END == deflate(&vz, Z_FINISH)); i = vz.stop_bit & 7; if (hp->gzipresidual >= 0 && hp->gzipresidual != i) vtc_log(hp->vl, hp->fatal, "Wrong gzip residual got %d wanted %d", i, hp->gzipresidual); *bodylen = vz.total_out; vtc_log(hp->vl, 4, "startbit = %ju %ju/%ju", (uintmax_t)vz.start_bit, (uintmax_t)vz.start_bit >> 3, (uintmax_t)vz.start_bit & 7); vtc_log(hp->vl, 4, "lastbit = %ju %ju/%ju", (uintmax_t)vz.last_bit, (uintmax_t)vz.last_bit >> 3, (uintmax_t)vz.last_bit & 7); vtc_log(hp->vl, 4, "stopbit = %ju %ju/%ju", (uintmax_t)vz.stop_bit, (uintmax_t)vz.stop_bit >> 3, (uintmax_t)vz.stop_bit & 7); assert(Z_OK == deflateEnd(&vz)); }
static void varnish_vclbackend(struct varnish *v, const char *vcl) { struct vsb *vsb, *vsb2; enum VCLI_status_e u; if (v->cli_fd < 0) varnish_launch(v); if (vtc_error) return; vsb = VSB_new_auto(); AN(vsb); vsb2 = VSB_new_auto(); AN(vsb2); cmd_server_genvcl(vsb2); AZ(VSB_finish(vsb2)); VSB_printf(vsb, "vcl.inline vcl%d << %s\n%s\n%s\n%s\n", ++v->vcl_nbr, NONSENSE, VSB_data(vsb2), vcl, NONSENSE); AZ(VSB_finish(vsb)); u = varnish_ask_cli(v, VSB_data(vsb), NULL); if (u != CLIS_OK) { VSB_delete(vsb); VSB_delete(vsb2); vtc_log(v->vl, 0, "FAIL VCL does not compile"); return; } VSB_clear(vsb); VSB_printf(vsb, "vcl.use vcl%d", v->vcl_nbr); AZ(VSB_finish(vsb)); u = varnish_ask_cli(v, VSB_data(vsb), NULL); assert(u == CLIS_OK); VSB_delete(vsb); VSB_delete(vsb2); }
static void cmd_http_recv(CMD_ARGS) { struct http *hp; int i, n; char u[32]; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); AN(av[1]); AZ(av[2]); n = strtoul(av[1], NULL, 0); while (n > 0) { i = read(hp->fd, u, n > 32 ? 32 : n); if (i > 0) vtc_dump(hp->vl, 4, "recv", u, i); else vtc_log(hp->vl, hp->fatal, "recv() got %d (%s)", i, strerror(errno)); n -= i; } }
static void cmd_http_send_n(CMD_ARGS) { struct http *hp; int i, n, l; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); AN(av[1]); AN(av[2]); AZ(av[3]); n = strtoul(av[1], NULL, 0); vtc_dump(hp->vl, 4, "send_n", av[2], -1); l = strlen(av[2]); while (n--) { i = write(hp->fd, av[2], l); if (i != l) vtc_log(hp->vl, hp->fatal, "Write error in http_send(): %s", strerror(errno)); } }
void macro_def(struct vtclog *vl, const char *instance, const char *name, const char *fmt, ...) { char buf1[256]; char buf2[256]; struct macro *m; va_list ap; AN(fmt); if (instance != NULL) { bprintf(buf1, "%s_%s", instance, name); name = buf1; } AZ(pthread_mutex_lock(¯o_mtx)); VTAILQ_FOREACH(m, ¯o_list, list) if (!strcmp(name, m->name)) break; if (m == NULL) { m = calloc(sizeof *m, 1); AN(m); REPLACE(m->name, name); VTAILQ_INSERT_TAIL(¯o_list, m, list); } AN(m); va_start(ap, fmt); free(m->val); m->val = NULL; vbprintf(buf2, fmt, ap); va_end(ap); m->val = strdup(buf2); AN(m->val); vtc_log(vl, 4, "macro def %s=%s", name, m->val); AZ(pthread_mutex_unlock(¯o_mtx)); }
static void cmd_http_txreq(CMD_ARGS) { struct http *hp; const char *req = "GET"; const char *url = "/"; const char *proto = "HTTP/1.1"; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); ONLY_CLIENT(hp, av); AZ(strcmp(av[0], "txreq")); av++; VSB_clear(hp->vsb); for(; *av != NULL; av++) { if (!strcmp(*av, "-url")) { url = av[1]; av++; } else if (!strcmp(*av, "-proto")) { proto = av[1]; av++; } else if (!strcmp(*av, "-req")) { req = av[1]; av++; } else break; } VSB_printf(hp->vsb, "%s %s %s%s", req, url, proto, nl); av = http_tx_parse_args(av, vl, hp, NULL); if (*av != NULL) vtc_log(hp->vl, 0, "Unknown http txreq spec: %s\n", *av); http_write(hp, 4, "txreq"); }
void macro_undef(struct vtclog *vl, const char *instance, const char *name) { char buf1[256]; struct macro *m; if (instance != NULL) { bprintf(buf1, "%s_%s", instance, name); name = buf1; } AZ(pthread_mutex_lock(¯o_mtx)); VTAILQ_FOREACH(m, ¯o_list, list) if (!strcmp(name, m->name)) break; if (m != NULL) { vtc_log(vl, 4, "macro undef %s", name); VTAILQ_REMOVE(¯o_list, m, list); free(m->name); free(m->val); free(m); } AZ(pthread_mutex_unlock(¯o_mtx)); }
static void cmd_http_sendhex(CMD_ARGS) { struct http *hp; char buf[3], *q; uint8_t *p; int i, j, l; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); AN(av[1]); AZ(av[2]); l = strlen(av[1]) / 2; p = malloc(l); AN(p); q = av[1]; for (i = 0; i < l; i++) { while (vct_issp(*q)) q++; if (*q == '\0') break; memcpy(buf, q, 2); q += 2; buf[2] = '\0'; if (!vct_ishex(buf[0]) || !vct_ishex(buf[1])) vtc_log(hp->vl, 0, "Illegal Hex char \"%c%c\"", buf[0], buf[1]); p[i] = (uint8_t)strtoul(buf, NULL, 16); } vtc_hexdump(hp->vl, 4, "sendhex", (void*)p, i); j = write(hp->fd, p, i); assert(j == i); free(p); }
static void cmd_err_shell(CMD_ARGS) { (void)priv; (void)cmd; struct vsb *vsb; FILE *fp; int r, c; if (av == NULL) return; AN(av[1]); AN(av[2]); AZ(av[3]); vsb = VSB_new_auto(); AN(vsb); vtc_dump(vl, 4, "cmd", av[2], -1); fp = popen(av[2], "r"); if (fp == NULL) vtc_log(vl, 0, "popen fails: %s", strerror(errno)); do { c = getc(fp); if (c != EOF) VSB_putc(vsb, c); } while (c != EOF); r = pclose(fp); vtc_log(vl, 4, "Status = %d", WEXITSTATUS(r)); if (WIFSIGNALED(r)) vtc_log(vl, 4, "Signal = %d", WTERMSIG(r)); if (WEXITSTATUS(r) == 0) { vtc_log(vl, 0, "expected error from shell"); } AZ(VSB_finish(vsb)); vtc_dump(vl, 4, "stdout", VSB_data(vsb), VSB_len(vsb)); if (strstr(VSB_data(vsb), av[1]) == NULL) vtc_log(vl, 0, "Did not find expected string: (\"%s\")", av[1]); else vtc_log(vl, 4, "Found expected string: (\"%s\")", av[1]); VSB_delete(vsb); }
void parse_string(const char *spec, const struct cmds *cmd, void *priv, struct vtclog *vl) { char *token_s[MAX_TOKENS], *token_e[MAX_TOKENS]; struct vsb *token_exp[MAX_TOKENS]; char *p, *q, *f, *buf; int nest_brace; int tn; const struct cmds *cp; AN(spec); buf = strdup(spec); AN(buf); for (p = buf; *p != '\0'; p++) { if (vtc_error || vtc_stop) break; /* Start of line */ if (isspace(*p)) continue; if (*p == '\n') continue; if (*p == '#') { for (; *p != '\0' && *p != '\n'; p++) ; if (*p == '\0') break; continue; } q = strchr(p, '\n'); if (q == NULL) q = strchr(p, '\0'); if (q - p > 60) vtc_log(vl, 2, "=== %.60s...", p); else vtc_log(vl, 2, "=== %.*s", (int)(q - p), p); /* First content on line, collect tokens */ tn = 0; f = p; while (*p != '\0') { assert(tn < MAX_TOKENS); if (*p == '\n') { /* End on NL */ break; } if (isspace(*p)) { /* Inter-token whitespace */ p++; continue; } if (*p == '\\' && p[1] == '\n') { /* line-cont */ p += 2; continue; } if (*p == '"') { /* quotes */ token_s[tn] = ++p; q = p; for (; *p != '\0'; p++) { if (*p == '"') break; if (*p == '\\') { p += VAV_BackSlash(p, q) - 1; q++; } else { if (*p == '\n') vtc_log(vl, 0, "Unterminated quoted string in line: %*.*s", (int)(p - f), (int)(p - f), f); assert(*p != '\n'); *q++ = *p; } } token_e[tn++] = q; p++; } else if (*p == '{') { /* Braces */ nest_brace = 0; token_s[tn] = p + 1; for (; *p != '\0'; p++) { if (*p == '{') nest_brace++; else if (*p == '}') { if (--nest_brace == 0) break; } } assert(*p == '}'); token_e[tn++] = p++; } else { /* other tokens */ token_s[tn] = p; for (; *p != '\0' && !isspace(*p); p++) ; token_e[tn++] = p; } } assert(tn < MAX_TOKENS); token_s[tn] = NULL; for (tn = 0; token_s[tn] != NULL; tn++) { token_exp[tn] = NULL; AN(token_e[tn]); /*lint !e771 */ *token_e[tn] = '\0'; /*lint !e771 */ if (NULL == strstr(token_s[tn], "${")) continue; token_exp[tn] = macro_expand(vl, token_s[tn]); if (vtc_error) { return; } token_s[tn] = VSB_data(token_exp[tn]); token_e[tn] = strchr(token_s[tn], '\0'); } for (cp = cmd; cp->name != NULL; cp++) if (!strcmp(token_s[0], cp->name)) break; if (cp->name == NULL) { vtc_log(vl, 0, "Unknown command: \"%s\"", token_s[0]); return; } assert(cp->cmd != NULL); cp->cmd(token_s, priv, cmd, vl); } }
static void cmd_http_expect(CMD_ARGS) { struct http *hp; const char *lhs, *clhs; char *cmp; const char *rhs, *crhs; vre_t *vre; const char *error; int erroroffset; int i, retval = -1; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); AZ(strcmp(av[0], "expect")); av++; AN(av[0]); AN(av[1]); AN(av[2]); AZ(av[3]); lhs = cmd_var_resolve(hp, av[0]); cmp = av[1]; rhs = cmd_var_resolve(hp, av[2]); clhs = lhs ? lhs : "<undef>"; crhs = rhs ? rhs : "<undef>"; if (!strcmp(cmp, "~") || !strcmp(cmp, "!~")) { vre = VRE_compile(crhs, 0, &error, &erroroffset); if (vre == NULL) vtc_log(hp->vl, 0, "REGEXP error: %s (@%d) (%s)", error, erroroffset, crhs); i = VRE_exec(vre, clhs, strlen(clhs), 0, 0, NULL, 0, 0); retval = (i >= 0 && *cmp == '~') || (i < 0 && *cmp == '!'); VRE_free(&vre); } else if (!strcmp(cmp, "==")) { retval = strcmp(clhs, crhs) == 0; } else if (!strcmp(cmp, "!=")) { retval = strcmp(clhs, crhs) != 0; } else if (lhs == NULL || rhs == NULL) { // fail inequality comparisons if either side is undef'ed retval = 0; } else if (!strcmp(cmp, "<")) { retval = isless(VNUM(lhs), VNUM(rhs)); } else if (!strcmp(cmp, ">")) { retval = isgreater(VNUM(lhs), VNUM(rhs)); } else if (!strcmp(cmp, "<=")) { retval = islessequal(VNUM(lhs), VNUM(rhs)); } else if (!strcmp(cmp, ">=")) { retval = isgreaterequal(VNUM(lhs), VNUM(rhs)); } if (retval == -1) vtc_log(hp->vl, 0, "EXPECT %s (%s) %s %s (%s) test not implemented", av[0], clhs, av[1], av[2], crhs); else vtc_log(hp->vl, retval ? 4 : 0, "EXPECT %s (%s) %s \"%s\" %s", av[0], clhs, cmp, crhs, retval ? "match" : "failed"); }
static void varnish_launch(struct varnish *v) { struct vsb *vsb, *vsb1; int i, nfd, nap; struct vss_addr **ap; char abuf[128], pbuf[128]; struct pollfd fd[2]; enum VCLI_status_e u; char *r; v->vd = VSM_New(); VSC_Setup(v->vd); /* Create listener socket */ nap = VSS_resolve("127.0.0.1", "0", &ap); AN(nap); v->cli_fd = VSS_listen(ap[0], 1); VTCP_myname(v->cli_fd, abuf, sizeof abuf, pbuf, sizeof pbuf); AZ(VSB_finish(v->args)); vtc_log(v->vl, 2, "Launch"); vsb = VSB_new_auto(); AN(vsb); VSB_printf(vsb, "cd ${pwd} &&"); VSB_printf(vsb, " ${varnishd} -d -d -n %s", v->workdir); VSB_printf(vsb, " -l 10m,1m,-"); VSB_printf(vsb, " -p auto_restart=off"); VSB_printf(vsb, " -p syslog_cli_traffic=off"); VSB_printf(vsb, " -a '%s'", "127.0.0.1:0"); VSB_printf(vsb, " -S %s/_S", v->workdir); VSB_printf(vsb, " -M '%s %s'", abuf, pbuf); VSB_printf(vsb, " -P %s/varnishd.pid", v->workdir); VSB_printf(vsb, " %s", VSB_data(v->storage)); VSB_printf(vsb, " %s", VSB_data(v->args)); AZ(VSB_finish(vsb)); vtc_log(v->vl, 3, "CMD: %s", VSB_data(vsb)); vsb1 = macro_expand(v->vl, VSB_data(vsb)); AN(vsb1); VSB_delete(vsb); vsb = vsb1; vtc_log(v->vl, 3, "CMD: %s", VSB_data(vsb)); AZ(pipe(&v->fds[0])); AZ(pipe(&v->fds[2])); v->pid = fork(); assert(v->pid >= 0); if (v->pid == 0) { assert(dup2(v->fds[0], 0) == 0); assert(dup2(v->fds[3], 1) == 1); assert(dup2(1, 2) == 2); AZ(close(v->fds[0])); AZ(close(v->fds[1])); AZ(close(v->fds[2])); AZ(close(v->fds[3])); for (i = 3; i <getdtablesize(); i++) (void)close(i); AZ(execl("/bin/sh", "/bin/sh", "-c", VSB_data(vsb), (char*)0)); exit(1); } else { vtc_log(v->vl, 3, "PID: %ld", (long)v->pid); } AZ(close(v->fds[0])); AZ(close(v->fds[3])); v->fds[0] = v->fds[2]; v->fds[2] = v->fds[3] = -1; VSB_delete(vsb); AZ(pthread_create(&v->tp, NULL, varnish_thread, v)); AZ(pthread_create(&v->tp_vsl, NULL, varnishlog_thread, v)); /* Wait for the varnish to call home */ memset(fd, 0, sizeof fd); fd[0].fd = v->cli_fd; fd[0].events = POLLIN; fd[1].fd = v->fds[0]; fd[1].events = 0; /* Only care about POLLHUP, which is output-only */ i = poll(fd, 2, 10000); vtc_log(v->vl, 4, "CLIPOLL %d 0x%x 0x%x", i, fd[0].revents, fd[1].revents); if (i == 0) { vtc_log(v->vl, 0, "FAIL timeout waiting for CLI connection"); return; } if (fd[1].revents & POLLHUP) { vtc_log(v->vl, 0, "FAIL debug pipe closed"); return; } if (!(fd[0].revents & POLLIN)) { vtc_log(v->vl, 0, "FAIL CLI connection wait failure"); return; } nfd = accept(v->cli_fd, NULL, NULL); if (nfd < 0) { vtc_log(v->vl, 0, "FAIL no CLI connection accepted"); return; } AZ(close(v->cli_fd)); v->cli_fd = nfd; vtc_log(v->vl, 3, "CLI connection fd = %d", v->cli_fd); assert(v->cli_fd >= 0); /* Receive the banner or auth response */ u = varnish_ask_cli(v, NULL, &r); if (vtc_error) return; if (u != CLIS_AUTH) vtc_log(v->vl, 0, "CLI auth demand expected: %u %s", u, r); bprintf(abuf, "%s/_S", v->workdir); nfd = open(abuf, O_RDONLY); assert(nfd >= 0); assert(sizeof abuf >= CLI_AUTH_RESPONSE_LEN + 7); strcpy(abuf, "auth "); VCLI_AuthResponse(nfd, r, abuf + 5); AZ(close(nfd)); free(r); strcat(abuf, "\n"); u = varnish_ask_cli(v, abuf, &r); if (vtc_error) return; if (u != CLIS_OK) vtc_log(v->vl, 0, "CLI auth command failed: %u %s", u, r); free(r); (void)VSL_Arg(v->vd, 'n', v->workdir); AZ(VSC_Open(v->vd, 1)); }
static void cmd_http_txresp(CMD_ARGS) { struct http *hp; const char *proto = "HTTP/1.1"; const char *status = "200"; const char *msg = "Ok"; int bodylen = 0; char *b, *c; char *body = NULL, *nullbody; int nolen = 0; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); ONLY_SERVER(hp, av); assert(!strcmp(av[0], "txresp")); av++; VSB_clear(hp->vsb); /* send a "Content-Length: 0" header unless something else happens */ REPLACE(body, ""); nullbody = body; for(; *av != NULL; av++) { if (!strcmp(*av, "-proto")) { proto = av[1]; av++; } else if (!strcmp(*av, "-status")) { status = av[1]; av++; } else if (!strcmp(*av, "-msg")) { msg = av[1]; av++; continue; } else break; } VSB_printf(hp->vsb, "%s %s %s%s", proto, status, msg, nl); for(; *av != NULL; av++) { if (!strcmp(*av, "-nolen")) { nolen = 1; } else if (!strcmp(*av, "-hdr")) { VSB_printf(hp->vsb, "%s%s", av[1], nl); av++; } else break; } for(; *av != NULL; av++) { if (!strcmp(*av, "-body")) { assert(body == nullbody); REPLACE(body, av[1]); AN(body); av++; bodylen = strlen(body); for (b = body; *b != '\0'; b++) { if(*b == '\\' && b[1] == '0') { *b = '\0'; for(c = b+1; *c != '\0'; c++) { *c = c[1]; } b++; bodylen--; } } } else if (!strcmp(*av, "-bodylen")) { assert(body == nullbody); body = synth_body(av[1], 0); bodylen = strlen(body); av++; } else if (!strcmp(*av, "-gzipresidual")) { hp->gzipresidual = strtoul(av[1], NULL, 0); av++; } else if (!strcmp(*av, "-gziplevel")) { hp->gziplevel = strtoul(av[1], NULL, 0); av++; } else if (!strcmp(*av, "-gziplen")) { assert(body == nullbody); b = synth_body(av[1], 1); gzip_body(hp, b, &body, &bodylen); VSB_printf(hp->vsb, "Content-Encoding: gzip%s", nl); // vtc_hexdump(hp->vl, 4, "gzip", (void*)body, bodylen); av++; } else if (!strcmp(*av, "-gzipbody")) { assert(body == nullbody); gzip_body(hp, av[1], &body, &bodylen); VSB_printf(hp->vsb, "Content-Encoding: gzip%s", nl); // vtc_hexdump(hp->vl, 4, "gzip", (void*)body, bodylen); av++; } else break; } if (*av != NULL) vtc_log(hp->vl, 0, "Unknown http txresp spec: %s\n", *av); if (body != NULL && !nolen) VSB_printf(hp->vsb, "Content-Length: %d%s", bodylen, nl); VSB_cat(hp->vsb, nl); if (body != NULL) VSB_bcat(hp->vsb, body, bodylen); http_write(hp, 4, "txresp"); }
int exec_file(const char *fn, const char *script, const char *tmpdir, char *logbuf, unsigned loglen) { unsigned old_err; char *cwd, *p; FILE *f; struct extmacro *m; signal(SIGPIPE, SIG_IGN); vtc_loginit(logbuf, loglen); vltop = vtc_logopen("top"); AN(vltop); init_macro(); init_sema(); /* Apply extmacro definitions */ VTAILQ_FOREACH(m, &extmacro_list, list) macro_def(vltop, NULL, m->name, "%s", m->val); /* Other macro definitions */ cwd = getcwd(NULL, PATH_MAX); macro_def(vltop, NULL, "pwd", "%s", cwd); macro_def(vltop, NULL, "topbuild", "%s/%s", cwd, TOP_BUILDDIR); /* * We need an IP number which will not repond, ever, and that is a * lot harder than it sounds. This IP# is from RFC5737 and a * C-class broadcast at that. * If tests involving ${bad_ip} fails and you run linux, you should * check your /proc/sys/net/ipv4/ip_nonlocal_bind setting. */ macro_def(vltop, NULL, "bad_ip", "192.0.2.255"); /* Move into our tmpdir */ AZ(chdir(tmpdir)); macro_def(vltop, NULL, "tmpdir", "%s", tmpdir); /* Drop file to tell what was going on here */ f = fopen("INFO", "w"); AN(f); fprintf(f, "Test case: %s\n", fn); AZ(fclose(f)); vtc_stop = 0; vtc_desc = NULL; vtc_log(vltop, 1, "TEST %s starting", fn); p = strdup(script); AN(p); vtc_thread = pthread_self(); parse_string(p, cmds, NULL, vltop); old_err = vtc_error; vtc_stop = 1; vtc_log(vltop, 1, "RESETTING after %s", fn); reset_cmds(cmds); vtc_error = old_err; if (vtc_error) vtc_log(vltop, 1, "TEST %s FAILED", fn); else vtc_log(vltop, 1, "TEST %s completed", fn); free(vtc_desc); return (vtc_error); }
static void cmd_http_txreq(CMD_ARGS) { struct http *hp; const char *req = "GET"; const char *url = "/"; const char *proto = "HTTP/1.1"; const char *body = NULL; (void)cmd; (void)vl; CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC); ONLY_CLIENT(hp, av); assert(!strcmp(av[0], "txreq")); av++; VSB_clear(hp->vsb); for(; *av != NULL; av++) { if (!strcmp(*av, "-url")) { url = av[1]; av++; } else if (!strcmp(*av, "-proto")) { proto = av[1]; av++; } else if (!strcmp(*av, "-req")) { req = av[1]; av++; } else break; } VSB_printf(hp->vsb, "%s %s %s%s", req, url, proto, nl); for(; *av != NULL; av++) { if (!strcmp(*av, "-hdr")) { VSB_printf(hp->vsb, "%s%s", av[1], nl); av++; } else break; } for(; *av != NULL; av++) { if (!strcmp(*av, "-body")) { AZ(body); body = av[1]; av++; } else if (!strcmp(*av, "-bodylen")) { AZ(body); body = synth_body(av[1], 0); av++; } else break; } if (*av != NULL) vtc_log(hp->vl, 0, "Unknown http txreq spec: %s\n", *av); if (body != NULL) VSB_printf(hp->vsb, "Content-Length: %ju%s", (uintmax_t)strlen(body), nl); VSB_cat(hp->vsb, nl); if (body != NULL) { VSB_cat(hp->vsb, body); VSB_cat(hp->vsb, nl); } http_write(hp, 4, "txreq"); }