/* Adds the session <sess> to the pending connection list of server <sess>->srv * or to the one of <sess>->proxy if srv is NULL. All counters and back pointers * are updated accordingly. Returns NULL if no memory is available, otherwise the * pendconn itself. If the session was already marked as served, its flag is * cleared. It is illegal to call this function with a non-NULL sess->srv_conn. */ struct pendconn *pendconn_add(struct session *sess) { struct pendconn *p; p = pool_alloc2(pool2_pendconn); if (!p) return NULL; sess->pend_pos = p; p->sess = sess; p->srv = sess->srv; if (sess->flags & SN_ASSIGNED && sess->srv) { LIST_ADDQ(&sess->srv->pendconns, &p->list); sess->srv->nbpend++; sess->logs.srv_queue_size += sess->srv->nbpend; if (sess->srv->nbpend > sess->srv->nbpend_max) sess->srv->nbpend_max = sess->srv->nbpend; } else { LIST_ADDQ(&sess->be->pendconns, &p->list); sess->be->nbpend++; sess->logs.prx_queue_size += sess->be->nbpend; if (sess->be->nbpend > sess->be->nbpend_max) sess->be->nbpend_max = sess->be->nbpend; } sess->be->totpend++; return p; }
/* Marks a ready listener as limited so that we only try to re-enable it when * resources are free again. It will be queued into the specified queue. */ void limit_listener(struct listener *l, struct list *list) { if (l->state == LI_READY) { LIST_ADDQ(list, &l->wait_queue); fd_stop_recv(l->fd); l->state = LI_LIMITED; } }
/* Marks a ready listener as limited so that we only try to re-enable it when * resources are free again. It will be queued into the specified queue. */ void limit_listener(struct listener *l, struct list *list) { if (l->state == LI_READY) { LIST_ADDQ(list, &l->wait_queue); EV_FD_CLR(l->fd, DIR_RD); l->state = LI_LIMITED; } }
/* * push to the logformat linked list * * start: start pointer * end: end text pointer * type: string type * list_format: destination list * * LOG_TEXT: copy chars from start to end excluding end. * */ void add_to_logformat_list(char *start, char *end, int type, struct list *list_format) { char *str; if (type == LF_TEXT) { /* type text */ struct logformat_node *node = calloc(1, sizeof(struct logformat_node)); str = calloc(end - start + 1, 1); strncpy(str, start, end - start); str[end - start] = '\0'; node->arg = str; node->type = LOG_FMT_TEXT; // type string LIST_ADDQ(list_format, &node->list); } else if (type == LF_SEPARATOR) { struct logformat_node *node = calloc(1, sizeof(struct logformat_node)); node->type = LOG_FMT_SEPARATOR; LIST_ADDQ(list_format, &node->list); } }
/* * Parse the sample fetch expression <text> and add a node to <list_format> upon * success. At the moment, sample converters are not yet supported but fetch arguments * should work. The curpx->conf.args.ctx must be set by the caller. */ void add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, const char *file, int line) { char *cmd[2]; struct sample_expr *expr; struct logformat_node *node; int cmd_arg; char *errmsg = NULL; cmd[0] = text; cmd[1] = ""; cmd_arg = 0; expr = sample_parse_expr(cmd, &cmd_arg, file, line, &errmsg, &curpx->conf.args); if (!expr) { Warning("parsing [%s:%d] : '%s' : sample fetch <%s> failed with : %s\n", curpx->conf.args.file, curpx->conf.args.line, fmt_directive(curpx), text, errmsg); return; } node = calloc(1, sizeof(struct logformat_node)); node->type = LOG_FMT_EXPR; node->expr = expr; node->options = options; if (arg_len) { node->arg = my_strndup(arg, arg_len); parse_logformat_var_args(node->arg, node); } if (expr->fetch->val & cap & SMP_VAL_REQUEST) node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */ if (expr->fetch->val & cap & SMP_VAL_RESPONSE) node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */ if (!(expr->fetch->val & cap)) Warning("parsing [%s:%d] : '%s' : sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here.\n", curpx->conf.args.file, curpx->conf.args.line, fmt_directive(curpx), text, sample_src_names(expr->fetch->use)); /* check if we need to allocate an hdr_idx struct for HTTP parsing */ /* Note, we may also need to set curpx->to_log with certain fetches */ curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY); /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags * needed with some sample fetches (eg: ssl*). We always set it for * now on, but this will leave with sample capabilities soon. */ curpx->to_log |= LW_XPRT; curpx->to_log |= LW_REQ; LIST_ADDQ(list_format, &node->list); }
/* * Parse a variable '%varname' or '%{args}varname' in log-format. The caller * must pass the args part in the <arg> pointer with its length in <arg_len>, * and varname with its length in <var> and <var_len> respectively. <arg> is * ignored when arg_len is 0. Neither <var> nor <var_len> may be null. */ int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions) { int j; struct logformat_node *node; for (j = 0; logformat_keywords[j].name; j++) { // search a log type if (strlen(logformat_keywords[j].name) == var_len && strncmp(var, logformat_keywords[j].name, var_len) == 0) { if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) { node = calloc(1, sizeof(struct logformat_node)); node->type = logformat_keywords[j].type; node->options = *defoptions; if (arg_len) { node->arg = my_strndup(arg, arg_len); parse_logformat_var_args(node->arg, node); } if (node->type == LOG_FMT_GLOBAL) { *defoptions = node->options; free(node->arg); free(node); } else { if (logformat_keywords[j].config_callback && logformat_keywords[j].config_callback(node, curproxy) != 0) { return -1; } curproxy->to_log |= logformat_keywords[j].lw; LIST_ADDQ(list_format, &node->list); } if (logformat_keywords[j].replace_by) Warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n", curproxy->conf.args.file, curproxy->conf.args.line, logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by); return 0; } else { Warning("parsing [%s:%d] : '%s' : format variable '%s' is reserved for HTTP mode.\n", curproxy->conf.args.file, curproxy->conf.args.line, fmt_directive(curproxy), logformat_keywords[j].name); return -1; } } } j = var[var_len]; var[var_len] = 0; Warning("parsing [%s:%d] : no such format variable '%s' in '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%' in log-format expressions.\n", curproxy->conf.args.file, curproxy->conf.args.line, var, fmt_directive(curproxy)); var[var_len] = j; return -1; }
void applet_run_active() { struct appctx *curr; struct stream_interface *si; if (LIST_ISEMPTY(&applet_active_queue)) return; /* move active queue to run queue */ applet_active_queue.n->p = &applet_cur_queue; applet_active_queue.p->n = &applet_cur_queue; applet_cur_queue = applet_active_queue; LIST_INIT(&applet_active_queue); /* The list is only scanned from the head. This guarantees that if any * applet removes another one, there is no side effect while walking * through the list. */ while (!LIST_ISEMPTY(&applet_cur_queue)) { curr = LIST_ELEM(applet_cur_queue.n, typeof(curr), runq); si = curr->owner; /* Now we'll try to allocate the input buffer. We wake up the * applet in all cases. So this is the applet responsibility to * check if this buffer was allocated or not. This let a chance * for applets to do some other processing if needed. */ if (!channel_alloc_buffer(si_ic(si), &curr->buffer_wait)) si_applet_cant_put(si); /* We always pretend the applet can't get and doesn't want to * put, it's up to it to change this if needed. This ensures * that one applet which ignores any event will not spin. */ si_applet_cant_get(si); si_applet_stop_put(si); curr->applet->fct(curr); si_applet_wake_cb(si); channel_release_buffer(si_ic(si), &curr->buffer_wait); if (applet_cur_queue.n == &curr->runq) { /* curr was left in the list, move it back to the active list */ LIST_DEL(&curr->runq); LIST_ADDQ(&applet_active_queue, &curr->runq); } } }
/* * Parse a variable '%varname' or '%{args}varname' in log-format. The caller * must pass the args part in the <arg> pointer with its length in <arg_len>, * and varname with its length in <var> and <var_len> respectively. <arg> is * ignored when arg_len is 0. Neither <var> nor <var_len> may be null. */ int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions) { int j; struct logformat_node *node; for (j = 0; logformat_keywords[j].name; j++) { // search a log type if (strlen(logformat_keywords[j].name) == var_len && strncmp(var, logformat_keywords[j].name, var_len) == 0) { if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) { node = calloc(1, sizeof(struct logformat_node)); node->type = logformat_keywords[j].type; node->options = *defoptions; if (arg_len) { node->arg = my_strndup(arg, arg_len); parse_logformat_var_args(node->arg, node); } if (node->type == LOG_FMT_GLOBAL) { *defoptions = node->options; free(node->arg); free(node); } else { if (logformat_keywords[j].config_callback && logformat_keywords[j].config_callback(node, curproxy) != 0) { return -1; } curproxy->to_log |= logformat_keywords[j].lw; LIST_ADDQ(list_format, &node->list); } if (logformat_keywords[j].replace_by) Warning("Warning: deprecated variable '%s' in log-format, please replace it with '%s'\n", logformat_keywords[j].name, logformat_keywords[j].replace_by); return 0; } else { Warning("Warning: log-format variable name '%s' is not suited to HTTP mode\n", logformat_keywords[j].name); return -1; } } } j = var[var_len]; var[var_len] = 0; Warning("Warning: no such variable name '%s' in log-format\n", var); var[var_len] = j; return -1; }
/* * Parse the sample fetch expression <text> and add a node to <list_format> upon * success. At the moment, sample converters are not yet supported but fetch arguments * should work. */ void add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options) { char *cmd[2]; struct sample_expr *expr; struct logformat_node *node; int cmd_arg; cmd[0] = text; cmd[1] = ""; cmd_arg = 0; expr = sample_parse_expr(cmd, &cmd_arg, trash.str, trash.size); if (!expr) { Warning("log-format: sample fetch <%s> failed with : %s\n", text, trash.str); return; } node = calloc(1, sizeof(struct logformat_node)); node->type = LOG_FMT_EXPR; node->expr = expr; node->options = options; if (arg_len) { node->arg = my_strndup(arg, arg_len); parse_logformat_var_args(node->arg, node); } if (expr->fetch->cap & SMP_CAP_REQ) node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */ if (expr->fetch->cap & SMP_CAP_RES) node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */ /* check if we need to allocate an hdr_idx struct for HTTP parsing */ /* Note, we may also need to set curpx->to_log with certain fetches */ if (expr->fetch->cap & SMP_CAP_L7) curpx->acl_requires |= ACL_USE_L7_ANY; /* FIXME: temporary workaround for missing LW_XPRT flag needed with some * sample fetches (eg: ssl*). We always set it for now on, but this will * leave with sample capabilities soon. */ curpx->to_log |= LW_XPRT; LIST_ADDQ(list_format, &node->list); }
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; }
/* * Create a new peer session in assigned state (connect will start automatically) */ static struct session *peer_session_create(struct peer *peer, struct peer_session *ps) { struct listener *l = ((struct proxy *)peer->peers->peers_fe)->listen; struct proxy *p = (struct proxy *)l->frontend; /* attached frontend */ struct session *s; struct http_txn *txn; struct task *t; if ((s = pool_alloc2(pool2_session)) == NULL) { /* disable this proxy for a while */ Alert("out of memory in event_accept().\n"); goto out_close; } LIST_ADDQ(&sessions, &s->list); LIST_INIT(&s->back_refs); s->flags = SN_ASSIGNED|SN_ADDR_SET; s->term_trace = 0; /* if this session comes from a known monitoring system, we want to ignore * it as soon as possible, which means closing it immediately for TCP. */ if ((t = task_new()) == NULL) { /* disable this proxy for a while */ Alert("out of memory in event_accept().\n"); goto out_free_session; } ps->reconnect = tick_add(now_ms, MS_TO_TICKS(5000)); ps->statuscode = PEER_SESSION_CONNECTCODE; t->process = l->handler; t->context = s; t->nice = l->nice; memcpy(&s->si[1].conn.addr.to, &peer->addr, sizeof(s->si[1].conn.addr.to)); s->task = t; s->listener = l; /* Note: initially, the session's backend points to the frontend. * This changes later when switching rules are executed or * when the default backend is assigned. */ s->be = s->fe = p; s->req = s->rep = NULL; /* will be allocated later */ s->si[0].conn.t.sock.fd = -1; s->si[0].conn.flags = CO_FL_NONE; s->si[0].owner = t; s->si[0].state = s->si[0].prev_state = SI_ST_EST; s->si[0].err_type = SI_ET_NONE; s->si[0].err_loc = NULL; s->si[0].release = NULL; s->si[0].send_proxy_ofs = 0; set_target_client(&s->si[0].conn.target, l); s->si[0].exp = TICK_ETERNITY; s->si[0].flags = SI_FL_NONE; if (s->fe->options2 & PR_O2_INDEPSTR) s->si[0].flags |= SI_FL_INDEP_STR; stream_int_register_handler(&s->si[0], &peer_applet); s->si[0].applet.st0 = PEER_SESSION_CONNECT; s->si[0].conn.data_ctx = (void *)ps; s->si[1].conn.t.sock.fd = -1; /* just to help with debugging */ s->si[1].conn.flags = CO_FL_NONE; s->si[1].owner = t; s->si[1].state = s->si[1].prev_state = SI_ST_ASS; s->si[1].conn_retries = p->conn_retries; s->si[1].err_type = SI_ET_NONE; s->si[1].err_loc = NULL; s->si[1].release = NULL; s->si[1].send_proxy_ofs = 0; set_target_proxy(&s->si[1].conn.target, s->be); si_prepare_conn(&s->si[1], peer->proto, peer->data); s->si[1].exp = TICK_ETERNITY; s->si[1].flags = SI_FL_NONE; if (s->be->options2 & PR_O2_INDEPSTR) s->si[1].flags |= SI_FL_INDEP_STR; session_init_srv_conn(s); set_target_proxy(&s->target, s->be); s->pend_pos = NULL; /* init store persistence */ s->store_count = 0; s->stkctr1_entry = NULL; s->stkctr2_entry = NULL; /* FIXME: the logs are horribly complicated now, because they are * defined in <p>, <p>, and later <be> and <be>. */ s->logs.logwait = 0; s->do_log = NULL; /* default error reporting function, may be changed by analysers */ s->srv_error = default_srv_error; s->uniq_id = 0; s->unique_id = NULL; txn = &s->txn; /* Those variables will be checked and freed if non-NULL in * session.c:session_free(). It is important that they are * properly initialized. */ txn->sessid = NULL; txn->srv_cookie = NULL; txn->cli_cookie = NULL; txn->uri = NULL; txn->req.cap = NULL; txn->rsp.cap = NULL; txn->hdr_idx.v = NULL; txn->hdr_idx.size = txn->hdr_idx.used = 0; if ((s->req = pool_alloc2(pool2_channel)) == NULL) goto out_fail_req; /* no memory */ s->req->buf.size = global.tune.bufsize; channel_init(s->req); s->req->prod = &s->si[0]; s->req->cons = &s->si[1]; s->si[0].ib = s->si[1].ob = s->req; s->req->flags |= CF_READ_ATTACHED; /* the producer is already connected */ /* activate default analysers enabled for this listener */ s->req->analysers = l->analysers; /* note: this should not happen anymore since there's always at least the switching rules */ if (!s->req->analysers) { channel_auto_connect(s->req);/* don't wait to establish connection */ channel_auto_close(s->req);/* let the producer forward close requests */ } s->req->rto = s->fe->timeout.client; s->req->wto = s->be->timeout.server; if ((s->rep = pool_alloc2(pool2_channel)) == NULL) goto out_fail_rep; /* no memory */ s->rep->buf.size = global.tune.bufsize; channel_init(s->rep); s->rep->prod = &s->si[1]; s->rep->cons = &s->si[0]; s->si[0].ob = s->si[1].ib = s->rep; s->rep->rto = s->be->timeout.server; s->rep->wto = s->fe->timeout.client; s->req->rex = TICK_ETERNITY; s->req->wex = TICK_ETERNITY; s->req->analyse_exp = TICK_ETERNITY; s->rep->rex = TICK_ETERNITY; s->rep->wex = TICK_ETERNITY; s->rep->analyse_exp = TICK_ETERNITY; t->expire = TICK_ETERNITY; s->rep->flags |= CF_READ_DONTWAIT; /* it is important not to call the wakeup function directly but to * pass through task_wakeup(), because this one knows how to apply * priorities to tasks. */ task_wakeup(t, TASK_WOKEN_INIT); l->nbconn++; /* warning! right now, it's up to the handler to decrease this */ p->feconn++;/* beconn will be increased later */ jobs++; if (!(s->listener->options & LI_O_UNLIMITED)) actconn++; totalconn++; return s; /* Error unrolling */ out_fail_rep: pool_free2(pool2_channel, s->req); out_fail_req: task_free(t); out_free_session: LIST_DEL(&s->list); pool_free2(pool2_session, s); out_close: return s; }