REORG: shctx: move ssl functions to ssl_sock.c

Move the ssl callback functions of the ssl shared session cache to
ssl_sock.c. The shctx functions still needs to be separated of the ssl
tree and data.
diff --git a/include/proto/shctx.h b/include/proto/shctx.h
index d56320c..dfa0c57 100644
--- a/include/proto/shctx.h
+++ b/include/proto/shctx.h
@@ -49,6 +49,14 @@
  * Shared context MUST be firstly initialized */
 void shared_context_set_cache(SSL_CTX *ctx);
 
+
+int shsess_free(struct shared_context *shctx, struct shared_session *shsess);
+
+struct shared_session *shsess_get_next(struct shared_context *shctx, int data_len);
+
+int shsess_store(struct shared_context *shctx, unsigned char *s_id, unsigned char *data, int data_len);
+
+
 /* Lock functions */
 
 #if defined (USE_PRIVATE_CACHE)
@@ -186,6 +194,30 @@
 
 #endif
 
+/* List Macros */
+
+#define shblock_unset(s)		(s)->n->p = (s)->p; \
+					(s)->p->n = (s)->n;
+
+static inline void shblock_set_free(struct shared_context *shctx,
+				    struct shared_block *s)
+{
+	shblock_unset(s);
+	(s)->n = &shctx->free;
+	(s)->p = shctx->free.p;
+	shctx->free.p->n = s;
+	shctx->free.p = s;
+}
+
+static inline void shblock_set_active(struct shared_context *shctx,
+				      struct shared_block *s)
+{
+	shblock_unset(s)
+	(s)->n = &shctx->active;
+	(s)->p = shctx->active.p;
+	shctx->active.p->n = s;
+	shctx->active.p = s;
+}
 
 #endif /* SHCTX_H */
 
diff --git a/include/proto/ssl_sock.h b/include/proto/ssl_sock.h
index 86ad137..9f974dd 100644
--- a/include/proto/ssl_sock.h
+++ b/include/proto/ssl_sock.h
@@ -76,6 +76,19 @@
 int ssl_sock_set_generated_cert(SSL_CTX *ctx, unsigned int key, struct bind_conf *bind_conf);
 unsigned int ssl_sock_generated_cert_key(const void *data, size_t len);
 
+
+/* ssl shctx macro */
+
+#define shsess_tree_delete(s)	ebmb_delete(&(s)->key);
+
+#define shsess_tree_insert(shctx, s)	(struct shared_session *)ebmb_insert(&shctx->active.data.session.key.node.branches, \
+								     &(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH);
+
+#define shsess_tree_lookup(shctx, k)	(struct shared_session *)ebmb_lookup(&shctx->active.data.session.key.node.branches, \
+								     (k), SSL_MAX_SSL_SESSION_ID_LENGTH);
+
+
+
 #endif /* _PROTO_SSL_SOCK_H */
 
 /*
diff --git a/src/shctx.c b/src/shctx.c
index 8f900cc..853b522 100644
--- a/src/shctx.c
+++ b/src/shctx.c
@@ -15,55 +15,25 @@
 #include <arpa/inet.h>
 #include <ebmbtree.h>
 
+#include <proto/connection.h>
 #include <proto/shctx.h>
+#include <proto/ssl_sock.h>
 #include <proto/openssl-compat.h>
 
 #include <types/global.h>
 #include <types/shctx.h>
 
+
 #if !defined (USE_PRIVATE_CACHE)
 int use_shared_mem = 0;
 #endif
 
-/* List Macros */
-
-#define shblock_unset(s)		(s)->n->p = (s)->p; \
-					(s)->p->n = (s)->n;
-
-static inline void shblock_set_free(struct shared_context *shctx,
-				    struct shared_block *s)
-{
-	shblock_unset(s);
-	(s)->n = &shctx->free;
-	(s)->p = shctx->free.p;
-	shctx->free.p->n = s;
-	shctx->free.p = s;
-}
-
-static inline void shblock_set_active(struct shared_context *shctx,
-				      struct shared_block *s)
-{
-	shblock_unset(s)
-	(s)->n = &shctx->active;
-	(s)->p = shctx->active.p;
-	shctx->active.p->n = s;
-	shctx->active.p = s;
-}
-
 /* Tree Macros */
 
-#define shsess_tree_delete(s)	ebmb_delete(&(s)->key);
-
-#define shsess_tree_insert(shctx, s)	(struct shared_session *)ebmb_insert(&shctx->active.data.session.key.node.branches, \
-								     &(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH);
-
-#define shsess_tree_lookup(shctx, k)	(struct shared_session *)ebmb_lookup(&shctx->active.data.session.key.node.branches, \
-								     (k), SSL_MAX_SSL_SESSION_ID_LENGTH);
-
 /* shared session functions */
 
 /* Free session blocks, returns number of freed blocks */
