src/ssl_sock.c
int ssl_sock_handshake(struct connection *conn, unsigned int flag)
{
	int ret;

	if (!conn->xprt_ctx)
		goto out_error;

	/* If we use SSL_do_handshake to process a reneg initiated by
	 * the remote peer, it sometimes returns SSL_ERROR_SSL.
	 * Usually SSL_write and SSL_read are used and process implicitly
	 * the reneg handshake.
	 * Here we use SSL_peek as a workaround for reneg.
	 */
	if ((conn->flags & CO_FL_CONNECTED) && SSL_renegotiate_pending(conn->xprt_ctx)) {
		char c;

		ret = SSL_peek(conn->xprt_ctx, &c, 1);
		if (ret <= 0) {
			/* handshake may have not been completed, let's find why */
			ret = SSL_get_error(conn->xprt_ctx, ret);
			if (ret == SSL_ERROR_WANT_WRITE) {
				/* SSL handshake needs to write, L4 connection may not be ready */
				__conn_sock_stop_recv(conn);
				__conn_sock_poll_send(conn);
				return 0;
			}
			else if (ret == SSL_ERROR_WANT_READ) {
				/* handshake may have been completed but we have
				 * no more data to read.
                                 */
				if (!SSL_renegotiate_pending(conn->xprt_ctx)) {
					ret = 1;
					goto reneg_ok;
				}
				/* SSL handshake needs to read, L4 connection is ready */
				if (conn->flags & CO_FL_WAIT_L4_CONN)
					conn->flags &= ~CO_FL_WAIT_L4_CONN;
				__conn_sock_stop_send(conn);
				__conn_sock_poll_recv(conn);
				return 0;
			}
			else if (ret == SSL_ERROR_SYSCALL) {
				/* if errno is null, then connection was successfully established */
				if (!errno && conn->flags & CO_FL_WAIT_L4_CONN)
					conn->flags &= ~CO_FL_WAIT_L4_CONN;
				if (!conn->err_code) {
					if (!((SSL *)conn->xprt_ctx)->packet_length)
						if (!errno)
							conn->err_code = CO_ER_SSL_EMPTY;
						else
							conn->err_code = CO_ER_SSL_ABORT;
					else
						conn->err_code = CO_ER_SSL_HANDSHAKE;
				}
				goto out_error;
			}
			else {
				/* Fail on all other handshake errors */
				/* Note: OpenSSL may leave unread bytes in the socket's
				 * buffer, causing an RST to be emitted upon close() on
				 * TCP sockets. We first try to drain possibly pending
				 * data to avoid this as much as possible.
				 */
				ret = recv(conn->t.sock.fd, trash.str, trash.size, MSG_NOSIGNAL|MSG_DONTWAIT);
				if (!conn->err_code)
					conn->err_code = CO_ER_SSL_HANDSHAKE;
				goto out_error;
			}
		}
		/* read some data: consider handshake completed */
		goto reneg_ok;
	}

	ret = SSL_do_handshake(conn->xprt_ctx);
	if (ret != 1) {
		/* handshake did not complete, let's find why */
		ret = SSL_get_error(conn->xprt_ctx, ret);

		if (ret == SSL_ERROR_WANT_WRITE) {
			/* SSL handshake needs to write, L4 connection may not be ready */
			__conn_sock_stop_recv(conn);
			__conn_sock_poll_send(conn);
			return 0;
		}
		else if (ret == SSL_ERROR_WANT_READ) {
			/* SSL handshake needs to read, L4 connection is ready */
			if (conn->flags & CO_FL_WAIT_L4_CONN)
				conn->flags &= ~CO_FL_WAIT_L4_CONN;
			__conn_sock_stop_send(conn);
			__conn_sock_poll_recv(conn);
			return 0;
		}
		else if (ret == SSL_ERROR_SYSCALL) {
			/* if errno is null, then connection was successfully established */
			if (!errno && conn->flags & CO_FL_WAIT_L4_CONN)
				conn->flags &= ~CO_FL_WAIT_L4_CONN;

			if (!((SSL *)conn->xprt_ctx)->packet_length)
				if (!errno)
					conn->err_code = CO_ER_SSL_EMPTY;
				else
					conn->err_code = CO_ER_SSL_ABORT;
			else
				conn->err_code = CO_ER_SSL_HANDSHAKE;
			goto out_error;
		}
		else {
			/* Fail on all other handshake errors */
			/* Note: OpenSSL may leave unread bytes in the socket's
			 * buffer, causing an RST to be emitted upon close() on
			 * TCP sockets. We first try to drain possibly pending
			 * data to avoid this as much as possible.
			 */
			ret = recv(conn->t.sock.fd, trash.str, trash.size, MSG_NOSIGNAL|MSG_DONTWAIT);
			if (!conn->err_code)
				conn->err_code = CO_ER_SSL_HANDSHAKE;
			goto out_error;
		}
	}

reneg_ok:

	/* Handshake succeeded */
	if (objt_server(conn->target)) {
		if (!SSL_session_reused(conn->xprt_ctx)) {
			/* check if session was reused, if not store current session on server for reuse */
			if (objt_server(conn->target)->ssl_ctx.reused_sess)
				SSL_SESSION_free(objt_server(conn->target)->ssl_ctx.reused_sess);

			objt_server(conn->target)->ssl_ctx.reused_sess = SSL_get1_session(conn->xprt_ctx);
		}
	}

	/* The connection is now established at both layers, it's time to leave */
	conn->flags &= ~(flag | CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN);
	return 1;

 out_error:
	/* Clear openssl global errors stack */
	ERR_clear_error();

	/* free resumed session if exists */
	if (objt_server(conn->target) && objt_server(conn->target)->ssl_ctx.reused_sess) {
		SSL_SESSION_free(objt_server(conn->target)->ssl_ctx.reused_sess);
		objt_server(conn->target)->ssl_ctx.reused_sess = NULL;
	}

	/* Fail on all other handshake errors */
	conn->flags |= CO_FL_ERROR;
	if (!conn->err_code)
		conn->err_code = CO_ER_SSL_HANDSHAKE;
	return 0;
}
/* This is the callback which is used when an SSL handshake is pending. It
 * updates the FD status if it wants some polling before being called again.
 * It returns 0 if it fails in a fatal way or needs to poll to go further,
 * otherwise it returns non-zero and removes itself from the connection's
 * flags (the bit is provided in <flag> by the caller).
 */
