From: Fredrik Tolf Date: Wed, 9 Mar 2011 00:18:16 +0000 (+0100) Subject: Merge branch 'master' into sslres X-Git-Tag: 0.7~1 X-Git-Url: http://www.dolda2000.com/gitweb/?p=ashd.git;a=commitdiff_plain;h=4d2dc22a9a68395a5788ae66c84ae0ced2d0e733;hp=0b7964e936e61c43e9f9db51a8f9cbb6f9869b63 Merge branch 'master' into sslres --- diff --git a/lib/utils.c b/lib/utils.c index 1e3c363..33e55c7 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -306,3 +306,163 @@ char *base64decode(char *data, size_t *datalen) bufadd(buf, 0); return(buf.b); } + +static int btheight(struct btree *tree) +{ + if(tree == NULL) + return(0); + return(tree->h); +} + +static void btsetheight(struct btree *tree) +{ + if(tree == NULL) + return; + tree->h = max(btheight(tree->l), btheight(tree->r)) + 1; +} + +static void bbtrl(struct btree **tree); + +static void bbtrr(struct btree **tree) +{ + struct btree *m, *l, *r; + + if(btheight((*tree)->l->r) > btheight((*tree)->l->l)) + bbtrl(&(*tree)->l); + r = (*tree); + l = r->l; + m = l->r; + r->l = m; + btsetheight(r); + l->r = r; + btsetheight(l); + *tree = l; +} + +static void bbtrl(struct btree **tree) +{ + struct btree *m, *l, *r; + + if(btheight((*tree)->r->l) > btheight((*tree)->r->r)) + bbtrr(&(*tree)->r); + l = (*tree); + r = l->r; + m = r->l; + l->r = m; + btsetheight(l); + r->l = l; + btsetheight(r); + *tree = r; +} + +static int ptrcmp(void *a, void *b) +{ + if(a < b) + return(-1); + else if(a > b) + return(1); + return(0); +} + +int bbtreedel(struct btree **tree, void *item, int (*cmp)(void *, void *)) +{ + int c, r; + struct btree *s, **sp, *o; + + if(cmp == NULL) + cmp = ptrcmp; + if(*tree == NULL) + return(0); + if((c = cmp(item, (*tree)->d)) < 0) { + r = bbtreedel(&(*tree)->l, item, cmp); + } else if(c > 0) { + r = bbtreedel(&(*tree)->r, item, cmp); + } else { + r = 1; + o = *tree; + if(((*tree)->r != NULL) && ((*tree)->l != NULL)) { + sp = &(*tree)->r; + s = *sp; + while(s->l != NULL) { + sp = &(s->l); + s = *sp; + } + *sp = (*sp)->r; + s->l = (*tree)->l; + s->r = (*tree)->r; + *tree = s; + } else if((*tree)->l != NULL) { + *tree = (*tree)->l; + } else if((*tree)->r != NULL) { + *tree = (*tree)->r; + } else { + *tree = NULL; + } + free(o); + } + if(*tree != NULL) { + btsetheight(*tree); + if(btheight((*tree)->l) > btheight((*tree)->r) + 1) + bbtrr(tree); + if(btheight((*tree)->r) > btheight((*tree)->l) + 1) + bbtrl(tree); + } + return(r); +} + +void freebtree(struct btree **tree, void (*ffunc)(void *)) +{ + if(*tree == NULL) + return; + freebtree(&(*tree)->l, ffunc); + freebtree(&(*tree)->r, ffunc); + if(ffunc != NULL) + ffunc((*tree)->d); + free(*tree); + *tree = NULL; +} + +int bbtreeput(struct btree **tree, void *item, int (*cmp)(void *, void *)) +{ + int c, r; + + if(cmp == NULL) + cmp = ptrcmp; + if(*tree == NULL) { + *tree = szmalloc(sizeof(**tree)); + (*tree)->d = item; + (*tree)->h = 1; + return(1); + } + if((c = cmp(item, (*tree)->d)) < 0) + r = bbtreeput(&(*tree)->l, item, cmp); + else if(c > 0) + r = bbtreeput(&(*tree)->r, item, cmp); + else + return(0); + btsetheight(*tree); + if(btheight((*tree)->l) > btheight((*tree)->r) + 1) + bbtrr(tree); + if(btheight((*tree)->r) > btheight((*tree)->l) + 1) + bbtrl(tree); + return(r); +} + +void *btreeget(struct btree *tree, void *key, int (*cmp)(void *, void *)) +{ + int c; + + if(cmp == NULL) + cmp = ptrcmp; + while(1) { + if(tree == NULL) + return(NULL); + c = cmp(key, tree->d); + if(c < 0) + tree = tree->l; + else if(c > 0) + tree = tree->r; + else + return(tree->d); + } +} diff --git a/lib/utils.h b/lib/utils.h index b74bfb5..2de1df6 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -60,6 +60,12 @@ struct charvbuf { size_t s, d; }; +struct btree { + struct btree *l, *r; + int h; + void *d; +}; + void _sizebuf(struct buffer *buf, size_t wanted, size_t el); char *decstr(char **p, size_t *len); char *vsprintf2(char *format, va_list al); @@ -74,5 +80,9 @@ void bprintf(struct charbuf *buf, char *format, ...); void replstr(char **p, char *n); char *base64encode(char *data, size_t datalen); char *base64decode(char *data, size_t *datalen); +int bbtreedel(struct btree **tree, void *item, int (*cmp)(void *, void *)); +void freebtree(struct btree **tree, void (*ffunc)(void *)); +int bbtreeput(struct btree **tree, void *item, int (*cmp)(void *, void *)); +void *btreeget(struct btree *tree, void *key, int (*cmp)(void *, void *)); #endif diff --git a/src/ssl-gnutls.c b/src/ssl-gnutls.c index 8e4ea5c..24c8752 100644 --- a/src/ssl-gnutls.c +++ b/src/ssl-gnutls.c @@ -67,6 +67,118 @@ struct sslconn { struct charbuf in; }; +struct savedsess { + struct savedsess *next, *prev; + gnutls_datum_t key, value; +}; + +static int numconn = 0, numsess = 0; +static struct btree *sessidx = NULL; +static struct savedsess *sesslistf = NULL, *sesslistl = NULL; + +static int sesscmp(void *ap, void *bp) +{ + struct savedsess *a = ap, *b = bp; + + if(a->key.size != b->key.size) + return(a->key.size - b->key.size); + return(memcmp(a->key.data, b->key.data, a->key.size)); +} + +static gnutls_datum_t sessdbfetch(void *uudata, gnutls_datum_t key) +{ + struct savedsess *sess, lkey; + gnutls_datum_t ret; + + memset(&ret, 0, sizeof(ret)); + lkey.key = key; + if((sess = btreeget(sessidx, &lkey, sesscmp)) == NULL) + return(ret); + ret.data = memcpy(gnutls_malloc(ret.size = sess->value.size), sess->value.data, sess->value.size); + return(ret); +} + +static void freesess(struct savedsess *sess) +{ + bbtreedel(&sessidx, sess, sesscmp); + if(sess->next) + sess->next->prev = sess->prev; + if(sess->prev) + sess->prev->next = sess->next; + if(sess == sesslistf) + sesslistf = sess->next; + if(sess == sesslistl) + sesslistl = sess->prev; + free(sess->key.data); + free(sess->value.data); + free(sess); + numsess--; +} + +static int sessdbdel(void *uudata, gnutls_datum_t key) +{ + struct savedsess *sess, lkey; + + lkey.key = key; + if((sess = btreeget(sessidx, &lkey, sesscmp)) == NULL) + return(-1); + freesess(sess); + return(0); +} + +static void cleansess(void) +{ + while(numsess > (max(numconn, 1) * 100)) + freesess(sesslistl); +} + +static int sessdbstore(void *uudata, gnutls_datum_t key, gnutls_datum_t value) +{ + static int cc = 0; + struct savedsess *sess, lkey; + + if((value.data == NULL) || (value.size == 0)) { + sessdbdel(NULL, key); + return(0); + } + lkey.key = key; + if((sess = btreeget(sessidx, &lkey, sesscmp)) == NULL) { + omalloc(sess); + sess->key.data = memcpy(smalloc(sess->key.size = key.size), key.data, key.size); + sess->value.data = memcpy(smalloc(sess->value.size = value.size), value.data, value.size); + bbtreeput(&sessidx, sess, sesscmp); + sess->prev = NULL; + sess->next = sesslistf; + if(sesslistf) + sesslistf->prev = sess; + sesslistf = sess; + if(sesslistl == NULL) + sesslistl = sess; + numsess++; + } else { + free(sess->value.data); + sess->value.data = memcpy(smalloc(sess->value.size = value.size), value.data, value.size); + if(sess != sesslistf) { + if(sess->next) + sess->next->prev = sess->prev; + if(sess->prev) + sess->prev->next = sess->next; + if(sess == sesslistl) + sesslistl = sess->prev; + sess->prev = NULL; + sess->next = sesslistf; + if(sesslistf) + sesslistf->prev = sess; + sesslistf = sess; + } + } + if(cc++ > 100) { + cleansess(); + cc = 0; + } + return(0); +} + static int tlsblock(int fd, gnutls_session_t sess, time_t to) { if(gnutls_record_get_direction(sess)) @@ -210,9 +322,14 @@ static void servessl(struct muth *muth, va_list args) return(0); } + numconn++; fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); gnutls_init(&sess, GNUTLS_SERVER); gnutls_set_default_priority(sess); + gnutls_db_set_retrieve_function(sess, sessdbfetch); + gnutls_db_set_store_function(sess, sessdbstore); + gnutls_db_set_remove_function(sess, sessdbdel); + gnutls_db_set_ptr(sess, NULL); gnutls_handshake_set_post_client_hello_function(sess, setcreds); gnutls_transport_set_ptr(sess, (gnutls_transport_ptr_t)(intptr_t)fd); while((ret = gnutls_handshake(sess)) != 0) { @@ -236,6 +353,7 @@ static void servessl(struct muth *muth, va_list args) out: gnutls_deinit(sess); close(fd); + numconn--; } static void listenloop(struct muth *muth, va_list args)