-static int shsess_free(struct shared_context *shctx, struct shared_session *shsess)
+int shsess_free(struct shared_context *shctx, struct shared_session *shsess)
 {
 	struct shared_block *block;
 	int ret = 1;
@@ -95,7 +65,7 @@
  * Returns a ptr on a free block if it succeeds, or NULL if there are not
  * enough blocks to store that session.
  */
-static struct shared_session *shsess_get_next(struct shared_context *shctx, int data_len)
+struct shared_session *shsess_get_next(struct shared_context *shctx, int data_len)
 {
 	int head = 0;
 	struct shared_block *b;
@@ -135,7 +105,7 @@
  * data_len: asn1 encoded session length
  * Returns 1 id session was stored (else 0)
  */
-static int shsess_store(struct shared_context *shctx, unsigned char *s_id, unsigned char *data, int data_len)
+int shsess_store(struct shared_context *shctx, unsigned char *s_id, unsigned char *data, int data_len)
 {
 	struct shared_session *shsess, *oldshsess;
 
@@ -199,169 +169,7 @@
 	return 1;
 }
 
-
-/* SSL context callbacks */
-
-/* SSL callback used on new session creation */
-int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
-{
-	unsigned char encsess[SHSESS_MAX_DATA_LEN];           /* encoded session  */
-	unsigned char encid[SSL_MAX_SSL_SESSION_ID_LENGTH];   /* encoded id */
-	unsigned char *p;
-	int data_len;
-	unsigned int sid_length, sid_ctx_length;
-	const unsigned char *sid_data;
-	const unsigned char *sid_ctx_data;
-
-	/* Session id is already stored in to key and session id is known
-	 * so we dont store it to keep size.
-	 */
-
-	sid_data = SSL_SESSION_get_id(sess, &sid_length);
-	sid_ctx_data = SSL_SESSION_get0_id_context(sess, &sid_ctx_length);
-	SSL_SESSION_set1_id(sess, sid_data, 0);
-	SSL_SESSION_set1_id_context(sess, sid_ctx_data, 0);
-
-	/* check if buffer is large enough for the ASN1 encoded session */
-	data_len = i2d_SSL_SESSION(sess, NULL);
-	if (data_len > SHSESS_MAX_DATA_LEN)
-		goto err;
-
-	p = encsess;
-
-	/* process ASN1 session encoding before the lock */
-	i2d_SSL_SESSION(sess, &p);
-
-	memcpy(encid, sid_data, sid_length);
-	if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
-		memset(encid + sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length);
-
-	shared_context_lock(ssl_shctx);
-
-	/* store to cache */
-	shsess_store(ssl_shctx, encid, encsess, data_len);
-
-	shared_context_unlock(ssl_shctx);
-
-err:
-	/* reset original length values */
-	SSL_SESSION_set1_id(sess, sid_data, sid_length);
-	SSL_SESSION_set1_id_context(sess, sid_ctx_data, sid_ctx_length);
-
-	return 0; /* do not increment session reference count */
-}
-
-/* SSL callback used on lookup an existing session cause none found in internal cache */
-SSL_SESSION *shctx_get_cb(SSL *ssl, __OPENSSL_110_CONST__ unsigned char *key, int key_len, int *do_copy)
-{
-	struct shared_session *shsess;
-	unsigned char data[SHSESS_MAX_DATA_LEN], *p;
-	unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
-	int data_len;
-	SSL_SESSION *sess;
-
-	global.shctx_lookups++;
-
-	/* allow the session to be freed automatically by openssl */
-	*do_copy = 0;
-
-	/* tree key is zeros padded sessionid */
-	if (key_len < SSL_MAX_SSL_SESSION_ID_LENGTH) {
-		memcpy(tmpkey, key, key_len);
-		memset(tmpkey + key_len, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - key_len);
-		key = tmpkey;
-	}
-
-	/* lock cache */
-	shared_context_lock(ssl_shctx);
-
-	/* lookup for session */
-	shsess = shsess_tree_lookup(ssl_shctx, key);
-	if (!shsess) {
-		/* no session found: unlock cache and exit */
-		shared_context_unlock(ssl_shctx);
-		global.shctx_misses++;
-		return NULL;
-	}
-
-	data_len = ((struct shared_block *)shsess)->data_len;
-	if (data_len <= sizeof(shsess->data)) {
-		/* Session stored on single block */
-		memcpy(data, shsess->data, data_len);
-		shblock_set_active(ssl_shctx, (struct shared_block *)shsess);
-	}
-	else {
-		/* Session stored on multiple blocks */
-		struct shared_block *block;
-
-		memcpy(data, shsess->data, sizeof(shsess->data));
-		p = data + sizeof(shsess->data);
-		block = ((struct shared_block *)shsess)->n;
-		shblock_set_active(ssl_shctx, (struct shared_block *)shsess);
-		while (1) {
-			/* Retrieve data from next block */
-			struct shared_block *next;
-
-			if (block->data_len <= sizeof(block->data.data)) {
-				/* This is the last block */
-				memcpy(p, block->data.data, block->data_len);
-				p += block->data_len;
-				shblock_set_active(ssl_shctx, block);
-				break;
-			}
-			/* Intermediate block */
-			memcpy(p, block->data.data, sizeof(block->data.data));
-			p += sizeof(block->data.data);
-			next = block->n;
-			shblock_set_active(ssl_shctx, block);
-			block = next;
-		}
-	}
-
-	shared_context_unlock(ssl_shctx);
-
-	/* decode ASN1 session */
-	p = data;
-	sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
-	/* Reset session id and session id contenxt */
-	if (sess) {
-		SSL_SESSION_set1_id(sess, key, key_len);
-		SSL_SESSION_set1_id_context(sess, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
-	}
-
-	return sess;
-}
-
-/* SSL callback used to signal session is no more used in internal cache */
-void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
-{
-	struct shared_session *shsess;
-	unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
-	unsigned int sid_length;
-	const unsigned char *sid_data;
-	(void)ctx;
-
-	sid_data = SSL_SESSION_get_id(sess, &sid_length);
-	/* tree key is zeros padded sessionid */
-	if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
-		memcpy(tmpkey, sid_data, sid_length);
-		memset(tmpkey+sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - sid_length);
-		sid_data = tmpkey;
-	}
-
-	shared_context_lock(ssl_shctx);
-
-	/* lookup for session */
-	shsess = shsess_tree_lookup(ssl_shctx, sid_data);
-	if (shsess) {
-		/* free session */
-		shsess_tree_delete(shsess);
-		shsess_free(ssl_shctx, shsess);
-	}
 
-	/* unlock cache */
-	shared_context_unlock(ssl_shctx);
-}
 
 /* Allocate shared memory context.
  * <size> is maximum cached sessions.
@@ -461,25 +269,3 @@
 	return ret;
 }
 
-
-/* Set session cache mode to server and disable openssl internal cache.
- * Set shared cache callbacks on an ssl context.
- * Shared context MUST be firstly initialized */
-void shared_context_set_cache(SSL_CTX *ctx)
-{
-	SSL_CTX_set_session_id_context(ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
-
-	if (!ssl_shctx) {
-		SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
-		return;
-	}
-
-	SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER |
-	                                    SSL_SESS_CACHE_NO_INTERNAL |
-	                                    SSL_SESS_CACHE_NO_AUTO_CLEAR);
-
-	/* Set callbacks */
-	SSL_CTX_sess_set_new_cb(ctx, shctx_new_cb);
-	SSL_CTX_sess_set_get_cb(ctx, shctx_get_cb);
-	SSL_CTX_sess_set_remove_cb(ctx, shctx_remove_cb);
-}
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 24e4f21..71bcbe3 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -3718,6 +3718,191 @@
 	return cfgerr;
 }
 
+/* SSL context callbacks */
+
+/* SSL callback used on new session creation */
+int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
+{
+	unsigned char encsess[SHSESS_MAX_DATA_LEN];           /* encoded session  */
+	unsigned char encid[SSL_MAX_SSL_SESSION_ID_LENGTH];   /* encoded id */
+	unsigned char *p;
+	int data_len;
+	unsigned int sid_length, sid_ctx_length;
+	const unsigned char *sid_data;
+	const unsigned char *sid_ctx_data;
+
+	/* Session id is already stored in to key and session id is known
+	 * so we dont store it to keep size.
+	 */
+
+	sid_data = SSL_SESSION_get_id(sess, &sid_length);
+	sid_ctx_data = SSL_SESSION_get0_id_context(sess, &sid_ctx_length);
+	SSL_SESSION_set1_id(sess, sid_data, 0);
+	SSL_SESSION_set1_id_context(sess, sid_ctx_data, 0);
+
+	/* check if buffer is large enough for the ASN1 encoded session */
+	data_len = i2d_SSL_SESSION(sess, NULL);
+	if (data_len > SHSESS_MAX_DATA_LEN)
+		goto err;
+
+	p = encsess;
+
+	/* process ASN1 session encoding before the lock */
+	i2d_SSL_SESSION(sess, &p);
+
+	memcpy(encid, sid_data, sid_length);
+	if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
+		memset(encid + sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length);
+
+	shared_context_lock(ssl_shctx);
+
+	/* store to cache */
+	shsess_store(ssl_shctx, encid, encsess, data_len);
+
+	shared_context_unlock(ssl_shctx);
+
+err:
+	/* reset original length values */
+	SSL_SESSION_set1_id(sess, sid_data, sid_length);
+	SSL_SESSION_set1_id_context(sess, sid_ctx_data, sid_ctx_length);
+
+	return 0; /* do not increment session reference count */
+}
+
+/* SSL callback used on lookup an existing session cause none found in internal cache */
+SSL_SESSION *shctx_get_cb(SSL *ssl, __OPENSSL_110_CONST__ unsigned char *key, int key_len, int *do_copy)
+{
+	struct shared_session *shsess;
+	unsigned char data[SHSESS_MAX_DATA_LEN], *p;
+	unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
+	int data_len;
+	SSL_SESSION *sess;
+
+	global.shctx_lookups++;
+
+	/* allow the session to be freed automatically by openssl */
+	*do_copy = 0;
+
+	/* tree key is zeros padded sessionid */
+	if (key_len < SSL_MAX_SSL_SESSION_ID_LENGTH) {
+		memcpy(tmpkey, key, key_len);
+		memset(tmpkey + key_len, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - key_len);
+		key = tmpkey;
+	}
+
+	/* lock cache */
+	shared_context_lock(ssl_shctx);
+
+	/* lookup for session */
+	shsess = shsess_tree_lookup(ssl_shctx, key);
+	if (!shsess) {
+		/* no session found: unlock cache and exit */
+		shared_context_unlock(ssl_shctx);
+		global.shctx_misses++;
+		return NULL;
+	}
+
+	data_len = ((struct shared_block *)shsess)->data_len;
+	if (data_len <= sizeof(shsess->data)) {
+		/* Session stored on single block */
+		memcpy(data, shsess->data, data_len);
+		shblock_set_active(ssl_shctx, (struct shared_block *)shsess);
+	}
+	else {
+		/* Session stored on multiple blocks */
+		struct shared_block *block;
+
+		memcpy(data, shsess->data, sizeof(shsess->data));
+		p = data + sizeof(shsess->data);
+		block = ((struct shared_block *)shsess)->n;
+		shblock_set_active(ssl_shctx, (struct shared_block *)shsess);
+		while (1) {
+			/* Retrieve data from next block */
+			struct shared_block *next;
+
+			if (block->data_len <= sizeof(block->data.data)) {
+				/* This is the last block */
+				memcpy(p, block->data.data, block->data_len);
+				p += block->data_len;
+				shblock_set_active(ssl_shctx, block);
+				break;
+			}
+			/* Intermediate block */
+			memcpy(p, block->data.data, sizeof(block->data.data));
+			p += sizeof(block->data.data);
+			next = block->n;
+			shblock_set_active(ssl_shctx, block);
+			block = next;
+		}
+	}
+
+	shared_context_unlock(ssl_shctx);
+
+	/* decode ASN1 session */
+	p = data;
+	sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
+	/* Reset session id and session id contenxt */
+	if (sess) {
+		SSL_SESSION_set1_id(sess, key, key_len);
+		SSL_SESSION_set1_id_context(sess, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
+	}
+
+	return sess;
+}
+
+/* SSL callback used to signal session is no more used in internal cache */
+void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
+{
+	struct shared_session *shsess;
+	unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
+	unsigned int sid_length;
+	const unsigned char *sid_data;
+	(void)ctx;
+
+	sid_data = SSL_SESSION_get_id(sess, &sid_length);
+	/* tree key is zeros padded sessionid */
+	if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
+		memcpy(tmpkey, sid_data, sid_length);
+		memset(tmpkey+sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - sid_length);
+		sid_data = tmpkey;
+	}
+
+	shared_context_lock(ssl_shctx);
+
+	/* lookup for session */
+	shsess = shsess_tree_lookup(ssl_shctx, sid_data);
+	if (shsess) {
+		/* free session */
+		shsess_tree_delete(shsess);
+		shsess_free(ssl_shctx, shsess);
+	}
+
+	/* unlock cache */
+	shared_context_unlock(ssl_shctx);
+}
+
+/* Set session cache mode to server and disable openssl internal cache.
+ * Set shared cache callbacks on an ssl context.
+ * Shared context MUST be firstly initialized */
+void shared_context_set_cache(SSL_CTX *ctx)
+{
+	SSL_CTX_set_session_id_context(ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
+
+	if (!ssl_shctx) {
+		SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+		return;
+	}
+
+	SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER |
+	                                    SSL_SESS_CACHE_NO_INTERNAL |
+	                                    SSL_SESS_CACHE_NO_AUTO_CLEAR);
+
+	/* Set callbacks */
+	SSL_CTX_sess_set_new_cb(ctx, shctx_new_cb);
+	SSL_CTX_sess_set_get_cb(ctx, shctx_get_cb);
+	SSL_CTX_sess_set_remove_cb(ctx, shctx_remove_cb);
+}
+
 int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf, SSL_CTX *ctx)
 {
 	struct proxy *curproxy = bind_conf->frontend;