From: Nikos Mavrogiannopoulos Date: Thu, 24 Jan 2013 04:18:03 +0000 (+0100) Subject: introduced gnutls_cork() and gnutls_uncork(). X-Git-Tag: gnutls_3_1_7~80 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dc4f3f5eced9101907138a188440933531be8522;p=thirdparty%2Fgnutls.git introduced gnutls_cork() and gnutls_uncork(). --- diff --git a/NEWS b/NEWS index 6b1820b80c..3cbb5b68a7 100644 --- a/NEWS +++ b/NEWS @@ -38,6 +38,8 @@ gnutls_x509_crt_set_dn: Added gnutls_x509_crt_set_issuer_dn: Added gnutls_x509_crq_set_dn: Added dane_state_set_dlv_file: Added +gnutls_record_cork(): Added +gnutls_record_uncork(): Added gnutls_record_send_range: Added gnutls_record_set_max_empty_records: Added gnutls_range_send_message: Added diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 84064ea242..018cbaaa11 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -166,6 +166,12 @@ typedef enum transport_t GNUTLS_DGRAM } transport_t; +typedef enum record_flush_t +{ + RECORD_FLUSH = 0, + RECORD_CORKED, +} record_flush_t; + /* the maximum size of encrypted packets */ #define IS_DTLS(session) (session->internals.transport == GNUTLS_DGRAM) @@ -760,6 +766,12 @@ typedef struct * send. */ + record_flush_t record_flush_mode; /* GNUTLS_FLUSH or GNUTLS_CORKED */ + gnutls_buffer_st record_presend_buffer;/* holds cached data + * for the gnutls_record_send() + * function. + */ + int expire_time; /* after expire_time seconds this session will expire */ struct mod_auth_st_int *auth_struct; /* used in handshake packets and KX algorithms */ diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index 15c65c25cb..e022810b94 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -1297,9 +1297,93 @@ ssize_t gnutls_record_send (gnutls_session_t session, const void *data, size_t data_size) { - return _gnutls_send_int (session, GNUTLS_APPLICATION_DATA, -1, - EPOCH_WRITE_CURRENT, data, data_size, - MBUFFER_FLUSH); + if (session->internals.record_flush_mode == RECORD_FLUSH) + { + return _gnutls_send_int (session, GNUTLS_APPLICATION_DATA, -1, + EPOCH_WRITE_CURRENT, data, data_size, + MBUFFER_FLUSH); + } + else /* GNUTLS_CORKED */ + { + int ret; + + ret = _gnutls_buffer_append_data(&session->internals.record_presend_buffer, data, data_size); + if (ret < 0) + return gnutls_assert_val(ret); + + return data_size; + } +} + +/** + * gnutls_cork: + * @session: is a #gnutls_session_t structure. + * + * If called gnutls_record_send() will no longer send partial records. + * All queued records will be sent when gnutls_uncork() is called, or + * when the maximum record size is reached. + * + * Since: 3.1.7 + **/ +void +gnutls_record_cork (gnutls_session_t session) +{ + session->internals.record_flush_mode = RECORD_CORKED; +} + +/** + * gnutls_uncork: + * @session: is a #gnutls_session_t structure. + * @flags: Could be zero or %GNUTLS_RECORD_WAIT + * + * This resets the effect of gnutls_cork(), and flushes any pending + * data. If the %GNUTLS_RECORD_WAIT flag is specified then this + * function will block until the data is sent or a fatal error + * occurs (i.e., the function will retry on %GNUTLS_E_AGAIN and + * %GNUTLS_E_INTERRUPTED). + * + * Returns: On success the number of transmitted data is returned, or + * otherwise a negative error code. + * + * Since: 3.1.7 + **/ +int +gnutls_record_uncork (gnutls_session_t session, unsigned int flags) +{ +int ret; +ssize_t total = 0; + + session->internals.record_flush_mode = RECORD_FLUSH; + + while(session->internals.record_presend_buffer.length > 0) + { + if (flags == GNUTLS_RECORD_WAIT) + { + do + { + ret = gnutls_record_send(session, session->internals.record_presend_buffer.data, + session->internals.record_presend_buffer.length); + } + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + } + else + { + ret = gnutls_record_send(session, session->internals.record_presend_buffer.data, + session->internals.record_presend_buffer.length); + } + if (ret < 0) + goto fail; + + session->internals.record_presend_buffer.data += ret; + session->internals.record_presend_buffer.length -= ret; + total += ret; + } + + return total; + +fail: + session->internals.record_flush_mode = RECORD_CORKED; + return ret; } /** diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index 25a08cdcc5..06935fc503 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -333,6 +333,7 @@ gnutls_init (gnutls_session_t * session, unsigned int flags) _gnutls_buffer_init (&(*session)->internals.handshake_hash_buffer); _gnutls_buffer_init (&(*session)->internals.hb_remote_data); _gnutls_buffer_init (&(*session)->internals.hb_local_data); + _gnutls_buffer_init (&(*session)->internals.record_presend_buffer); _mbuffer_head_init (&(*session)->internals.record_buffer); _mbuffer_head_init (&(*session)->internals.record_send_buffer); @@ -451,6 +452,7 @@ gnutls_deinit (gnutls_session_t session) _gnutls_buffer_clear (&session->internals.handshake_hash_buffer); _gnutls_buffer_clear (&session->internals.hb_remote_data); _gnutls_buffer_clear (&session->internals.hb_local_data); + _gnutls_buffer_clear (&session->internals.record_presend_buffer); _mbuffer_head_clear (&session->internals.record_buffer); _mbuffer_head_clear (&session->internals.record_recv_buffer); diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 4504f9adef..b51112b15d 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -886,6 +886,10 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session); void gnutls_record_set_timeout (gnutls_session_t session, unsigned int ms); void gnutls_record_disable_padding (gnutls_session_t session); + void gnutls_record_cork (gnutls_session_t session); +#define GNUTLS_RECORD_WAIT 1 + int gnutls_record_uncork (gnutls_session_t session, unsigned int flags); + typedef struct { size_t low; size_t high;