This is the callback which is used when an SSL handshake is pending. It
updates the FD status if it wants some polling before being called again.
It returns 0 if it fails in a fatal way or needs to poll to go further,
otherwise it returns non-zero and removes itself from the connection's
flags (the bit is provided in  by the caller).
This is the callback which is used when an SSL handshake is pending . It updates the FD status if it wants some polling before being called again . It returns 0 if it fails in a fatal way or needs to poll to go further otherwise it returns non - zero and removes itself from the connection ' s flags ( the bit is provided in by the caller ) .
int ssl_sock_handshake(struct connection *conn, unsigned int flag)
{
	int ret;
	if (!conn->xprt_ctx)
		goto out_error;
	if ((conn->flags & CO_FL_CONNECTED) && SSL_renegotiate_pending(conn->xprt_ctx)) {
		char c;
		ret = SSL_peek(conn->xprt_ctx, &c, 1);
		if (ret <= 0) {
			ret = SSL_get_error(conn->xprt_ctx, ret);
			if (ret == SSL_ERROR_WANT_WRITE) {
				__conn_sock_stop_recv(conn);
				__conn_sock_poll_send(conn);
				return 0;
			}
			else if (ret == SSL_ERROR_WANT_READ) {
				if (!SSL_renegotiate_pending(conn->xprt_ctx)) {
					ret = 1;
					goto reneg_ok;
				}
				if (conn->flags & CO_FL_WAIT_L4_CONN)
					conn->flags &= ~CO_FL_WAIT_L4_CONN;
				__conn_sock_stop_send(conn);
				__conn_sock_poll_recv(conn);
				return 0;
			}
			else if (ret == SSL_ERROR_SYSCALL) {
				if (!errno && conn->flags & CO_FL_WAIT_L4_CONN)
					conn->flags &= ~CO_FL_WAIT_L4_CONN;
				if (!conn->err_code) {
					if (!((SSL *)conn->xprt_ctx)->packet_length)
						if (!errno)
							conn->err_code = CO_ER_SSL_EMPTY;
						else
							conn->err_code = CO_ER_SSL_ABORT;
					else
						conn->err_code = CO_ER_SSL_HANDSHAKE;
				}
				goto out_error;
			}
			else {
				ret = recv(conn->t.sock.fd, trash.str, trash.size, MSG_NOSIGNAL|MSG_DONTWAIT);
				if (!conn->err_code)
					conn->err_code = CO_ER_SSL_HANDSHAKE;
				goto out_error;
			}
		}
		goto reneg_ok;
	}
	ret = SSL_do_handshake(conn->xprt_ctx);
	if (ret != 1) {
		ret = SSL_get_error(conn->xprt_ctx, ret);
		if (ret == SSL_ERROR_WANT_WRITE) {
			__conn_sock_stop_recv(conn);
			__conn_sock_poll_send(conn);
			return 0;
		}
		else if (ret == SSL_ERROR_WANT_READ) {
			if (conn->flags & CO_FL_WAIT_L4_CONN)
				conn->flags &= ~CO_FL_WAIT_L4_CONN;
			__conn_sock_stop_send(conn);
			__conn_sock_poll_recv(conn);
			return 0;
		}
		else if (ret == SSL_ERROR_SYSCALL) {
			if (!errno && conn->flags & CO_FL_WAIT_L4_CONN)
				conn->flags &= ~CO_FL_WAIT_L4_CONN;
			if (!((SSL *)conn->xprt_ctx)->packet_length)
				if (!errno)
					conn->err_code = CO_ER_SSL_EMPTY;
				else
					conn->err_code = CO_ER_SSL_ABORT;
			else
				conn->err_code = CO_ER_SSL_HANDSHAKE;
			goto out_error;
		}
		else {
			ret = recv(conn->t.sock.fd, trash.str, trash.size, MSG_NOSIGNAL|MSG_DONTWAIT);
			if (!conn->err_code)
				conn->err_code = CO_ER_SSL_HANDSHAKE;
			goto out_error;
		}
	}
reneg_ok:
	if (objt_server(conn->target)) {
		if (!SSL_session_reused(conn->xprt_ctx)) {
			if (objt_server(conn->target)->ssl_ctx.reused_sess)
				SSL_SESSION_free(objt_server(conn->target)->ssl_ctx.reused_sess);
			objt_server(conn->target)->ssl_ctx.reused_sess = SSL_get1_session(conn->xprt_ctx);
		}
	}
	conn->flags &= ~(flag | CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN);
	return 1;
 out_error:
	ERR_clear_error();
	if (objt_server(conn->target) && objt_server(conn->target)->ssl_ctx.reused_sess) {
		SSL_SESSION_free(objt_server(conn->target)->ssl_ctx.reused_sess);
		objt_server(conn->target)->ssl_ctx.reused_sess = NULL;
	}
	conn->flags |= CO_FL_ERROR;
	if (!conn->err_code)
		conn->err_code = CO_ER_SSL_HANDSHAKE;
	return 0;
}
int ssl_sock_handshake ( struct connection * conn , unsigned int flag ) { int ret ; if ( ! conn -> xprt_ctx ) goto out_error ; if ( ( conn -> flags & CO_FL_CONNECTED ) && SSL_renegotiate_pending ( conn -> xprt_ctx ) ) { char c ; ret = SSL_peek ( conn -> xprt_ctx , & c , 1 ) ; if ( ret <= 0 ) { ret = SSL_get_error ( conn -> xprt_ctx , ret ) ; if ( ret == SSL_ERROR_WANT_WRITE ) { __conn_sock_stop_recv ( conn ) ; __conn_sock_poll_send ( conn ) ; return 0 ; } else if ( ret == SSL_ERROR_WANT_READ ) { if ( ! SSL_renegotiate_pending ( conn -> xprt_ctx ) ) { ret = 1 ; goto reneg_ok ; } if ( conn -> flags & CO_FL_WAIT_L4_CONN ) conn -> flags &= ~ CO_FL_WAIT_L4_CONN ; __conn_sock_stop_send ( conn ) ; __conn_sock_poll_recv ( conn ) ; return 0 ; } else if ( ret == SSL_ERROR_SYSCALL ) { if ( ! errno && conn -> flags & CO_FL_WAIT_L4_CONN ) conn -> flags &= ~ CO_FL_WAIT_L4_CONN ; if ( ! conn -> err_code ) { if ( ! ( ( SSL * ) conn -> xprt_ctx ) -> packet_length ) if ( ! errno ) conn -> err_code = CO_ER_SSL_EMPTY ; else conn -> err_code = CO_ER_SSL_ABORT ; else conn -> err_code = CO_ER_SSL_HANDSHAKE ; } goto out_error ; } else { ret = recv ( conn -> t . sock . fd , trash . str , trash . size , MSG_NOSIGNAL | MSG_DONTWAIT ) ; if ( ! conn -> err_code ) conn -> err_code = CO_ER_SSL_HANDSHAKE ; goto out_error ; } } goto reneg_ok ; } ret = SSL_do_handshake ( conn -> xprt_ctx ) ; if ( ret != 1 ) { ret = SSL_get_error ( conn -> xprt_ctx , ret ) ; if ( ret == SSL_ERROR_WANT_WRITE ) { __conn_sock_stop_recv ( conn ) ; __conn_sock_poll_send ( conn ) ; return 0 ; } else if ( ret == SSL_ERROR_WANT_READ ) { if ( conn -> flags & CO_FL_WAIT_L4_CONN ) conn -> flags &= ~ CO_FL_WAIT_L4_CONN ; __conn_sock_stop_send ( conn ) ; __conn_sock_poll_recv ( conn ) ; return 0 ; } else if ( ret == SSL_ERROR_SYSCALL ) { if ( ! errno && conn -> flags & CO_FL_WAIT_L4_CONN ) conn -> flags &= ~ CO_FL_WAIT_L4_CONN ; if ( ! ( ( SSL * ) conn -> xprt_ctx ) -> packet_length ) if ( ! errno ) conn -> err_code = CO_ER_SSL_EMPTY ; else conn -> err_code = CO_ER_SSL_ABORT ; else conn -> err_code = CO_ER_SSL_HANDSHAKE ; goto out_error ; } else { ret = recv ( conn -> t . sock . fd , trash . str , trash . size , MSG_NOSIGNAL | MSG_DONTWAIT ) ; if ( ! conn -> err_code ) conn -> err_code = CO_ER_SSL_HANDSHAKE ; goto out_error ; } } reneg_ok : if ( objt_server ( conn -> target ) ) { if ( ! SSL_session_reused ( conn -> xprt_ctx ) ) { if ( objt_server ( conn -> target ) -> ssl_ctx . reused_sess ) SSL_SESSION_free ( objt_server ( conn -> target ) -> ssl_ctx . reused_sess ) ; objt_server ( conn -> target ) -> ssl_ctx . reused_sess = SSL_get1_session ( conn -> xprt_ctx ) ; } } conn -> flags &= ~ ( flag | CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN ) ; return 1 ; out_error : ERR_clear_error ( ) ; if ( objt_server ( conn -> target ) && objt_server ( conn -> target ) -> ssl_ctx . reused_sess ) { SSL_SESSION_free ( objt_server ( conn -> target ) -> ssl_ctx . reused_sess ) ; objt_server ( conn -> target ) -> ssl_ctx . reused_sess = NULL ; } conn -> flags |= CO_FL_ERROR ; if ( ! conn -> err_code ) conn -> err_code = CO_ER_SSL_HANDSHAKE ; return 0 ; }
This is the callback which is used when an SSL handshake is pending.
This is the callback which is used when an SSL handshake is pending .
/* If we use SSL_do_handshake to process a reneg initiated by
	 * the remote peer, it sometimes returns SSL_ERROR_SSL.
	 * Usually SSL_write and SSL_read are used and process implicitly
	 * the reneg handshake.
	 * Here we use SSL_peek as a workaround for reneg.
	 */ /* handshake may have not been completed, let's find why */ /* SSL handshake needs to write, L4 connection may not be ready */ /* handshake may have been completed but we have
				 * no more data to read.
                                 */ /* SSL handshake needs to read, L4 connection is ready */ /* if errno is null, then connection was successfully established */ /* Fail on all other handshake errors */ /* Note: OpenSSL may leave unread bytes in the socket's
				 * buffer, causing an RST to be emitted upon close() on
				 * TCP sockets. We first try to drain possibly pending
				 * data to avoid this as much as possible.
				 */ /* read some data: consider handshake completed */ /* handshake did not complete, let's find why */ /* SSL handshake needs to write, L4 connection may not be ready */ /* SSL handshake needs to read, L4 connection is ready */ /* if errno is null, then connection was successfully established */ /* Fail on all other handshake errors */ /* Note: OpenSSL may leave unread bytes in the socket's
			 * buffer, causing an RST to be emitted upon close() on
			 * TCP sockets. We first try to drain possibly pending
			 * data to avoid this as much as possible.
			 */ /* Handshake succeeded */ /* check if session was reused, if not store current session on server for reuse */ /* The connection is now established at both layers, it's time to leave */ /* Clear openssl global errors stack */ /* free resumed session if exists */ /* Fail on all other handshake errors */