MINOR: ssl: Add ocsp_update_tree and helper functions

The OCSP update tree holds ocsp responses that will need to be updated
automatically. The entries are inserted in an eb64_tree where the keys
are the absolute time after which the entry will need to be updated.
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index aed823c..cf918ae 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -957,6 +957,7 @@
 	struct buffer response;
 	int refcount;
 	long expire;
+	struct eb64_node next_update;	/* Key of items inserted in ocsp_update_tree (sorted by absolute date) */
 };
 
 struct ocsp_cbk_arg {
@@ -978,6 +979,11 @@
 
 __decl_thread(HA_SPINLOCK_T ocsp_tree_lock);
 
+static struct eb_root ocsp_update_tree = EB_ROOT; /* updatable ocsp responses sorted by next_update in absolute time */
+#define SSL_OCSP_UPDATE_DELAY_MAX 60*60 /* 1H */
+#define SSL_OCSP_UPDATE_DELAY_MIN 5*60  /* 5 minutes */
+#define SSL_OCSP_UPDATE_MARGIN 60   /* 1 minute */
+
 /* This function starts to check if the OCSP response (in DER format) contained
  * in chunk 'ocsp_response' is valid (else exits on error).
  * If 'cid' is not NULL, it will be compared to the OCSP certificate ID
@@ -1315,6 +1321,37 @@
 	OCSP_BASICRESP_free(basic);
 	return ret;
 }
+
+/*
+ * Insert a certificate_ocsp structure into the ocsp_update_tree tree, in which
+ * entries are sorted by absolute date of the next update. The next_update key
+ * will be the smallest out of the actual expire value of the response and
+ * now+1H. This arbitrary 1H value ensures that ocsp responses are updated
+ * periodically even when they have a long expire time, while not overloading
+ * the system too much (in theory). Likewise, a minimum 5 minutes interval is
+ * defined in order to avoid updating too often responses that have a really
+ * short expire time or even no 'Next Update' at all.
+ */
+static int ssl_ocsp_update_insert(struct certificate_ocsp *ocsp)
+{
+	int update_margin = (ocsp->expire >= SSL_OCSP_UPDATE_MARGIN) ? SSL_OCSP_UPDATE_MARGIN : 0;
+
+	ocsp->next_update.key = MIN(now.tv_sec + SSL_OCSP_UPDATE_DELAY_MAX,
+	                            ocsp->expire - update_margin);
+
+	/* An already existing valid OCSP response that expires within less than
+	 * SSL_OCSP_UPDATE_DELAY_MIN or has no 'Next Update' field should not be
+	 * updated more than once every 5 minutes in order to avoid continuous
+	 * update of the same response. */
+	if (b_data(&ocsp->response))
+		ocsp->next_update.key = MAX(ocsp->next_update.key, SSL_OCSP_UPDATE_DELAY_MIN);
+
+	HA_SPIN_LOCK(OCSP_LOCK, &ocsp_tree_lock);
+	eb64_insert(&ocsp_update_tree, &ocsp->next_update);
+	HA_SPIN_UNLOCK(OCSP_LOCK, &ocsp_tree_lock);
+
+	return 0;
+}
 #endif /* defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP */
 
 /*
@@ -1630,7 +1667,9 @@
 	ocsp->refcount--;
 	if (ocsp->refcount <= 0) {
 		ebmb_delete(&ocsp->key);
+		eb64_delete(&ocsp->next_update);
 		chunk_destroy(&ocsp->response);
+
 		free(ocsp);
 	}
 }