diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-07-21 12:09:49 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-07-25 09:17:20 +0200 |
commit | a7008621ae3d873141b63bb5da90fea7a5373306 (patch) | |
tree | e8fc32063decda39c4927dadf75348392a9d0485 | |
parent | 7978a733460f92b31033affd0e487c86d66c643d (diff) | |
download | gnutls-a7008621ae3d873141b63bb5da90fea7a5373306.tar.gz |
gnutls_priority_set: use reference counting
That eliminates the need for gnutls_priority_set2() which is now
removed.
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r-- | lib/gnutls_int.h | 6 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 4 | ||||
-rw-r--r-- | lib/libgnutls.map | 1 | ||||
-rw-r--r-- | lib/priority.c | 68 | ||||
-rw-r--r-- | lib/state.c | 5 |
5 files changed, 29 insertions, 55 deletions
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index aad07979d6..d624a05284 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -666,6 +666,8 @@ typedef struct sign_algo_list_st { unsigned int size; } sign_algo_list_st; +#include "atomic.h" + /* For the external api */ struct gnutls_priority_st { priority_st protocol; @@ -717,6 +719,7 @@ struct gnutls_priority_st { bool _dumbfw; unsigned int _dh_prime_bits; /* old (deprecated) variable */ + DEF_ATOMIC_INT(usage_cnt); }; /* Allow around 50KB of length-hiding padding @@ -837,9 +840,6 @@ typedef struct { /* priorities */ struct gnutls_priority_st *priorities; - /* non-zero if the priorities are assigned only to this session (and - * thus should be freed by it */ - bool deinit_priorities; /* variables directly set when setting the priorities above, or * when overriding them */ diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 6c1012f175..35b2de3e91 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1370,10 +1370,6 @@ gnutls_priority_string_list(unsigned iter, unsigned int flags); int gnutls_priority_set(gnutls_session_t session, gnutls_priority_t priority); -#define GNUTLS_PRIORITY_FLAG_COPY 1 -int gnutls_priority_set2(gnutls_session_t session, - gnutls_priority_t priority, - unsigned int flags); int gnutls_priority_set_direct(gnutls_session_t session, const char *priorities, const char **err_pos); diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 8121f40773..2a9d0af70a 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1164,7 +1164,6 @@ GNUTLS_3_4 gnutls_sign_supports_pk_algorithm; gnutls_privkey_sign_hash2; gnutls_privkey_sign_data2; - gnutls_priority_set2; gnutls_sign_is_secure2; local: *; diff --git a/lib/priority.c b/lib/priority.c index 730edd1131..7a17964bad 100644 --- a/lib/priority.c +++ b/lib/priority.c @@ -537,57 +537,21 @@ static void prio_add(priority_st * priority_list, unsigned int algo) * Sets the priorities to use on the ciphers, key exchange methods, * and macs. * - * This is identical to calling gnutls_priority_set2() with - * %GNUTLS_PRIORITY_FLAG_COPY. - * * Returns: %GNUTLS_E_SUCCESS on success, or an error code. **/ int gnutls_priority_set(gnutls_session_t session, gnutls_priority_t priority) { - return gnutls_priority_set2(session, priority, GNUTLS_PRIORITY_FLAG_COPY); -} - -/** - * gnutls_priority_set2: - * @session: is a #gnutls_session_t type. - * @priority: is a #gnutls_priority_t type. - * @flags: zero or %GNUTLS_PRIORITY_FLAG_COPY - * - * Sets the priorities to use on the ciphers, key exchange methods, - * and macs. - * - * Unless %GNUTLS_PRIORITY_FLAG_COPY is specified, the @priority reference - * must remain valid for the lifetime of the session. - * - * Returns: %GNUTLS_E_SUCCESS on success, or an error code. - **/ -int -gnutls_priority_set2(gnutls_session_t session, gnutls_priority_t priority, unsigned int flags) -{ if (priority == NULL) { gnutls_assert(); return GNUTLS_E_NO_CIPHER_SUITES; } - if (session->internals.deinit_priorities && - session->internals.priorities) + if (session->internals.priorities) gnutls_priority_deinit(session->internals.priorities); - if (flags & GNUTLS_PRIORITY_FLAG_COPY) { - session->internals.priorities = gnutls_malloc(sizeof(*session->internals.priorities)); - if (session->internals.priorities == NULL) - return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); - - /* it is fine to use memcpy() here since we are only storing - * values and pointers to constant static data. */ - memcpy(session->internals.priorities, priority, sizeof(*priority)); - - session->internals.deinit_priorities = 1; - } else { - session->internals.priorities = priority; - session->internals.deinit_priorities = 0; - } + session->internals.priorities = priority; + gnutls_atomic_increment(&priority->usage_cnt); /* set the current version to the first in the chain. * This will be overridden later. @@ -1318,6 +1282,7 @@ gnutls_priority_init(gnutls_priority_t * priority_cache, */ (*priority_cache)->sr = SR_PARTIAL; (*priority_cache)->min_record_version = 1; + gnutls_atomic_init(&(*priority_cache)->usage_cnt); if (priorities == NULL) priorities = DEFAULT_PRIORITY_STRING; @@ -1500,7 +1465,7 @@ gnutls_priority_init(gnutls_priority_t * priority_cache, } } free(darg); - gnutls_free(*priority_cache); + gnutls_priority_deinit(*priority_cache); *priority_cache = NULL; return GNUTLS_E_INVALID_REQUEST; @@ -1515,7 +1480,24 @@ gnutls_priority_init(gnutls_priority_t * priority_cache, **/ void gnutls_priority_deinit(gnutls_priority_t priority_cache) { - gnutls_free(priority_cache); + if (priority_cache == NULL) + return; + + /* Note that here we care about the following two cases: + * 1. Multiple sessions or different threads holding a reference + a global reference + * 2. One session holding a reference with a possible global reference + * + * As such, it will never be that two threads reach the + * zero state at the same time, unless the global reference + * is cleared too, which is invalid state. + */ + if (gnutls_atomic_val(&priority_cache->usage_cnt) == 0) { + gnutls_atomic_deinit(&priority_cache->usage_cnt); + gnutls_free(priority_cache); + return; + } else { + gnutls_atomic_decrement(&priority_cache->usage_cnt); + } } @@ -1555,9 +1537,7 @@ gnutls_priority_set_direct(gnutls_session_t session, return ret; } - /* ensure this priority is deinitialized with the session */ - session->internals.deinit_priorities = 1; - + /* ensure that the session holds the only reference for the struct */ gnutls_priority_deinit(prio); return 0; diff --git a/lib/state.c b/lib/state.c index d3e75c71c2..a36ed92d25 100644 --- a/lib/state.c +++ b/lib/state.c @@ -429,9 +429,8 @@ void gnutls_deinit(gnutls_session_t session) gnutls_credentials_clear(session); _gnutls_selected_certs_deinit(session); - if (session->internals.deinit_priorities && - session->internals.priorities) - gnutls_priority_deinit(session->internals.priorities); + /* we rely on priorities' internal reference counting */ + gnutls_priority_deinit(session->internals.priorities); gnutls_free(session); } |