src/session.c
int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
{
	struct proxy *p = l->frontend;
	struct session *s;
	struct task *t;
	int ret;


	ret = -1; /* assume unrecoverable error by default */

	if (unlikely((s = pool_alloc2(pool2_session)) == NULL))
		goto out_close;

	if (unlikely((s->si[0].conn = pool_alloc2(pool2_connection)) == NULL))
		goto out_fail_conn0;

	if (unlikely((s->si[1].conn = pool_alloc2(pool2_connection)) == NULL))
		goto out_fail_conn1;

	/* minimum session initialization required for an embryonic session is
	 * fairly low. We need very little to execute L4 ACLs, then we need a
	 * task to make the client-side connection live on its own.
	 *  - flags
	 *  - stick-entry tracking
	 */
	s->flags = 0;
	s->logs.logwait = p->to_log;
	s->stkctr[0].entry = NULL;
	s->stkctr[1].entry = NULL;
	s->stkctr[0].table = NULL;
	s->stkctr[1].table = NULL;

	s->listener = l;
	s->fe  = p;

	/* OK, we're keeping the session, so let's properly initialize the session */
	s->si[0].conn->t.sock.fd = cfd;
	s->si[0].conn->ctrl = l->proto;
	s->si[0].conn->flags = CO_FL_NONE;
	s->si[0].conn->err_code = CO_ER_NONE;
	s->si[0].conn->addr.from = *addr;
	s->si[0].conn->target = &l->obj_type;

	s->logs.accept_date = date; /* user-visible date for logging */
	s->logs.tv_accept = now;  /* corrected date for internal use */
	s->uniq_id = totalconn;
	p->feconn++;
	/* This session was accepted, count it now */
	if (p->feconn > p->fe_counters.conn_max)
		p->fe_counters.conn_max = p->feconn;

	proxy_inc_fe_conn_ctr(l, p);

	/* now evaluate the tcp-request layer4 rules. Since we expect to be able
	 * to abort right here as soon as possible, we check the rules before
	 * even initializing the stream interfaces.
	 */
	if ((l->options & LI_O_TCP_RULES) && !tcp_exec_req_rules(s)) {
		/* let's do a no-linger now to close with a single RST. */
		setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
		ret = 0; /* successful termination */
		goto out_free_session;
	}

#ifndef USE_ACCEPT4
	/* Adjust some socket options if the connection was accepted by a plain
	 * accept() syscall.
	 */
	if (unlikely(fcntl(cfd, F_SETFL, O_NONBLOCK) == -1))
		goto out_free_session;
#endif

	/* monitor-net and health mode are processed immediately after TCP
	 * connection rules. This way it's possible to block them, but they
	 * never use the lower data layers, they send directly over the socket,
	 * as they were designed for. We first flush the socket receive buffer
	 * in order to avoid emission of an RST by the system. We ignore any
	 * error.
	 */
	if (unlikely((p->mode == PR_MODE_HEALTH) ||
		     ((l->options & LI_O_CHK_MONNET) &&
		      addr->ss_family == AF_INET &&
		      (((struct sockaddr_in *)addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr))) {
		/* we have 4 possibilities here :
		 *  - HTTP mode, from monitoring address => send "HTTP/1.0 200 OK"
		 *  - HEALTH mode with HTTP check => send "HTTP/1.0 200 OK"
		 *  - HEALTH mode without HTTP check => just send "OK"
		 *  - TCP mode from monitoring address => just close
		 */
		recv(cfd, trash.str, trash.size, MSG_DONTWAIT);
		if (p->mode == PR_MODE_HTTP ||
		    (p->mode == PR_MODE_HEALTH && (p->options2 & PR_O2_CHK_ANY) == PR_O2_HTTP_CHK))
			send(cfd, "HTTP/1.0 200 OK\r\n\r\n", 19, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE);
		else if (p->mode == PR_MODE_HEALTH)
			send(cfd, "OK\n", 3, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE);
		ret = 0;
		goto out_free_session;
	}


	/* wait for a PROXY protocol header */
	if (l->options & LI_O_ACC_PROXY) {
		s->si[0].conn->flags |= CO_FL_ACCEPT_PROXY;
		conn_sock_want_recv(s->si[0].conn);
	}

	if (unlikely((t = task_new()) == NULL))
		goto out_free_session;

	t->context = s;
	t->nice = l->nice;
	s->task = t;

	/* Add the various callbacks. Right now the transport layer is present
	 * but not initialized. Also note we need to be careful as the stream
	 * int is not initialized yet.
	 */
	conn_prepare(s->si[0].conn, &sess_conn_cb, l->proto, l->xprt, s);

	/* finish initialization of the accepted file descriptor */
	fd_insert(cfd);
	fdtab[cfd].owner = s->si[0].conn;
	fdtab[cfd].iocb = conn_fd_handler;
	conn_data_want_recv(s->si[0].conn);
	if (conn_xprt_init(s->si[0].conn) < 0)
		goto out_free_task;

	/* OK, now either we have a pending handshake to execute with and
	 * then we must return to the I/O layer, or we can proceed with the
	 * end of the session initialization. In case of handshake, we also
	 * set the I/O timeout to the frontend's client timeout.
	 */

	if (s->si[0].conn->flags & CO_FL_HANDSHAKE) {
		t->process = expire_mini_session;
		t->expire = tick_add_ifset(now_ms, p->timeout.client);
		task_queue(t);
		s->si[0].conn->flags |= CO_FL_INIT_DATA | CO_FL_WAKE_DATA;
		return 1;
	}

	/* OK let's complete session initialization since there is no handshake */
	s->si[0].conn->flags |= CO_FL_CONNECTED;
	ret = session_complete(s);
	if (ret > 0)
		return ret;

	/* Error unrolling */
 out_free_task:
	task_free(t);
 out_free_session:
	p->feconn--;
	if (s->stkctr[0].entry || s->stkctr[1].entry)
		session_store_counters(s);
	pool_free2(pool2_connection, s->si[1].conn);
 out_fail_conn1:
	pool_free2(pool2_connection, s->si[0].conn);
 out_fail_conn0:
	pool_free2(pool2_session, s);
 out_close:
	if (ret < 0 && l->xprt == &raw_sock && p->mode == PR_MODE_HTTP) {
		/* critical error, no more memory, try to emit a 500 response */
		struct chunk *err_msg = http_error_message(s, HTTP_ERR_500);
		send(cfd, err_msg->str, err_msg->len, MSG_DONTWAIT|MSG_NOSIGNAL);
	}

	if (fdtab[cfd].owner)
		fd_delete(cfd);
	else
		close(cfd);
	return ret;
}
/* This function is called from the protocol layer accept() in order to
 * instanciate a new embryonic session on behalf of a given listener and
 * frontend. It returns a positive value upon success, 0 if the connection
 * can be ignored, or a negative value upon critical failure. The accepted
 * file descriptor is closed if we return <= 0.
 */
This function is called from the protocol layer accept() in order to
instanciate a new embryonic session on behalf of a given listener and
frontend. It returns a positive value upon success, 0 if the connection
can be ignored, or a negative value upon critical failure. The accepted
file descriptor is closed if we return <= 0.
This function is called from the protocol layer accept () in order to instanciate a new embryonic session on behalf of a given listener and frontend . It returns a positive value upon success 0 if the connection can be ignored or a negative value upon critical failure . The accepted file descriptor is closed if we return < = 0 .
int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
{
	struct proxy *p = l->frontend;
	struct session *s;
	struct task *t;
	int ret;
	ret = -1; 
	if (unlikely((s = pool_alloc2(pool2_session)) == NULL))
		goto out_close;
	if (unlikely((s->si[0].conn = pool_alloc2(pool2_connection)) == NULL))
		goto out_fail_conn0;
	if (unlikely((s->si[1].conn = pool_alloc2(pool2_connection)) == NULL))
		goto out_fail_conn1;
	s->flags = 0;
	s->logs.logwait = p->to_log;
	s->stkctr[0].entry = NULL;
	s->stkctr[1].entry = NULL;
	s->stkctr[0].table = NULL;
	s->stkctr[1].table = NULL;
	s->listener = l;
	s->fe  = p;
	s->si[0].conn->t.sock.fd = cfd;
	s->si[0].conn->ctrl = l->proto;
	s->si[0].conn->flags = CO_FL_NONE;
	s->si[0].conn->err_code = CO_ER_NONE;
	s->si[0].conn->addr.from = *addr;
	s->si[0].conn->target = &l->obj_type;
	s->logs.accept_date = date; 
	s->logs.tv_accept = now;  
	s->uniq_id = totalconn;
	p->feconn++;
	if (p->feconn > p->fe_counters.conn_max)
		p->fe_counters.conn_max = p->feconn;
	proxy_inc_fe_conn_ctr(l, p);
	if ((l->options & LI_O_TCP_RULES) && !tcp_exec_req_rules(s)) {
		setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
		ret = 0; 
		goto out_free_session;
	}
#ifndef USE_ACCEPT4
	if (unlikely(fcntl(cfd, F_SETFL, O_NONBLOCK) == -1))
		goto out_free_session;
#endif
	if (unlikely((p->mode == PR_MODE_HEALTH) ||
		     ((l->options & LI_O_CHK_MONNET) &&
		      addr->ss_family == AF_INET &&
		      (((struct sockaddr_in *)addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr))) {
		recv(cfd, trash.str, trash.size, MSG_DONTWAIT);
		if (p->mode == PR_MODE_HTTP ||
		    (p->mode == PR_MODE_HEALTH && (p->options2 & PR_O2_CHK_ANY) == PR_O2_HTTP_CHK))
			send(cfd, "HTTP/1.0 200 OK\r\n\r\n", 19, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE);
		else if (p->mode == PR_MODE_HEALTH)
			send(cfd, "OK\n", 3, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE);
		ret = 0;
		goto out_free_session;
	}
	if (l->options & LI_O_ACC_PROXY) {
		s->si[0].conn->flags |= CO_FL_ACCEPT_PROXY;
		conn_sock_want_recv(s->si[0].conn);
	}
	if (unlikely((t = task_new()) == NULL))
		goto out_free_session;
	t->context = s;
	t->nice = l->nice;
	s->task = t;
	conn_prepare(s->si[0].conn, &sess_conn_cb, l->proto, l->xprt, s);
	fd_insert(cfd);
	fdtab[cfd].owner = s->si[0].conn;
	fdtab[cfd].iocb = conn_fd_handler;
	conn_data_want_recv(s->si[0].conn);
	if (conn_xprt_init(s->si[0].conn) < 0)
		goto out_free_task;
	if (s->si[0].conn->flags & CO_FL_HANDSHAKE) {
		t->process = expire_mini_session;
		t->expire = tick_add_ifset(now_ms, p->timeout.client);
		task_queue(t);
		s->si[0].conn->flags |= CO_FL_INIT_DATA | CO_FL_WAKE_DATA;
		return 1;
	}
	s->si[0].conn->flags |= CO_FL_CONNECTED;
	ret = session_complete(s);
	if (ret > 0)
		return ret;
 out_free_task:
	task_free(t);
 out_free_session:
	p->feconn--;
	if (s->stkctr[0].entry || s->stkctr[1].entry)
		session_store_counters(s);
	pool_free2(pool2_connection, s->si[1].conn);
 out_fail_conn1:
	pool_free2(pool2_connection, s->si[0].conn);
 out_fail_conn0:
	pool_free2(pool2_session, s);
 out_close:
	if (ret < 0 && l->xprt == &raw_sock && p->mode == PR_MODE_HTTP) {
		struct chunk *err_msg = http_error_message(s, HTTP_ERR_500);
		send(cfd, err_msg->str, err_msg->len, MSG_DONTWAIT|MSG_NOSIGNAL);
	}
	if (fdtab[cfd].owner)
		fd_delete(cfd);
	else
		close(cfd);
	return ret;
}
int session_accept ( struct listener * l , int cfd , struct sockaddr_storage * addr ) { struct proxy * p = l -> frontend ; struct session * s ; struct task * t ; int ret ; ret = -1 ; if ( unlikely ( ( s = pool_alloc2 ( pool2_session ) ) == NULL ) ) goto out_close ; if ( unlikely ( ( s -> si [ 0 ] . conn = pool_alloc2 ( pool2_connection ) ) == NULL ) ) goto out_fail_conn0 ; if ( unlikely ( ( s -> si [ 1 ] . conn = pool_alloc2 ( pool2_connection ) ) == NULL ) ) goto out_fail_conn1 ; s -> flags = 0 ; s -> logs . logwait = p -> to_log ; s -> stkctr [ 0 ] . entry = NULL ; s -> stkctr [ 1 ] . entry = NULL ; s -> stkctr [ 0 ] . table = NULL ; s -> stkctr [ 1 ] . table = NULL ; s -> listener = l ; s -> fe = p ; s -> si [ 0 ] . conn -> t . sock . fd = cfd ; s -> si [ 0 ] . conn -> ctrl = l -> proto ; s -> si [ 0 ] . conn -> flags = CO_FL_NONE ; s -> si [ 0 ] . conn -> err_code = CO_ER_NONE ; s -> si [ 0 ] . conn -> addr . from = * addr ; s -> si [ 0 ] . conn -> target = & l -> obj_type ; s -> logs . accept_date = date ; s -> logs . tv_accept = now ; s -> uniq_id = totalconn ; p -> feconn ++ ; if ( p -> feconn > p -> fe_counters . conn_max ) p -> fe_counters . conn_max = p -> feconn ; proxy_inc_fe_conn_ctr ( l , p ) ; if ( ( l -> options & LI_O_TCP_RULES ) && ! tcp_exec_req_rules ( s ) ) { setsockopt ( cfd , SOL_SOCKET , SO_LINGER , ( struct linger * ) & nolinger , sizeof ( struct linger ) ) ; ret = 0 ; goto out_free_session ; } #ifndef USE_ACCEPT4 if ( unlikely ( fcntl ( cfd , F_SETFL , O_NONBLOCK ) == -1 ) ) goto out_free_session ; #endif if ( unlikely ( ( p -> mode == PR_MODE_HEALTH ) || ( ( l -> options & LI_O_CHK_MONNET ) && addr -> ss_family == AF_INET && ( ( ( struct sockaddr_in * ) addr ) -> sin_addr . s_addr & p -> mon_mask . s_addr ) == p -> mon_net . s_addr ) ) ) { recv ( cfd , trash . str , trash . size , MSG_DONTWAIT ) ; if ( p -> mode == PR_MODE_HTTP || ( p -> mode == PR_MODE_HEALTH && ( p -> options2 & PR_O2_CHK_ANY ) == PR_O2_HTTP_CHK ) ) send ( cfd , " \r \n \r \n " , 19 , MSG_DONTWAIT | MSG_NOSIGNAL | MSG_MORE ) ; else if ( p -> mode == PR_MODE_HEALTH ) send ( cfd , " \n " , 3 , MSG_DONTWAIT | MSG_NOSIGNAL | MSG_MORE ) ; ret = 0 ; goto out_free_session ; } if ( l -> options & LI_O_ACC_PROXY ) { s -> si [ 0 ] . conn -> flags |= CO_FL_ACCEPT_PROXY ; conn_sock_want_recv ( s -> si [ 0 ] . conn ) ; } if ( unlikely ( ( t = task_new ( ) ) == NULL ) ) goto out_free_session ; t -> context = s ; t -> nice = l -> nice ; s -> task = t ; conn_prepare ( s -> si [ 0 ] . conn , & sess_conn_cb , l -> proto , l -> xprt , s ) ; fd_insert ( cfd ) ; fdtab [ cfd ] . owner = s -> si [ 0 ] . conn ; fdtab [ cfd ] . iocb = conn_fd_handler ; conn_data_want_recv ( s -> si [ 0 ] . conn ) ; if ( conn_xprt_init ( s -> si [ 0 ] . conn ) < 0 ) goto out_free_task ; if ( s -> si [ 0 ] . conn -> flags & CO_FL_HANDSHAKE ) { t -> process = expire_mini_session ; t -> expire = tick_add_ifset ( now_ms , p -> timeout . client ) ; task_queue ( t ) ; s -> si [ 0 ] . conn -> flags |= CO_FL_INIT_DATA | CO_FL_WAKE_DATA ; return 1 ; } s -> si [ 0 ] . conn -> flags |= CO_FL_CONNECTED ; ret = session_complete ( s ) ; if ( ret > 0 ) return ret ; out_free_task : task_free ( t ) ; out_free_session : p -> feconn -- ; if ( s -> stkctr [ 0 ] . entry || s -> stkctr [ 1 ] . entry ) session_store_counters ( s ) ; pool_free2 ( pool2_connection , s -> si [ 1 ] . conn ) ; out_fail_conn1 : pool_free2 ( pool2_connection , s -> si [ 0 ] . conn ) ; out_fail_conn0 : pool_free2 ( pool2_session , s ) ; out_close : if ( ret < 0 && l -> xprt == & raw_sock && p -> mode == PR_MODE_HTTP ) { struct chunk * err_msg = http_error_message ( s , HTTP_ERR_500 ) ; send ( cfd , err_msg -> str , err_msg -> len , MSG_DONTWAIT | MSG_NOSIGNAL ) ; } if ( fdtab [ cfd ] . owner ) fd_delete ( cfd ) ; else close ( cfd ) ; return ret ; }
This function is called from the protocol layer accept() in order to
 instanciate a new embryonic session on behalf of a given listener and
 frontend.
This function is called from the protocol layer accept () in order to instanciate a new embryonic session on behalf of a given listener and frontend .
/* assume unrecoverable error by default */ /* minimum session initialization required for an embryonic session is
	 * fairly low. We need very little to execute L4 ACLs, then we need a
	 * task to make the client-side connection live on its own.
	 *  - flags
	 *  - stick-entry tracking
	 */ /* OK, we're keeping the session, so let's properly initialize the session */ /* user-visible date for logging */ /* corrected date for internal use */ /* This session was accepted, count it now */ /* now evaluate the tcp-request layer4 rules. Since we expect to be able
	 * to abort right here as soon as possible, we check the rules before
	 * even initializing the stream interfaces.
	 */ /* let's do a no-linger now to close with a single RST. */ /* successful termination */ /* Adjust some socket options if the connection was accepted by a plain
	 * accept() syscall.
	 */ /* monitor-net and health mode are processed immediately after TCP
	 * connection rules. This way it's possible to block them, but they
	 * never use the lower data layers, they send directly over the socket,
	 * as they were designed for. We first flush the socket receive buffer
	 * in order to avoid emission of an RST by the system. We ignore any
	 * error.
	 */ /* we have 4 possibilities here :
		 *  - HTTP mode, from monitoring address => send "HTTP/1.0 200 OK"
		 *  - HEALTH mode with HTTP check => send "HTTP/1.0 200 OK"
		 *  - HEALTH mode without HTTP check => just send "OK"
		 *  - TCP mode from monitoring address => just close
		 */ /* wait for a PROXY protocol header */ /* Add the various callbacks. Right now the transport layer is present
	 * but not initialized. Also note we need to be careful as the stream
	 * int is not initialized yet.
	 */ /* finish initialization of the accepted file descriptor */ /* OK, now either we have a pending handshake to execute with and
	 * then we must return to the I/O layer, or we can proceed with the
	 * end of the session initialization. In case of handshake, we also
	 * set the I/O timeout to the frontend's client timeout.
	 */ /* OK let's complete session initialization since there is no handshake */ /* Error unrolling */ /* critical error, no more memory, try to emit a 500 response */