summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-07-21 12:09:49 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-07-25 09:17:20 +0200
commita7008621ae3d873141b63bb5da90fea7a5373306 (patch)
treee8fc32063decda39c4927dadf75348392a9d0485
parent7978a733460f92b31033affd0e487c86d66c643d (diff)
downloadgnutls-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.h6
-rw-r--r--lib/includes/gnutls/gnutls.h.in4
-rw-r--r--lib/libgnutls.map1
-rw-r--r--lib/priority.c68
-rw-r--r--lib/state.c5
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);
}