]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
introduced gnutls_cork() and gnutls_uncork().
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 24 Jan 2013 04:18:03 +0000 (05:18 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 24 Jan 2013 04:18:13 +0000 (05:18 +0100)
NEWS
lib/gnutls_int.h
lib/gnutls_record.c
lib/gnutls_state.c
lib/includes/gnutls/gnutls.h.in

diff --git a/NEWS b/NEWS
index 6b1820b80c06df1f88292502661a1ce934d780a6..3cbb5b68a751700e5d8e3704a32df5db48759944 100644 (file)
--- 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
index 84064ea24261a8fc61b04b35c09809eb58745587..018cbaaa11178cc7fecb4eab6eb64b6eccd9c8dc 100644 (file)
@@ -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 */
 
index 15c65c25cb41b3b0854d92b697db92da86c6b7a8..e022810b94d5ec645d6a483cbf693f8a207aa50f 100644 (file)
@@ -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;
 }
 
 /**
index 25a08cdcc58fe006ba4d135f5d0de99e0e4cc1eb..06935fc5036e10c9666b800d15e7da2083038ef9 100644 (file)
@@ -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);
index 4504f9adef95b7ca9cbeac4b671b29a43442a11f..b51112b15db2840476136207c26b180c7bb3e970 100644 (file)
@@ -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;