Beispiel #1
0
/* 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;
}
Beispiel #2
0
/* 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;
	}
}
Beispiel #3
0
/* 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;
	}
}
Beispiel #4
0
/*
 *  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);
	}
}
Beispiel #5
0
/*
 * 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);
}
Beispiel #6
0
/*
 * 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;
}
Beispiel #7
0
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);
		}
	}
}
Beispiel #8
0
/*
 * 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;
}
Beispiel #9
0
/*
 * 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);
}
Beispiel #10
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;
}
Beispiel #11
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;
}