/* This function parses a "max-keep-alive-queue" statement in a proxy section. * It returns -1 if there is any error, 1 for a warning, otherwise zero. If it * does not return zero, it will write an error or warning message into a * preallocated buffer returned at <err>. The function must be called with * <args> pointing to the first command line word, with <proxy> pointing to * the proxy being parsed, and <defpx> to the default proxy or NULL. */ static int proxy_parse_max_ka_queue(char **args, int section, struct proxy *proxy, struct proxy *defpx, const char *file, int line, char **err) { int retval; char *res; unsigned int val; retval = 0; if (*args[1] == 0) { memprintf(err, "'%s' expects expects an integer value (or -1 to disable)", args[0]); return -1; } val = strtol(args[1], &res, 0); if (*res) { memprintf(err, "'%s' : unexpected character '%c' in integer value '%s'", args[0], *res, args[1]); return -1; } if (!(proxy->cap & PR_CAP_BE)) { memprintf(err, "%s will be ignored because %s '%s' has no backend capability", args[0], proxy_type_str(proxy), proxy->id); retval = 1; } /* we store <val+1> so that a user-facing value of -1 is stored as zero (default) */ proxy->max_ka_queue = val + 1; return retval; }
/* parse set-status action: * This action accepts a single argument of type int representing * an http status code. It returns ACT_RET_PRS_OK on success, * ACT_RET_PRS_ERR on error. */ static enum act_parse_ret parse_http_set_status(const char **args, int *orig_arg, struct proxy *px, struct act_rule *rule, char **err) { char *error; rule->action = ACT_CUSTOM; rule->action_ptr = action_http_set_status; /* Check if an argument is available */ if (!*args[*orig_arg]) { memprintf(err, "expects 1 argument: <status>; or 3 arguments: <status> reason <fmt>"); return ACT_RET_PRS_ERR; } /* convert status code as integer */ rule->arg.status.code = strtol(args[*orig_arg], &error, 10); if (*error != '\0' || rule->arg.status.code < 100 || rule->arg.status.code > 999) { memprintf(err, "expects an integer status code between 100 and 999"); return ACT_RET_PRS_ERR; } (*orig_arg)++; /* set custom reason string */ rule->arg.status.reason = NULL; // If null, we use the default reason for the status code. if (*args[*orig_arg] && strcmp(args[*orig_arg], "reason") == 0 && (*args[*orig_arg + 1] && strcmp(args[*orig_arg + 1], "if") != 0 && strcmp(args[*orig_arg + 1], "unless") != 0)) { (*orig_arg)++; rule->arg.status.reason = strdup(args[*orig_arg]); (*orig_arg)++; } return ACT_RET_PRS_OK; }
/* This function is used to validate the arguments passed to a "payload_lv" fetch * keyword. This keyword allows two positive integers and an optional signed one, * with the second one being strictly positive and the third one being greater than * the opposite of the two others if negative. It is assumed that the types are * already the correct ones. Returns 0 on error, non-zero if OK. If <err_msg> is * not NULL, it will be filled with a pointer to an error message in case of * error, that the caller is responsible for freeing. The initial location must * either be freeable or NULL. */ static int val_payload_lv(struct arg *arg, char **err_msg) { if (!arg[1].data.uint) { memprintf(err_msg, "payload length must be > 0"); return 0; } if (arg[2].type == ARGT_SINT && (int)(arg[0].data.uint + arg[1].data.uint + arg[2].data.sint) < 0) { memprintf(err_msg, "payload offset too negative"); return 0; } return 1; }
int regex_comp(const char *str, struct my_regex *regex, int cs, int cap, char **err) { /* copy the original regex format */ regex->regstr = strdup(str); if (!regex->regstr) { memprintf(err, "out of memory"); return 0; } #ifdef USE_PCRE_JIT int flags = 0; const char *error; int erroffset; if (!cs) flags |= PCRE_CASELESS; if (!cap) flags |= PCRE_NO_AUTO_CAPTURE; regex->reg = pcre_compile(str, flags, &error, &erroffset, NULL); if (!regex->reg) { free(regex->regstr); memprintf(err, "regex '%s' is invalid (error=%s, erroffset=%d)", str, error, erroffset); return 0; } regex->extra = pcre_study(regex->reg, PCRE_STUDY_JIT_COMPILE, &error); if (!regex->extra) { free(regex->regstr); pcre_free(regex->reg); memprintf(err, "failed to compile regex '%s' (error=%s)", str, error); return 0; } #else int flags = REG_EXTENDED; if (!cs) flags |= REG_ICASE; if (!cap) flags |= REG_NOSUB; if (regcomp(®ex->regex, str, flags) != 0) { free(regex->regstr); memprintf(err, "regex '%s' is invalid", str); return 0; } #endif return 1; }
static enum act_parse_ret parse_set_priority_offset(const char **args, int *arg, struct proxy *px, struct act_rule *rule, char **err) { unsigned int where = 0; rule->arg.expr = sample_parse_expr((char **)args, arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args); if (!rule->arg.expr) return ACT_RET_PRS_ERR; if (px->cap & PR_CAP_FE) where |= SMP_VAL_FE_HRQ_HDR; if (px->cap & PR_CAP_BE) where |= SMP_VAL_BE_HRQ_HDR; if (!(rule->arg.expr->fetch->val & where)) { memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[0], sample_src_names(rule->arg.expr->fetch->use)); free(rule->arg.expr); return ACT_RET_PRS_ERR; } rule->action = ACT_CUSTOM; rule->action_ptr = action_set_priority_offset; return ACT_RET_PRS_OK; }
/* This function parses a "rate-limit" statement in a proxy section. It returns * -1 if there is any error, 1 for a warning, otherwise zero. If it does not * return zero, it will write an error or warning message into a preallocated * buffer returned at <err>. The function must be called with <args> pointing * to the first command line word, with <proxy> pointing to the proxy being * parsed, and <defpx> to the default proxy or NULL. */ static int proxy_parse_rate_limit(char **args, int section, struct proxy *proxy, struct proxy *defpx, const char *file, int line, char **err) { int retval, cap; char *res; unsigned int *tv = NULL; unsigned int *td = NULL; unsigned int val; retval = 0; if (strcmp(args[1], "sessions") == 0) { tv = &proxy->fe_sps_lim; td = &defpx->fe_sps_lim; cap = PR_CAP_FE; } else { memprintf(err, "'%s' only supports 'sessions' (got '%s')", args[0], args[1]); return -1; } if (*args[2] == 0) { memprintf(err, "'%s %s' expects expects an integer value (in sessions/second)", args[0], args[1]); return -1; } val = strtoul(args[2], &res, 0); if (*res) { memprintf(err, "'%s %s' : unexpected character '%c' in integer value '%s'", args[0], args[1], *res, args[2]); return -1; } if (!(proxy->cap & cap)) { memprintf(err, "%s %s will be ignored because %s '%s' has no %s capability", args[0], args[1], proxy_type_str(proxy), proxy->id, (cap & PR_CAP_BE) ? "backend" : "frontend"); retval = 1; } else if (defpx && *tv != *td) { memprintf(err, "overwriting %s %s which was already specified", args[0], args[1]); retval = 1; } *tv = val; return retval; }
/* parse an http-request action among : * set-method * set-path * set-query * set-uri * * All of them accept a single argument of type string representing a log-format. * The resulting rule makes use of arg->act.p[0..1] to store the log-format list * head, and p[2] to store the action as an int (0=method, 1=path, 2=query, 3=uri). * It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error. */ static enum act_parse_ret parse_set_req_line(const char **args, int *orig_arg, struct proxy *px, struct act_rule *rule, char **err) { int cur_arg = *orig_arg; rule->action = ACT_CUSTOM; switch (args[0][4]) { case 'm' : rule->arg.http.action = 0; rule->action_ptr = http_action_set_req_line; break; case 'p' : rule->arg.http.action = 1; rule->action_ptr = http_action_set_req_line; break; case 'q' : rule->arg.http.action = 2; rule->action_ptr = http_action_set_req_line; break; case 'u' : rule->arg.http.action = 3; rule->action_ptr = http_action_set_req_line; break; default: memprintf(err, "internal error: unhandled action '%s'", args[0]); return ACT_RET_PRS_ERR; } if (!*args[cur_arg] || (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) { memprintf(err, "expects exactly 1 argument <format>"); return ACT_RET_PRS_ERR; } LIST_INIT(&rule->arg.http.logfmt); px->conf.args.ctx = ARGC_HRQ; if (!parse_logformat_string(args[cur_arg], px, &rule->arg.http.logfmt, LOG_OPT_HTTP, (px->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR, err)) { return ACT_RET_PRS_ERR; } (*orig_arg)++; return ACT_RET_PRS_OK; }
static void __comp_fetch_init(void) { char *ptr = NULL; int i; #ifdef USE_SLZ slz_make_crc_table(); slz_prepare_dist_table(); #endif #if defined(USE_ZLIB) && defined(DEFAULT_MAXZLIBMEM) global.maxzlibmem = DEFAULT_MAXZLIBMEM * 1024U * 1024U; #endif #ifdef USE_ZLIB HA_SPIN_INIT(&comp_pool_lock); memprintf(&ptr, "Built with zlib version : " ZLIB_VERSION); memprintf(&ptr, "%s\nRunning on zlib version : %s", ptr, zlibVersion()); #elif defined(USE_SLZ) memprintf(&ptr, "Built with libslz for stateless compression."); #else memprintf(&ptr, "Built without compression support (neither USE_ZLIB nor USE_SLZ are set)."); #endif memprintf(&ptr, "%s\nCompression algorithms supported :", ptr); for (i = 0; comp_algos[i].cfg_name; i++) memprintf(&ptr, "%s%s %s(\"%s\")", ptr, (i == 0 ? "" : ","), comp_algos[i].cfg_name, comp_algos[i].ua_name); if (i == 0) memprintf(&ptr, "%s none", ptr); hap_register_build_opts(ptr, 1); cfg_register_keywords(&cfg_kws); }
static void write_biu() { memprintf("write_biu %08x, %08x @%08x %u\n", address, word, psxRegs.pc, psxRegs.cycle); if (address != 0xfffe0130) return; switch (word) { case 0x800: case 0x804: pcsx_ram_is_ro = 1; break; case 0: case 0x1e988: pcsx_ram_is_ro = 0; break; default: memprintf("write_biu: unexpected val: %08x\n", word); break; } }
/* config parser for global "tune.zlibmemlevel" */ static int zlib_parse_global_memlevel(char **args, int section_type, struct proxy *curpx, struct proxy *defpx, const char *file, int line, char **err) { if (too_many_args(1, args, err, NULL)) return -1; if (*(args[1]) == 0) { memprintf(err, "'%s' expects a numeric value between 1 and 9.", args[0]); return -1; } global_tune_zlibmemlevel = atoi(args[1]); if (global_tune_zlibmemlevel < 1 || global_tune_zlibmemlevel > 9) { memprintf(err, "'%s' expects a numeric value between 1 and 9.", args[0]); return -1; } return 0; }
/* config parser for global "tune.zlibwindowsize" */ static int zlib_parse_global_windowsize(char **args, int section_type, struct proxy *curpx, struct proxy *defpx, const char *file, int line, char **err) { if (too_many_args(1, args, err, NULL)) return -1; if (*(args[1]) == 0) { memprintf(err, "'%s' expects a numeric value between 8 and 15.", args[0]); return -1; } global_tune_zlibwindowsize = atoi(args[1]); if (global_tune_zlibwindowsize < 8 || global_tune_zlibwindowsize > 15) { memprintf(err, "'%s' expects a numeric value between 8 and 15.", args[0]); return -1; } return 0; }
static int da_log_level(char **args, int section_type, struct proxy *curpx, struct proxy *defpx, const char *file, int line, char **err) { int loglevel; if (*(args[1]) == 0) { memprintf(err, "deviceatlas log level : expects an integer argument.\n"); return -1; } loglevel = atol(args[1]); if (loglevel < 0 || loglevel > 3) { memprintf(err, "deviceatlas log level : expects a log level between 0 and 3, %s given.\n", args[1]); } else { global_deviceatlas.loglevel = (da_severity_t)loglevel; } return 0; }
static int da_json_file(char **args, int section_type, struct proxy *curpx, struct proxy *defpx, const char *file, int line, char **err) { if (*(args[1]) == 0) { memprintf(err, "deviceatlas json file : expects a json path.\n"); return -1; } global_deviceatlas.jsonpath = strdup(args[1]); return 0; }
static int da_property_separator(char **args, int section_type, struct proxy *curpx, struct proxy *defpx, const char *file, int line, char **err) { if (*(args[1]) == 0) { memprintf(err, "deviceatlas property separator : expects a character argument.\n"); return -1; } global_deviceatlas.separator = *args[1]; return 0; }
static int _51d_cache_size(char **args, int section_type, struct proxy *curpx, struct proxy *defpx, const char *file, int line, char **err) { if (*(args[1]) == 0) { memprintf(err, "'%s' expects a positive numeric value.", args[0]); return -1; } global._51degrees.cache_size = atoi(args[1]); if (global._51degrees.cache_size < 0) { memprintf(err, "'%s' expects a positive numeric value, got '%s'.", args[0], args[1]); return -1; } return 0; }
static int _51d_property_separator(char **args, int section_type, struct proxy *curpx, struct proxy *defpx, const char *file, int line, char **err) { if (*(args[1]) == 0) { memprintf(err, "'%s' expects a single character.", args[0]); return -1; } if (strlen(args[1]) > 1) { memprintf(err, "'%s' expects a single character, got '%s'.", args[0], args[1]); return -1; } global._51degrees.property_separator = *args[1]; return 0; }
static int da_properties_cookie(char **args, int section_type, struct proxy *curpx, struct proxy *defpx, const char *file, int line, char **err) { if (*(args[1]) == 0) { memprintf(err, "deviceatlas cookie name : expects a string argument.\n"); return -1; } else { global_deviceatlas.cookiename = strdup(args[1]); } global_deviceatlas.cookienamelen = strlen(global_deviceatlas.cookiename); return 0; }
int regex_comp(const char *str, struct my_regex *regex, int cs, int cap, char **err) { #if defined(USE_PCRE) || defined(USE_PCRE_JIT) int flags = 0; const char *error; int erroffset; if (!cs) flags |= PCRE_CASELESS; if (!cap) flags |= PCRE_NO_AUTO_CAPTURE; regex->reg = pcre_compile(str, flags, &error, &erroffset, NULL); if (!regex->reg) { memprintf(err, "regex '%s' is invalid (error=%s, erroffset=%d)", str, error, erroffset); return 0; } regex->extra = pcre_study(regex->reg, PCRE_STUDY_JIT_COMPILE, &error); if (!regex->extra && error != NULL) { pcre_free(regex->reg); memprintf(err, "failed to compile regex '%s' (error=%s)", str, error); return 0; } #else int flags = REG_EXTENDED; if (!cs) flags |= REG_ICASE; if (!cap) flags |= REG_NOSUB; if (regcomp(®ex->regex, str, flags) != 0) { memprintf(err, "regex '%s' is invalid", str); return 0; } #endif return 1; }
/* Check an "http-response capture" action. * * The function returns 1 in success case, otherwise, it returns 0 and err is * filled. */ static int check_http_res_capture(struct act_rule *rule, struct proxy *px, char **err) { if (rule->action_ptr != http_action_res_capture_by_id) return 1; if (rule->arg.capid.idx >= px->nb_rsp_cap) { memprintf(err, "unable to find capture id '%d' referenced by http-response capture rule", rule->arg.capid.idx); return 0; } return 1; }
/* post-initializes the HTTP parts. Returns non-zero on error, with <err> * pointing to the error message. */ int init_http(char **err) { int msg; for (msg = 0; msg < HTTP_ERR_SIZE; msg++) { if (!http_err_msgs[msg]) { memprintf(err, "Internal error: no message defined for HTTP return code %d", msg); return 0; } http_err_chunks[msg].area = (char *)http_err_msgs[msg]; http_err_chunks[msg].data = strlen(http_err_msgs[msg]); } return 1; }
static int _51d_data_file(char **args, int section_type, struct proxy *curpx, struct proxy *defpx, const char *file, int line, char **err) { if (*(args[1]) == 0) { memprintf(err, "'%s' expects a filepath to a 51Degrees trie or pattern data file.", args[0]); return -1; } if (global._51degrees.data_file_path) free(global._51degrees.data_file_path); global._51degrees.data_file_path = strdup(args[1]); return 0; }
static int _51d_property_name_list(char **args, int section_type, struct proxy *curpx, struct proxy *defpx, const char *file, int line, char **err) { int cur_arg = 1; struct _51d_property_names *name; if (*(args[cur_arg]) == 0) { memprintf(err, "'%s' expects at least one 51Degrees property name.", args[0]); return -1; } while (*(args[cur_arg])) { name = calloc(1, sizeof(struct _51d_property_names)); name->name = strdup(args[cur_arg]); LIST_ADDQ(&global._51degrees.property_names, &name->list); ++cur_arg; } return 0; }
static void write_mem32() { memprintf("ari64_write_mem32 %08x, %08x @%08x %u\n", address, word, psxRegs.pc, psxRegs.cycle); psxMemWrite32(address, word); }
/* This function parses a "balance" statement in a backend section describing * <curproxy>. It returns -1 if there is any error, otherwise zero. If it * returns -1, it will write an error message into the <err> buffer which will * automatically be allocated and must be passed as NULL. The trailing '\n' * will not be written. The function must be called with <args> pointing to the * first word after "balance". */ int backend_parse_balance(const char **args, char **err, struct proxy *curproxy) { if (!*(args[0])) { /* if no option is set, use round-robin by default */ curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_RR; return 0; } if (!strcmp(args[0], "roundrobin")) { curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_RR; } else if (!strcmp(args[0], "static-rr")) { curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_SRR; } else if (!strcmp(args[0], "first")) { curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_FAS; } else if (!strcmp(args[0], "leastconn")) { curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_LC; } else if (!strcmp(args[0], "source")) { curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_SH; } else if (!strcmp(args[0], "uri")) { int arg = 1; curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_UH; curproxy->uri_whole = 0; while (*args[arg]) { if (!strcmp(args[arg], "len")) { if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) { memprintf(err, "%s : '%s' expects a positive integer (got '%s').", args[0], args[arg], args[arg+1]); return -1; } curproxy->uri_len_limit = atoi(args[arg+1]); arg += 2; } else if (!strcmp(args[arg], "depth")) { if (!*args[arg+1] || (atoi(args[arg+1]) <= 0)) { memprintf(err, "%s : '%s' expects a positive integer (got '%s').", args[0], args[arg], args[arg+1]); return -1; } /* hint: we store the position of the ending '/' (depth+1) so * that we avoid a comparison while computing the hash. */ curproxy->uri_dirs_depth1 = atoi(args[arg+1]) + 1; arg += 2; } else if (!strcmp(args[arg], "whole")) { curproxy->uri_whole = 1; arg += 1; } else { memprintf(err, "%s only accepts parameters 'len', 'depth', and 'whole' (got '%s').", args[0], args[arg]); return -1; } } } else if (!strcmp(args[0], "url_param")) { if (!*args[1]) { memprintf(err, "%s requires an URL parameter name.", args[0]); return -1; } curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_PH; free(curproxy->url_param_name); curproxy->url_param_name = strdup(args[1]); curproxy->url_param_len = strlen(args[1]); if (*args[2]) { if (strcmp(args[2], "check_post")) { memprintf(err, "%s only accepts 'check_post' modifier (got '%s').", args[0], args[2]); return -1; } } } else if (!strncmp(args[0], "hdr(", 4)) { const char *beg, *end; beg = args[0] + 4; end = strchr(beg, ')'); if (!end || end == beg) { memprintf(err, "hdr requires an http header field name."); return -1; } curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_HH; free(curproxy->hh_name); curproxy->hh_len = end - beg; curproxy->hh_name = my_strndup(beg, end - beg); curproxy->hh_match_domain = 0; if (*args[1]) { if (strcmp(args[1], "use_domain_only")) { memprintf(err, "%s only accepts 'use_domain_only' modifier (got '%s').", args[0], args[1]); return -1; } curproxy->hh_match_domain = 1; } } else if (!strncmp(args[0], "rdp-cookie", 10)) { curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_RCH; if ( *(args[0] + 10 ) == '(' ) { /* cookie name */ const char *beg, *end; beg = args[0] + 11; end = strchr(beg, ')'); if (!end || end == beg) { memprintf(err, "rdp-cookie : missing cookie name."); return -1; } free(curproxy->hh_name); curproxy->hh_name = my_strndup(beg, end - beg); curproxy->hh_len = end - beg; } else if ( *(args[0] + 10 ) == '\0' ) { /* default cookie name 'mstshash' */ free(curproxy->hh_name); curproxy->hh_name = strdup("mstshash"); curproxy->hh_len = strlen(curproxy->hh_name); } else { /* syntax */ memprintf(err, "rdp-cookie : missing cookie name."); return -1; } } else { memprintf(err, "only supports 'roundrobin', 'static-rr', 'leastconn', 'source', 'uri', 'url_param', 'hdr(name)' and 'rdp-cookie(name)' options."); return -1; } return 0; }
/* parse an "http-response capture" action. It takes a single argument which is * a sample fetch expression. It stores the expression into arg->act.p[0] and * the allocated hdr_cap struct od the preallocated id into arg->act.p[1]. * It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error. */ static enum act_parse_ret parse_http_res_capture(const char **args, int *orig_arg, struct proxy *px, struct act_rule *rule, char **err) { struct sample_expr *expr; int cur_arg; int id; char *error; for (cur_arg = *orig_arg; cur_arg < *orig_arg + 3 && *args[cur_arg]; cur_arg++) if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) break; if (cur_arg < *orig_arg + 3) { memprintf(err, "expects <expression> id <idx>"); return ACT_RET_PRS_ERR; } cur_arg = *orig_arg; expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args); if (!expr) return ACT_RET_PRS_ERR; if (!(expr->fetch->val & SMP_VAL_FE_HRS_HDR)) { memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[cur_arg-1], sample_src_names(expr->fetch->use)); free(expr); return ACT_RET_PRS_ERR; } if (!args[cur_arg] || !*args[cur_arg]) { memprintf(err, "expects 'id'"); free(expr); return ACT_RET_PRS_ERR; } if (strcmp(args[cur_arg], "id") != 0) { memprintf(err, "expects 'id', found '%s'", args[cur_arg]); free(expr); return ACT_RET_PRS_ERR; } cur_arg++; if (!args[cur_arg]) { memprintf(err, "missing id value"); free(expr); return ACT_RET_PRS_ERR; } id = strtol(args[cur_arg], &error, 10); if (*error != '\0') { memprintf(err, "cannot parse id '%s'", args[cur_arg]); free(expr); return ACT_RET_PRS_ERR; } cur_arg++; px->conf.args.ctx = ARGC_CAP; rule->action = ACT_CUSTOM; rule->action_ptr = http_action_res_capture_by_id; rule->check_ptr = check_http_res_capture; rule->arg.capid.expr = expr; rule->arg.capid.idx = id; *orig_arg = cur_arg; return ACT_RET_PRS_OK; }
static void write_mem16() { memprintf("ari64_write_mem16 %08x, %04x @%08x %u\n", address, hword, psxRegs.pc, psxRegs.cycle); psxMemWrite16(address, hword); }
static void read_mem32() { memprintf("ari64_read_mem32 %08x @%08x %u\n", address, psxRegs.pc, psxRegs.cycle); readmem_word = psxMemRead32(address); }
static void write_mem8() { memprintf("ari64_write_mem8 %08x, %02x @%08x %u\n", address, byte, psxRegs.pc, psxRegs.cycle); psxMemWrite8(address, byte); }
/* This function parses a "timeout" statement in a proxy section. It returns * -1 if there is any error, 1 for a warning, otherwise zero. If it does not * return zero, it will write an error or warning message into a preallocated * buffer returned at <err>. The trailing is not be written. The function must * be called with <args> pointing to the first command line word, with <proxy> * pointing to the proxy being parsed, and <defpx> to the default proxy or NULL. * As a special case for compatibility with older configs, it also accepts * "{cli|srv|con}timeout" in args[0]. */ static int proxy_parse_timeout(char **args, int section, struct proxy *proxy, struct proxy *defpx, const char *file, int line, char **err) { unsigned timeout; int retval, cap; const char *res, *name; int *tv = NULL; int *td = NULL; int warn = 0; retval = 0; /* simply skip "timeout" but remain compatible with old form */ if (strcmp(args[0], "timeout") == 0) args++; name = args[0]; if (!strcmp(args[0], "client") || (!strcmp(args[0], "clitimeout") && (warn = WARN_CLITO_DEPRECATED))) { name = "client"; tv = &proxy->timeout.client; td = &defpx->timeout.client; cap = PR_CAP_FE; } else if (!strcmp(args[0], "tarpit")) { tv = &proxy->timeout.tarpit; td = &defpx->timeout.tarpit; cap = PR_CAP_FE | PR_CAP_BE; } else if (!strcmp(args[0], "http-keep-alive")) { tv = &proxy->timeout.httpka; td = &defpx->timeout.httpka; cap = PR_CAP_FE | PR_CAP_BE; } else if (!strcmp(args[0], "http-request")) { tv = &proxy->timeout.httpreq; td = &defpx->timeout.httpreq; cap = PR_CAP_FE | PR_CAP_BE; } else if (!strcmp(args[0], "server") || (!strcmp(args[0], "srvtimeout") && (warn = WARN_SRVTO_DEPRECATED))) { name = "server"; tv = &proxy->timeout.server; td = &defpx->timeout.server; cap = PR_CAP_BE; } else if (!strcmp(args[0], "connect") || (!strcmp(args[0], "contimeout") && (warn = WARN_CONTO_DEPRECATED))) { name = "connect"; tv = &proxy->timeout.connect; td = &defpx->timeout.connect; cap = PR_CAP_BE; } else if (!strcmp(args[0], "check")) { tv = &proxy->timeout.check; td = &defpx->timeout.check; cap = PR_CAP_BE; } else if (!strcmp(args[0], "queue")) { tv = &proxy->timeout.queue; td = &defpx->timeout.queue; cap = PR_CAP_BE; } else if (!strcmp(args[0], "tunnel")) { tv = &proxy->timeout.tunnel; td = &defpx->timeout.tunnel; cap = PR_CAP_BE; } else if (!strcmp(args[0], "client-fin")) { tv = &proxy->timeout.clientfin; td = &defpx->timeout.clientfin; cap = PR_CAP_FE; } else if (!strcmp(args[0], "server-fin")) { tv = &proxy->timeout.serverfin; td = &defpx->timeout.serverfin; cap = PR_CAP_BE; } else { memprintf(err, "'timeout' supports 'client', 'server', 'connect', 'check', " "'queue', 'http-keep-alive', 'http-request', 'tunnel', 'tarpit', " "'client-fin' and 'server-fin' (got '%s')", args[0]); return -1; } if (*args[1] == 0) { memprintf(err, "'timeout %s' expects an integer value (in milliseconds)", name); return -1; } res = parse_time_err(args[1], &timeout, TIME_UNIT_MS); if (res) { memprintf(err, "unexpected character '%c' in 'timeout %s'", *res, name); return -1; } if (!(proxy->cap & cap)) { memprintf(err, "'timeout %s' will be ignored because %s '%s' has no %s capability", name, proxy_type_str(proxy), proxy->id, (cap & PR_CAP_BE) ? "backend" : "frontend"); retval = 1; } else if (defpx && *tv != *td) { memprintf(err, "overwriting 'timeout %s' which was already specified", name); retval = 1; } else if (warn) { if (!already_warned(warn)) { memprintf(err, "the '%s' directive is now deprecated in favor of 'timeout %s', and will not be supported in future versions.", args[0], name); retval = 1; } } if (*args[2] != 0) { memprintf(err, "'timeout %s' : unexpected extra argument '%s' after value '%s'.", name, args[2], args[1]); retval = -1; } *tv = MS_TO_TICKS(timeout); return retval; }
/* parse an "http-request capture" action. It takes a single argument which is * a sample fetch expression. It stores the expression into arg->act.p[0] and * the allocated hdr_cap struct or the preallocated "id" into arg->act.p[1]. * It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error. */ static enum act_parse_ret parse_http_req_capture(const char **args, int *orig_arg, struct proxy *px, struct act_rule *rule, char **err) { struct sample_expr *expr; struct cap_hdr *hdr; int cur_arg; int len = 0; for (cur_arg = *orig_arg; cur_arg < *orig_arg + 3 && *args[cur_arg]; cur_arg++) if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) break; if (cur_arg < *orig_arg + 3) { memprintf(err, "expects <expression> [ 'len' <length> | id <idx> ]"); return ACT_RET_PRS_ERR; } cur_arg = *orig_arg; expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args); if (!expr) return ACT_RET_PRS_ERR; if (!(expr->fetch->val & SMP_VAL_FE_HRQ_HDR)) { memprintf(err, "fetch method '%s' extracts information from '%s', none of which is available here", args[cur_arg-1], sample_src_names(expr->fetch->use)); free(expr); return ACT_RET_PRS_ERR; } if (!args[cur_arg] || !*args[cur_arg]) { memprintf(err, "expects 'len or 'id'"); free(expr); return ACT_RET_PRS_ERR; } if (strcmp(args[cur_arg], "len") == 0) { cur_arg++; if (!(px->cap & PR_CAP_FE)) { memprintf(err, "proxy '%s' has no frontend capability", px->id); return ACT_RET_PRS_ERR; } px->conf.args.ctx = ARGC_CAP; if (!args[cur_arg]) { memprintf(err, "missing length value"); free(expr); return ACT_RET_PRS_ERR; } /* we copy the table name for now, it will be resolved later */ len = atoi(args[cur_arg]); if (len <= 0) { memprintf(err, "length must be > 0"); free(expr); return ACT_RET_PRS_ERR; } cur_arg++; hdr = calloc(1, sizeof(*hdr)); hdr->next = px->req_cap; hdr->name = NULL; /* not a header capture */ hdr->namelen = 0; hdr->len = len; hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED); hdr->index = px->nb_req_cap++; px->req_cap = hdr; px->to_log |= LW_REQHDR; rule->action = ACT_CUSTOM; rule->action_ptr = http_action_req_capture; rule->arg.cap.expr = expr; rule->arg.cap.hdr = hdr; } else if (strcmp(args[cur_arg], "id") == 0) { int id; char *error; cur_arg++; if (!args[cur_arg]) { memprintf(err, "missing id value"); free(expr); return ACT_RET_PRS_ERR; } id = strtol(args[cur_arg], &error, 10); if (*error != '\0') { memprintf(err, "cannot parse id '%s'", args[cur_arg]); free(expr); return ACT_RET_PRS_ERR; } cur_arg++; px->conf.args.ctx = ARGC_CAP; rule->action = ACT_CUSTOM; rule->action_ptr = http_action_req_capture_by_id; rule->check_ptr = check_http_req_capture; rule->arg.capid.expr = expr; rule->arg.capid.idx = id; } else { memprintf(err, "expects 'len' or 'id', found '%s'", args[cur_arg]); free(expr); return ACT_RET_PRS_ERR; } *orig_arg = cur_arg; return ACT_RET_PRS_OK; }