gnutls-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gnutls branch, master, updated. gnutls_2_9_10-304-g0de9288


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_2_9_10-304-g0de9288
Date: Sun, 11 Jul 2010 07:51:45 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gnutls".

http://git.savannah.gnu.org/cgit/gnutls.git/commit/?id=0de92887c94aadab46fb88e56a99e6f563f296d8

The branch, master has been updated
       via  0de92887c94aadab46fb88e56a99e6f563f296d8 (commit)
       via  389aee36fe8e454e44b0dfd588e22f1494be1961 (commit)
       via  7692b5734a8e508d99c7a6c77f3c0fb482166353 (commit)
       via  d0a081ec1b276a80a4b1ca1dc5109fd27ad0abc2 (commit)
      from  b3d8ec01ea3ffdc0e58b2f9f62148bc28a91e741 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 0de92887c94aadab46fb88e56a99e6f563f296d8
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Jul 11 09:50:44 2010 +0200

    Corrected the lowat behavior. Documented that it will be deprecated in
    later versions.

commit 389aee36fe8e454e44b0dfd588e22f1494be1961
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Jul 11 09:50:24 2010 +0200

    gnutls-serv: Do not print CR/LF if received, but instead print LF only.

commit 7692b5734a8e508d99c7a6c77f3c0fb482166353
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat Jul 10 23:25:31 2010 +0200

    system specific functions were moved to system.c

commit d0a081ec1b276a80a4b1ca1dc5109fd27ad0abc2
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat Jul 10 23:10:45 2010 +0200

    Support scattered write using writev(). This takes
    advantage of the new buffering layer and allows queuing of packets
    and flushing them. This is currently used for handshake messages
    only. Performance-wise the difference of packing several TLS records
    in a single write doesn't seem to offer anything over ethernet (that
    my tests were on). Probably on links with higher latency there would
    be a benefit.

-----------------------------------------------------------------------

Summary of changes:
 NEWS                            |   14 ++-
 configure.ac                    |    1 +
 lib/Makefile.am                 |    4 +-
 lib/gnutls_alert.c              |    2 +-
 lib/gnutls_buffers.c            |  327 +++++++++++++++++++++++++--------------
 lib/gnutls_buffers.h            |   10 +-
 lib/gnutls_global.c             |   39 -----
 lib/gnutls_handshake.c          |   51 ++++++-
 lib/gnutls_handshake.h          |    3 +-
 lib/gnutls_int.h                |    6 +-
 lib/gnutls_mbuffers.c           |   26 +++-
 lib/gnutls_mbuffers.h           |    4 +-
 lib/gnutls_record.c             |   10 +-
 lib/gnutls_record.h             |   10 +-
 lib/gnutls_state.c              |    9 +
 lib/includes/gnutls/gnutls.h.in |   18 ++-
 lib/libgnutls.map               |    2 +
 lib/locks.c                     |  141 -----------------
 lib/locks.h                     |   12 --
 lib/pakchois/pakchois.c         |    1 +
 lib/{locks.c => system.c}       |  110 +++++++++-----
 lib/system.h                    |   33 ++++
 libextra/gnutls_ia.c            |    2 +-
 src/serv.c                      |   19 +++
 24 files changed, 479 insertions(+), 375 deletions(-)
 copy lib/{locks.c => system.c} (70%)
 create mode 100644 lib/system.h

diff --git a/NEWS b/NEWS
index 32702d8..2fe8a5f 100644
--- a/NEWS
+++ b/NEWS
@@ -5,10 +5,17 @@ See the end for copying conditions.
 
 * Version 2.11.0 (unreleased)
 
+** libgnutls: support scattered write using writev(). This takes
+advantage of the new buffering layer and allows queuing of packets
+and flushing them. This is currently used for handshake messages
+only.
+
 ** libgnutls: Added gnutls_global_set_mutex() to allow setting
 alternative locking procedures. By default the system available
 locking is used. In *NIX pthreads are used and in windows the
-critical section API.
+critical section API. This follows a different approach than the
+previous versions that depended on libgcrypt initialization. The
+locks are now set by default in systems that support it.
 
 ** libgnutls: Added support for reading DN from EV-certificates.
 New DN values:
@@ -26,8 +33,9 @@ has to be called to register any required md5 handlers.
 code contributed by Jonathan Bastien-Filiatrault.
 
 ** libgnutls: Internal API for extensions augmented to allow
-safe storing and loading of data on resumption. OPRFI extension
-was removed.
+safe storing and loading of data on resumption. This allows writing
+self-contained extensions (when possible). As a side effect
+the OPRFI extension was removed.
 
 ** libgnutls: Added support for DSA-SHA256 and DSA-SHA224
 
diff --git a/configure.ac b/configure.ac
index 9e25ea5..0ec3cc4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -223,6 +223,7 @@ if test "$gl_gcc_warnings" = yes; then
   nw="$nw -Wconversion"             # Too many warnings for now
   nw="$nw -Wsign-conversion"        # Too many warnings for now
   nw="$nw -Wformat-y2k"             # Too many warnings for now
+  nw="$nw -Wvla"                    # There is no point to avoid C99 variable 
length arrays
   nw="$nw -Wformat-nonliteral"      # Incompatible with gettext _()
   nw="$nw -Wunsafe-loop-optimizations"
   nw="$nw -Wstrict-overflow"
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 3bafc5c..13531d9 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -78,7 +78,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c 
gnutls_cipher.c  \
        gnutls_str.c gnutls_state.c gnutls_x509.c ext_cert_type.c       \
        gnutls_rsa_export.c auth_rsa_export.c ext_server_name.c         \
        auth_dh_common.c gnutls_helper.c gnutls_supplemental.c          \
-       crypto.c random.c  ext_signature.c cryptodev.c \
+       crypto.c random.c  ext_signature.c cryptodev.c system.c \
        crypto-api.c ext_safe_renegotiation.c gnutls_privkey.c \
        pkcs11.c pkcs11_privkey.c gnutls_pubkey.c pkcs11_write.c locks.c
 
@@ -102,7 +102,7 @@ HFILES = debug.h gnutls_compress.h gnutls_cipher.h 
gnutls_buffers.h \
        gnutls_rsa_export.h ext_server_name.h auth_dh_common.h          \
        ext_srp.h gnutls_srp.h auth_srp.h auth_srp_passwd.h             \
        gnutls_helper.h auth_psk.h auth_psk_passwd.h                    \
-       gnutls_supplemental.h crypto.h random.h         \
+       gnutls_supplemental.h crypto.h random.h system.h        \
        ext_session_ticket.h ext_signature.h gnutls_cryptodev.h         \
        ext_safe_renegotiation.h locks.h gnutls_mbuffers.h pkcs11_int.h
 
diff --git a/lib/gnutls_alert.c b/lib/gnutls_alert.c
index 48ea34a..170ca7e 100644
--- a/lib/gnutls_alert.c
+++ b/lib/gnutls_alert.c
@@ -133,7 +133,7 @@ gnutls_alert_send (gnutls_session_t session, 
gnutls_alert_level_t level,
   _gnutls_record_log ("REC: Sending Alert[%d|%d] - %s\n", data[0],
                      data[1], name);
 
-  if ((ret = _gnutls_send_int (session, GNUTLS_ALERT, -1, data, 2)) >= 0)
+  if ((ret = _gnutls_send_int (session, GNUTLS_ALERT, -1, data, 2, 
MBUFFER_FLUSH)) >= 0)
     return 0;
   else
     return ret;
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 78aa8b7..f661837 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -54,18 +54,17 @@
 #include <gnutls_record.h>
 #include <gnutls_buffers.h>
 #include <gnutls_mbuffers.h>
+#include <system.h>
 
 #include <errno.h>
 
-/* We need to disable gnulib's replacement wrappers to get native
-   Windows interfaces. */
-#undef recv
-#undef send
-
 #ifndef EAGAIN
 # define EAGAIN EWOULDBLOCK
 #endif
 
+/* this is the maximum number of messages allowed to queue.
+ */
+#define MAX_QUEUE 16
 
 /**
  * gnutls_transport_set_errno:
@@ -192,9 +191,11 @@ _gnutls_record_buffer_get_size (content_type_t type, 
gnutls_session_t session)
  * This function checks if there are any data to receive in the gnutls
  * buffers.
  *
- * Notice that you may also use select() to check for data in a TCP
+ * Note that you could also use select() to check for data in a TCP
  * connection, instead of this function.  GnuTLS leaves some data in
- * the tcp buffer in order for select to work.
+ * the tcp buffer in order for select to work. However the select() 
+ * alternative is not recommended and will be deprecated in later
+ * GnuTLS revisions.
  *
  * Returns: the size of that data or 0.
  **/
@@ -248,6 +249,19 @@ _gnutls_record_buffer_get (content_type_t type,
   return length;
 }
 
+inline static void reset_errno(gnutls_session_t session)
+{  
+  session->internals.errnum = 0;
+}
+
+inline static int get_errno(gnutls_session_t session)
+{
+  if (session->internals.errnum != 0)
+    return session->internals.errnum;
+  else 
+    return 
session->internals.errno_func(session->internals.transport_recv_ptr);
+}
+
 
 /* This function is like read. But it does not return -1 on error.
  * It does return gnutls_errno instead.
@@ -256,7 +270,7 @@ _gnutls_record_buffer_get (content_type_t type,
  */
 static ssize_t
 _gnutls_read (gnutls_session_t session, void *iptr,
-             size_t sizeOfPtr, int flags)
+             size_t sizeOfPtr, gnutls_pull_func pull_func)
 {
   size_t left;
   ssize_t i = 0;
@@ -269,43 +283,13 @@ _gnutls_read (gnutls_session_t session, void *iptr,
   while (left > 0)
     {
 
-      session->internals.errnum = 0;
+      reset_errno(session);
 
-      if (session->internals._gnutls_pull_func == NULL)
-       {
-         i = recv (GNUTLS_POINTER_TO_INT (fd), &ptr[sizeOfPtr - left],
-                   left, flags);
-#if HAVE_WINSOCK2_H
-         if (i < 0)
-           {
-             int tmperr = WSAGetLastError ();
-             switch (tmperr)
-               {
-               case WSAEWOULDBLOCK:
-                 session->internals.errnum = EAGAIN;
-                 break;
-
-               case WSAEINTR:
-                 session->internals.errnum = EINTR;
-                 break;
-
-               default:
-                 session->internals.errnum = EIO;
-                 break;
-               }
-             WSASetLastError (tmperr);
-           }
-#endif
-       }
-      else
-       i = session->internals._gnutls_pull_func (fd,
-                                                 &ptr[sizeOfPtr -
-                                                      left], left);
+      i = pull_func (fd, &ptr[sizeOfPtr - left], left);
 
       if (i < 0)
        {
-         int err = session->internals.errnum ? session->internals.errnum
-           : errno;
+         int err = get_errno(session);
 
          _gnutls_read_log ("READ: %d returned from %p, errno=%d gerrno=%d\n",
                            (int) i, fd, errno, session->internals.errnum);
@@ -356,48 +340,53 @@ finish:
   return (sizeOfPtr - left);
 }
 
+
+
 static ssize_t
-_gnutls_write (gnutls_session_t session, void *iptr,
-              size_t sizeOfPtr)
+_gnutls_writev_emu (gnutls_session_t session, const giovec_t * giovec, int 
giovec_cnt)
 {
-  int i;
+  int ret, j = 0;
   gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
+  void* iptr;
+  size_t sizeOfPtr;
+  size_t total = 0;
 
-  session->internals.errnum = 0;
-
-  if (session->internals._gnutls_push_func == NULL)
+  for (j=0;j<giovec_cnt;j++)
     {
-      i = send (GNUTLS_POINTER_TO_INT (fd), iptr, sizeOfPtr, 0);
-#if HAVE_WINSOCK2_H
-      if (i < 0)
-       {
-         int tmperr = WSAGetLastError ();
-         switch (tmperr)
-           {
-           case WSAEWOULDBLOCK:
-             session->internals.errnum = EAGAIN;
-             break;
+      sizeOfPtr = giovec[j].iov_len;
+      iptr = giovec[j].iov_base;
+          
+      ret = session->internals.push_func (fd, iptr, sizeOfPtr);
 
-           case WSAEINTR:
-             session->internals.errnum = EINTR;
-             break;
+      if (ret == -1)
+        break;
 
-           default:
-             session->internals.errnum = EIO;
-             break;
-           }
-         WSASetLastError (tmperr);
-       }
-#endif
+      total += ret;
     }
+
+  if (total > 0)
+    return total;
+  
+  return ret;
+}
+
+static ssize_t
+_gnutls_writev (gnutls_session_t session, const giovec_t * giovec, int 
giovec_cnt)
+{
+  int i;
+  gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
+
+  reset_errno(session);
+
+  if (session->internals.push_func != NULL)
+    i = _gnutls_writev_emu(session, giovec, giovec_cnt);
   else
-    i = session->internals._gnutls_push_func (fd, iptr, sizeOfPtr);
+    i = session->internals.vec_push_func (fd, giovec, giovec_cnt);
 
   if (i == -1)
     {
-      int err = session->internals.errnum ? session->internals.errnum
-       : errno;
-
+      int err = get_errno(session);
+_gnutls_debug_log("errno: %d\n", err);
       if (err == EAGAIN)
        return GNUTLS_E_AGAIN;
       else if (err == EINTR)
@@ -410,6 +399,7 @@ _gnutls_write (gnutls_session_t session, void *iptr,
     }
   return i;
 }
+
 #define RCVLOWAT session->internals.lowat
 
 /* This function is only used with berkeley style sockets.
@@ -435,7 +425,7 @@ _gnutls_io_clear_peeked_data (gnutls_session_t session)
   sum = 0;
   do
     {                          /* we need this to finish now */
-      ret = _gnutls_read (session, peekdata, RCVLOWAT - sum, 0);
+      ret = _gnutls_read (session, peekdata, RCVLOWAT - sum, 
session->internals.pull_func);
       if (ret > 0)
        sum += ret;
     }
@@ -493,7 +483,7 @@ _gnutls_io_read_buffered (gnutls_session_t session, opaque 
** iptr,
   /* If an external pull function is used, then do not leave
    * any data into the kernel buffer.
    */
-  if (session->internals._gnutls_pull_func != NULL)
+  if (session->internals.pull_func != system_read)
     {
       recvlowat = 0;
     }
@@ -562,7 +552,7 @@ _gnutls_io_read_buffered (gnutls_session_t session, opaque 
** iptr,
    */
   if (recvdata - recvlowat > 0)
     {
-      ret = _gnutls_read (session, &buf[buf_pos], recvdata - recvlowat, 0);
+      ret = _gnutls_read (session, &buf[buf_pos], recvdata - recvlowat, 
session->internals.pull_func);
 
       /* return immediately if we got an interrupt or eagain
        * error.
@@ -593,7 +583,7 @@ _gnutls_io_read_buffered (gnutls_session_t session, opaque 
** iptr,
    */
   if (ret == (recvdata - recvlowat) && recvlowat > 0)
     {
-      ret2 = _gnutls_read (session, &buf[buf_pos], recvlowat, MSG_PEEK);
+      ret2 = _gnutls_read (session, &buf[buf_pos], recvlowat, 
system_read_peek);
 
       if (ret2 < 0 && gnutls_error_is_fatal (ret2) == 0)
        {
@@ -664,7 +654,7 @@ _gnutls_io_read_buffered (gnutls_session_t session, opaque 
** iptr,
  */
 ssize_t
 _gnutls_io_write_buffered (gnutls_session_t session,
-                          mbuffer_st *bufel)
+                          mbuffer_st *bufel, unsigned int mflag)
 {
   mbuffer_head_st * const send_buffer = &session->internals.record_send_buffer;
 
@@ -675,9 +665,14 @@ _gnutls_io_write_buffered (gnutls_session_t session,
      (int)bufel->msg.size, session->internals.transport_recv_ptr,
      (int)send_buffer->byte_length);
 
-  return _gnutls_io_write_flush (session);
+  if (mflag == MBUFFER_FLUSH)
+    return _gnutls_io_write_flush (session);
+  else
+    return bufel->msg.size;
 }
 
+typedef ssize_t (*send_func)(gnutls_session_t, const giovec_t *, int);
+
 /* This function writes the data that are left in the
  * TLS write buffer (ie. because the previous write was
  * interrupted.
@@ -685,53 +680,70 @@ _gnutls_io_write_buffered (gnutls_session_t session,
 ssize_t
 _gnutls_io_write_flush (gnutls_session_t session)
 {
-  mbuffer_head_st * const send_buffer = &session->internals.record_send_buffer;
   gnutls_datum_t msg;
+  mbuffer_head_st * send_buffer = &session->internals.record_send_buffer;
   int ret;
-  ssize_t total = 0;
+  ssize_t sent = 0, tosend = 0;
+  giovec_t iovec[MAX_QUEUE];
+  int i = 0;
+  mbuffer_st* cur;
 
   _gnutls_write_log ("WRITE FLUSH: %d bytes in buffer.\n",
                     (int)send_buffer->byte_length);
 
-  for (_mbuffer_get_head (send_buffer, &msg);
-       msg.data != NULL && msg.size > 0;
-       _mbuffer_get_head (send_buffer, &msg))
+  for (cur=_mbuffer_get_first(send_buffer, &msg);
+          cur != NULL;
+          cur = _mbuffer_get_next (cur, &msg))
+        {
+          iovec[i].iov_base = msg.data;
+          iovec[i++].iov_len = msg.size;
+          tosend += msg.size;
+          
+          /* we buffer up to MAX_QUEUE messages */
+          if (i>=sizeof(iovec)/sizeof(iovec[0]))
+            {
+              gnutls_assert();
+              return GNUTLS_E_INTERNAL_ERROR;
+            }
+        }
+        
+  ret = _gnutls_writev (session, iovec, i);
+  if (ret >= 0)
     {
-      ret = _gnutls_write (session, msg.data, msg.size);
-
-      if (ret >= 0)
-       {
-         _mbuffer_remove_bytes (send_buffer, ret);
-
-         _gnutls_write_log ("WRITE: wrote %d bytes, %d bytes left.\n",
+          _mbuffer_remove_bytes (send_buffer, ret);
+          _gnutls_write_log ("WRITE: wrote %d bytes, %d bytes left.\n",
                             ret, (int)send_buffer->byte_length);
 
-         total += ret;
-       }
-      else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
-       {
-         _gnutls_write_log ("WRITE interrupted: %d bytes left.\n",
+          sent += ret;
+    }
+  else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
+    {
+          _gnutls_write_log ("WRITE interrupted: %d bytes left.\n",
                             (int)send_buffer->byte_length);
          return ret;
-       }
-      else
-       {
-         _gnutls_write_log ("WRITE error: code %d, %d bytes left.\n",
-                            ret, (int)send_buffer->byte_length);
+    }
+  else
+    {
+          _gnutls_write_log ("WRITE error: code %d, %d bytes left.\n",
+                    ret, (int)send_buffer->byte_length);
 
-         gnutls_assert ();
-         return ret;
-       }
+          gnutls_assert ();
+          return ret;
+    }
+
+  if (sent < tosend)
+    {
+      gnutls_assert();
+      return GNUTLS_E_AGAIN;
     }
 
-  return total;
+  return sent;
 }
 
 /* This function writes the data that are left in the
  * Handshake write buffer (ie. because the previous write was
  * interrupted.
  *
- * FIXME: This is practically the same as _gnutls_io_write_flush.
  */
 ssize_t
 _gnutls_handshake_io_write_flush (gnutls_session_t session)
@@ -740,17 +752,18 @@ _gnutls_handshake_io_write_flush (gnutls_session_t 
session)
   gnutls_datum_t msg;
   int ret;
   ssize_t total = 0;
+  mbuffer_st * cur;
 
   _gnutls_write_log ("HWRITE FLUSH: %d bytes in buffer.\n",
                     (int)send_buffer->byte_length);
 
-  for (_mbuffer_get_head (send_buffer, &msg);
-       msg.data != NULL && msg.size > 0;
-       _mbuffer_get_head (send_buffer, &msg))
+  for (cur = _mbuffer_get_first (send_buffer, &msg);
+       cur != NULL;
+       cur = _mbuffer_get_first (send_buffer, &msg))
     {
       ret = _gnutls_send_int (session, GNUTLS_HANDSHAKE,
                              session->internals.handshake_send_buffer_htype,
-                             msg.data, msg.size);
+                             msg.data, msg.size, 0/* do not flush */);
 
       if (ret >= 0)
        {
@@ -761,12 +774,6 @@ _gnutls_handshake_io_write_flush (gnutls_session_t session)
 
          total += ret;
        }
-      else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
-       {
-         _gnutls_write_log ("HWRITE interrupted: %d bytes left.\n",
-                            (int)send_buffer->byte_length);
-         return ret;
-       }
       else
        {
          _gnutls_write_log ("HWRITE error: code %d, %d bytes left.\n",
@@ -777,17 +784,17 @@ _gnutls_handshake_io_write_flush (gnutls_session_t 
session)
        }
     }
 
-  return total;
+  return _gnutls_io_write_flush (session);
+
 }
 
 
 /* This is a send function for the gnutls handshake 
  * protocol. Just makes sure that all data have been sent.
  *
- * FIXME: This is practically the same as _gnutls_io_write_buffered.
  */
-ssize_t
-_gnutls_handshake_io_send_int (gnutls_session_t session,
+void
+_gnutls_handshake_io_cache_int (gnutls_session_t session,
                               gnutls_handshake_description_t htype,
                               mbuffer_st *bufel)
 {
@@ -801,7 +808,7 @@ _gnutls_handshake_io_send_int (gnutls_session_t session,
      (int)bufel->msg.size,
      (int)send_buffer->byte_length);
 
-  return _gnutls_handshake_io_write_flush(session);
+  return;
 }
 
 /* This is a receive function for the gnutls handshake 
@@ -969,3 +976,85 @@ _gnutls_handshake_buffer_clear (gnutls_session_t session)
 
   return 0;
 }
+
+/**
+ * gnutls_transport_set_pull_function:
+ * @pull_func: a callback function similar to read()
+ * @session: gnutls session
+ *
+ * This is the function where you set a function for gnutls to receive
+ * data.  Normally, if you use berkeley style sockets, do not need to
+ * use this function since the default (recv(2)) will probably be ok.
+ *
+ * PULL_FUNC is of the form,
+ * ssize_t (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t);
+ **/
+void
+gnutls_transport_set_pull_function (gnutls_session_t session,
+                                   gnutls_pull_func pull_func)
+{
+  session->internals.pull_func = pull_func;
+}
+
+/**
+ * gnutls_transport_set_push_function:
+ * @push_func: a callback function similar to write()
+ * @session: gnutls session
+ *
+ * This is the function where you set a push function for gnutls to
+ * use in order to send data.  If you are going to use berkeley style
+ * sockets, you do not need to use this function since the default
+ * (send(2)) will probably be ok.  Otherwise you should specify this
+ * function for gnutls to be able to send data.
+ *
+ * PUSH_FUNC is of the form,
+ * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
+ **/
+void
+gnutls_transport_set_push_function (gnutls_session_t session,
+                                   gnutls_push_func push_func)
+{
+  session->internals.push_func = push_func;
+  session->internals.vec_push_func = NULL;
+}
+
+/**
+ * @session: gnutls session
+ * gnutls_transport_set_push_function2:
+ * @vec_func: a callback function similar to writev()
+ *
+ * This is the function where you set a push function for gnutls to
+ * use in order to send data.  If you are going to use berkeley style
+ * sockets, you do not need to use this function since the default
+ * (send(2)) will probably be ok.  Otherwise you should specify this
+ * function for gnutls to be able to send data.
+ *
+ * PUSH_FUNC is of the form,
+ * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
+ **/
+void
+gnutls_transport_set_push_function2 (gnutls_session_t session,
+                                   gnutls_vec_push_func vec_func)
+{
+  session->internals.push_func = NULL;
+  session->internals.vec_push_func = vec_func;
+}
+
+/**
+ * @session: gnutls session
+ * gnutls_transport_set_errno_function:
+ * @errno_func: a callback function similar to write()
+ *
+ * This is the function where you set a function to retrieve errno
+ * after a failed push or pull operation.
+ *
+ * errno_func is of the form,
+ * int (*gnutls_errno_func)(gnutls_transport_ptr_t);
+ * and should return the errno.
+ **/
+void
+gnutls_transport_set_errno_function (gnutls_session_t session,
+                                   gnutls_errno_func errno_func)
+{
+  session->internals.errno_func = errno_func;
+}
diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h
index 729bcfc..5352874 100644
--- a/lib/gnutls_buffers.h
+++ b/lib/gnutls_buffers.h
@@ -22,6 +22,10 @@
  * USA
  *
  */
+#ifndef GNUTLS_BUFFERS_H
+# define GNUTLS_BUFFERS_H
+
+#define MBUFFER_FLUSH 1
 
 int _gnutls_record_buffer_put (content_type_t type,
                               gnutls_session_t session, opaque * data,
@@ -37,7 +41,7 @@ void _gnutls_io_clear_read_buffer (gnutls_session_t);
 int _gnutls_io_clear_peeked_data (gnutls_session_t session);
 
 ssize_t _gnutls_io_write_buffered (gnutls_session_t session,
-                                  mbuffer_st *bufel);
+                                  mbuffer_st *bufel, unsigned int mflag);
 
 int _gnutls_handshake_buffer_get_size (gnutls_session_t session);
 int _gnutls_handshake_buffer_put (gnutls_session_t session, opaque * data,
@@ -54,8 +58,10 @@ int _gnutls_handshake_buffer_get_ptr (gnutls_session_t 
session,
 ssize_t _gnutls_handshake_io_recv_int (gnutls_session_t, content_type_t,
                                       gnutls_handshake_description_t, void *,
                                       size_t);
-ssize_t _gnutls_handshake_io_send_int (gnutls_session_t,
+void _gnutls_handshake_io_cache_int (gnutls_session_t,
                                       gnutls_handshake_description_t,
                                       mbuffer_st *bufel);
 ssize_t _gnutls_io_write_flush (gnutls_session_t session);
 ssize_t _gnutls_handshake_io_write_flush (gnutls_session_t session);
+
+#endif
diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c
index 223abdc..943d2de 100644
--- a/lib/gnutls_global.c
+++ b/lib/gnutls_global.c
@@ -269,45 +269,6 @@ gnutls_global_deinit (void)
  * historical reasons.
  */
 
-/**
- * gnutls_transport_set_pull_function:
- * @pull_func: a callback function similar to read()
- * @session: gnutls session
- *
- * This is the function where you set a function for gnutls to receive
- * data.  Normally, if you use berkeley style sockets, do not need to
- * use this function since the default (recv(2)) will probably be ok.
- *
- * PULL_FUNC is of the form,
- * ssize_t (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t);
- **/
-void
-gnutls_transport_set_pull_function (gnutls_session_t session,
-                                   gnutls_pull_func pull_func)
-{
-  session->internals._gnutls_pull_func = pull_func;
-}
-
-/**
- * gnutls_transport_set_push_function:
- * @push_func: a callback function similar to write()
- * @session: gnutls session
- *
- * This is the function where you set a push function for gnutls to
- * use in order to send data.  If you are going to use berkeley style
- * sockets, you do not need to use this function since the default
- * (send(2)) will probably be ok.  Otherwise you should specify this
- * function for gnutls to be able to send data.
- *
- * PUSH_FUNC is of the form,
- * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
- **/
-void
-gnutls_transport_set_push_function (gnutls_session_t session,
-                                   gnutls_push_func push_func)
-{
-  session->internals._gnutls_push_func = push_func;
-}
 
 /**
  * gnutls_check_version:
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index 790861a..780d573 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -1162,7 +1162,30 @@ _gnutls_send_handshake (gnutls_session_t session, 
mbuffer_st *bufel,
 
   session->internals.last_handshake_out = type;
 
-  ret = _gnutls_handshake_io_send_int (session, type, bufel);
+  _gnutls_handshake_io_cache_int (session, type, bufel);
+    
+  switch (type) 
+    {
+      case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: /* this one is followed by 
ServerHelloDone
+                                              * or ClientKeyExchange always.
+                                              */
+      case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE: /* as above */
+      case GNUTLS_HANDSHAKE_SERVER_HELLO: /* as above */
+      case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: /* as above */
+      case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: /* followed by 
ChangeCipherSpec */
+
+      /* now for client Certificate, ClientKeyExchange and
+       * CertificateVerify are always followed by ChangeCipherSpec
+       */
+      case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
+      case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE:
+        ret = 0;
+        break;
+      default:
+        /* send cached messages */
+        ret = _gnutls_handshake_io_write_flush(session);
+        break;
+    }
 
   return ret;
 }
@@ -2307,12 +2330,25 @@ _gnutls_recv_hello (gnutls_session_t session, opaque * 
data, int datalen)
  *     CertificateVerify*
  *     [ChangeCipherSpec]
  *     Finished                     -------->
+ *                                                NewSessionTicket
  *                                              [ChangeCipherSpec]
  *                                  <--------             Finished
  *
  * (*): means optional packet.
  */
 
+/* Handshake when resumming session:
+ *      Client                                                Server
+ *
+ *      ClientHello                   -------->
+ *                                                      ServerHello
+ *                                               [ChangeCipherSpec]
+ *                                   <--------             Finished
+ *     [ChangeCipherSpec]
+ *     Finished                      -------->
+ * 
+ */
+
 /**
  * gnutls_rehandshake:
  * @session: is a #gnutls_session_t structure.
@@ -2731,6 +2767,7 @@ static int
 _gnutls_send_handshake_final (gnutls_session_t session, int init)
 {
   int ret = 0;
+  int oldstate = STATE;
 
   /* Send the CHANGE CIPHER SPEC PACKET */
 
@@ -2738,8 +2775,18 @@ _gnutls_send_handshake_final (gnutls_session_t session, 
int init)
     {
     case STATE0:
     case STATE20:
-      ret = _gnutls_send_change_cipher_spec (session, AGAIN (STATE20));
+
       STATE = STATE20;
+
+      ret = _gnutls_handshake_io_write_flush(session);
+      if (ret < 0) 
+        {
+          gnutls_assert();
+          return ret;
+        }
+
+      ret = _gnutls_send_change_cipher_spec (session, AGAIN2 (oldstate, 
STATE20));
+
       if (ret < 0)
        {
          ERR ("send ChangeCipherSpec", ret);
diff --git a/lib/gnutls_handshake.h b/lib/gnutls_handshake.h
index 4203b10..9a0ab6f 100644
--- a/lib/gnutls_handshake.h
+++ b/lib/gnutls_handshake.h
@@ -61,4 +61,5 @@ void _gnutls_handshake_hash_buffers_clear (gnutls_session_t 
session);
 /* This returns true if we have got there
  * before (and not finished due to an interrupt).
  */
-#define AGAIN(target) STATE==target?1:0
+#define AGAIN(target) (STATE==target?1:0)
+#define AGAIN2(state, target) (state==target?1:0)
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 47d96d1..a7e3287 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -586,8 +586,10 @@ typedef struct
 
   /* PUSH & PULL functions.
    */
-  gnutls_pull_func _gnutls_pull_func;
-  gnutls_push_func _gnutls_push_func;
+  gnutls_pull_func pull_func;
+  gnutls_push_func push_func;
+  gnutls_vec_push_func vec_push_func;
+  gnutls_errno_func errno_func;
   /* Holds the first argument of PUSH and PULL
    * functions;
    */
diff --git a/lib/gnutls_mbuffers.c b/lib/gnutls_mbuffers.c
index cb360e3..de06324 100644
--- a/lib/gnutls_mbuffers.c
+++ b/lib/gnutls_mbuffers.c
@@ -63,14 +63,29 @@ _mbuffer_enqueue (mbuffer_head_st *buf, mbuffer_st *bufel)
   buf->tail = &bufel->next;
 }
 
-void
-_mbuffer_get_head (mbuffer_head_st *buf, gnutls_datum_t *msg)
+mbuffer_st* _mbuffer_get_first (mbuffer_head_st *buf, gnutls_datum_t *msg)
 {
-  mbuffer_st *bufel;
+  mbuffer_st *bufel = buf->head;
+
+  if (bufel)
+    {
+      msg->data = bufel->msg.data + bufel->mark;
+      msg->size = bufel->msg.size - bufel->mark;
+    }
+  else
+    {
+      msg->data = NULL;
+      msg->size = 0;
+    }
+  return bufel;
+}
+
+mbuffer_st* _mbuffer_get_next (mbuffer_st * cur, gnutls_datum_t *msg)
+{
+  mbuffer_st *bufel = cur->next;
 
-  if (buf->head)
+  if (bufel)
     {
-      bufel = buf->head;
       msg->data = bufel->msg.data + bufel->mark;
       msg->size = bufel->msg.size - bufel->mark;
     }
@@ -79,6 +94,7 @@ _mbuffer_get_head (mbuffer_head_st *buf, gnutls_datum_t *msg)
       msg->data = NULL;
       msg->size = 0;
     }
+  return bufel;
 }
 
 static inline void
diff --git a/lib/gnutls_mbuffers.h b/lib/gnutls_mbuffers.h
index 1ea6718..ed94824 100644
--- a/lib/gnutls_mbuffers.h
+++ b/lib/gnutls_mbuffers.h
@@ -30,10 +30,12 @@
 void _mbuffer_init (mbuffer_head_st *buf);
 void _mbuffer_clear (mbuffer_head_st *buf);
 void _mbuffer_enqueue (mbuffer_head_st *buf, mbuffer_st *bufel);
-void _mbuffer_get_head (mbuffer_head_st *buf, gnutls_datum_t *msg);
 int  _mbuffer_remove_bytes (mbuffer_head_st *buf, size_t bytes);
 mbuffer_st* _mbuffer_alloc (size_t payload_size, size_t maximum_size);
 
+mbuffer_st* _mbuffer_get_first (mbuffer_head_st *buf, gnutls_datum_t *msg);
+mbuffer_st* _mbuffer_get_next (mbuffer_st * cur, gnutls_datum_t *msg);
+
 /* This is dangerous since it will replace bufel with a new
  * one.
  */
diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c
index 9ea214e..a10a6fd 100644
--- a/lib/gnutls_record.c
+++ b/lib/gnutls_record.c
@@ -335,7 +335,7 @@ copy_record_version (gnutls_session_t session,
 ssize_t
 _gnutls_send_int (gnutls_session_t session, content_type_t type,
                  gnutls_handshake_description_t htype, const void *_data,
-                 size_t sizeofdata)
+                 size_t sizeofdata, unsigned int mflags)
 {
   mbuffer_st *bufel;
   size_t cipher_size;
@@ -384,7 +384,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t 
type,
   /* Only encrypt if we don't have data to send 
    * from the previous run. - probably interrupted.
    */
-  if (session->internals.record_send_buffer.byte_length > 0)
+  if (mflags != 0 && session->internals.record_send_buffer.byte_length > 0)
     {
       ret = _gnutls_io_write_flush (session);
       if (ret > 0)
@@ -435,7 +435,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t 
type,
        }
 
       _mbuffer_set_udata_size(bufel, cipher_size);
-      ret = _gnutls_io_write_buffered (session, bufel);
+      ret = _gnutls_io_write_buffered (session, bufel, mflags);
     }
 
   if (ret != cipher_size)
@@ -481,7 +481,7 @@ _gnutls_send_change_cipher_spec (gnutls_session_t session, 
int again)
   _gnutls_handshake_log ("REC[%p]: Sent ChangeCipherSpec\n", session);
 
   if (again == 0)
-    return _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, data, 1);
+    return _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, data, 1, 
MBUFFER_FLUSH);
   else
     {
       return _gnutls_io_write_flush (session);
@@ -1133,7 +1133,7 @@ gnutls_record_send (gnutls_session_t session, const void 
*data,
                    size_t sizeofdata)
 {
   return _gnutls_send_int (session, GNUTLS_APPLICATION_DATA, -1, data,
-                          sizeofdata);
+                          sizeofdata, MBUFFER_FLUSH);
 }
 
 /**
diff --git a/lib/gnutls_record.h b/lib/gnutls_record.h
index bcb991f..6d35247 100644
--- a/lib/gnutls_record.h
+++ b/lib/gnutls_record.h
@@ -23,10 +23,18 @@
  *
  */
 
+#ifndef GNUTLS_RECORD_H
+# define GNUTLS_RECORD_H
+
+# include <gnutls/gnutls.h>
+# include <gnutls_buffers.h>
+
 ssize_t _gnutls_send_int (gnutls_session_t session, content_type_t type,
                          gnutls_handshake_description_t htype,
-                         const void *data, size_t sizeofdata);
+                         const void *data, size_t sizeofdata, unsigned int 
mflags);
 ssize_t _gnutls_recv_int (gnutls_session_t session, content_type_t type,
                          gnutls_handshake_description_t, opaque * data,
                          size_t sizeofdata);
 ssize_t _gnutls_send_change_cipher_spec (gnutls_session_t session, int again);
+
+#endif
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index b5769de..416c1ba 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -46,6 +46,7 @@
 #include <gnutls_algorithms.h>
 #include <gnutls_rsa_export.h>
 #include <gnutls_extensions.h>
+#include <system.h>
 
 /* These should really be static, but src/tests.c calls them.  Make
    them public functions?  */
@@ -352,6 +353,14 @@ gnutls_init (gnutls_session_t * session, 
gnutls_connection_end_t con_end)
    */
   (*session)->internals.priorities.sr = SR_PARTIAL;
 
+#ifdef HAVE_WRITEV
+  gnutls_transport_set_push_function2(*session, system_writev);
+#else
+  gnutls_transport_set_push_function(*session, system_write);
+#endif
+  gnutls_transport_set_pull_function(*session, system_read);
+  gnutls_transport_set_errno_function(*session, system_errno);
+
   return 0;
 }
 
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 9555432..6bed294 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -1209,10 +1209,19 @@ extern "C"
 
 /* Session stuff
  */
+  typedef struct {
+    void  *iov_base;    /* Starting address */
+    size_t iov_len;     /* Number of bytes to transfer */
+  } giovec_t;
+
   typedef ssize_t (*gnutls_pull_func) (gnutls_transport_ptr_t, void *,
                                       size_t);
-  typedef ssize_t (*gnutls_push_func) (gnutls_transport_ptr_t, const void *,
-                                      size_t);
+  typedef ssize_t (*gnutls_push_func) (gnutls_transport_ptr_t, const void *, 
size_t);
+
+  typedef ssize_t (*gnutls_vec_push_func) (gnutls_transport_ptr_t, const 
giovec_t *iov, int iovcnt);
+
+  typedef int (*gnutls_errno_func) (gnutls_transport_ptr_t);
+
   void gnutls_transport_set_ptr (gnutls_session_t session,
                                 gnutls_transport_ptr_t ptr);
   void gnutls_transport_set_ptr2 (gnutls_session_t session,
@@ -1227,11 +1236,16 @@ extern "C"
   void gnutls_transport_set_lowat (gnutls_session_t session, int num);
 
 
+  void gnutls_transport_set_push_function2 (gnutls_session_t session,
+                                      gnutls_vec_push_func vec_func);
   void gnutls_transport_set_push_function (gnutls_session_t session,
                                           gnutls_push_func push_func);
   void gnutls_transport_set_pull_function (gnutls_session_t session,
                                           gnutls_pull_func pull_func);
 
+  void gnutls_transport_set_errno_function (gnutls_session_t session,
+                                          gnutls_errno_func errno_func);
+
   void gnutls_transport_set_errno (gnutls_session_t session, int err);
   void gnutls_transport_set_global_errno (int err);
 
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 9b25b29..88c5c25 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -675,6 +675,8 @@ GNUTLS_2_11
        gnutls_pubkey_get_preferred_hash_algorithm;
        gnutls_x509_crt_get_preferred_hash_algorithm;
        gnutls_global_set_mutex;
+        gnutls_transport_set_push_function2;
+        gnutls_transport_set_errno_function;
 
        gnutls_sec_param_to_pk_bits;
        gnutls_sec_param_get_name;
diff --git a/lib/locks.c b/lib/locks.c
index 30ffd53..ea96733 100644
--- a/lib/locks.c
+++ b/lib/locks.c
@@ -31,147 +31,6 @@
 
 #include <locks.h>
 
-#ifdef HAVE_WIN32_LOCKS
-
-# include <windows.h>
-
-/* FIXME: win32 locks are untested */
-static int gnutls_system_mutex_init (void **priv)
-{
-  CRITICAL_SECTION *lock = malloc (sizeof (CRITICAL_SECTION));
-  int ret;
-
-  if (lock==NULL)
-    return GNUTLS_E_MEMORY_ERROR;
-
-  InitializeCriticalSection(lock);
-     
-  *priv = lock;
-  
-  return 0;
-}
-
-static int gnutls_system_mutex_deinit (void **priv)
-{
-  DeleteCriticalSection((CRITICAL_SECTION*)*priv);
-  free(*priv);
-  
-  return 0;
-}
-
-static int gnutls_system_mutex_lock (void **priv)
-{
-  EnterCriticalSection((CRITICAL_SECTION*)*priv);
-  return 0;
-}
-
-static int gnutls_system_mutex_unlock (void **priv)
-{
-  LeaveCriticalSection((CRITICAL_SECTION*)*priv);
-  return 0;
-}
-
-int _gnutls_atfork(void (*prepare)(void), void (*parent)(void), void 
(*child)(void))
-{
-  return 0;
-}
-
-
-#endif /* WIN32_LOCKS */
-
-#ifdef HAVE_PTHREAD_LOCKS
-# include <pthread.h>
-
-static int gnutls_system_mutex_init (void **priv)
-{
-  pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t));
-  int ret;
-
-  if (lock==NULL)
-    return GNUTLS_E_MEMORY_ERROR;
-
-   ret = pthread_mutex_init (lock, NULL);
-   if (ret)
-     {
-       free(lock);
-       gnutls_assert();
-       return GNUTLS_E_LOCKING_ERROR;
-     }
-     
-  *priv = lock;
-  
-  return 0;
-}
-
-static int gnutls_system_mutex_deinit (void **priv)
-{
-  pthread_mutex_destroy((pthread_mutex_t*)*priv);
-  free(*priv);
-  return 0;
-}
-
-static int gnutls_system_mutex_lock (void **priv)
-{
-  if (pthread_mutex_lock((pthread_mutex_t*)*priv))
-    {
-        gnutls_assert();
-        return GNUTLS_E_LOCKING_ERROR;
-    }
-
-  return 0;
-}
-
-static int gnutls_system_mutex_unlock (void **priv)
-{
-  if (pthread_mutex_unlock((pthread_mutex_t*)*priv))
-    {
-        gnutls_assert();
-        return GNUTLS_E_LOCKING_ERROR;
-    }
-
-  return 0;
-}
-
-int _gnutls_atfork(void (*prepare)(void), void (*parent)(void), void 
(*child)(void))
-{
-  return pthread_atfork(prepare, parent, child);
-}
-
-#endif /* PTHREAD_LOCKS */
-
-#ifdef HAVE_NO_LOCKS
-
-static int gnutls_system_mutex_init (void **priv)
-{
-  return 0;
-}
-
-static int gnutls_system_mutex_deinit (void **priv)
-{
-  return 0;
-}
-
-static int gnutls_system_mutex_lock (void **priv)
-{
-  return 0;
-}
-
-static int gnutls_system_mutex_unlock (void **priv)
-{
-  return 0;
-}
-
-int _gnutls_atfork(void (*prepare)(void), void (*parent)(void), void 
(*child)(void))
-{
-  return 0;
-}
-
-#endif /* NO_LOCKS */
-
-mutex_init_func gnutls_mutex_init = gnutls_system_mutex_init;
-mutex_deinit_func gnutls_mutex_deinit = gnutls_system_mutex_deinit;
-mutex_lock_func gnutls_mutex_lock = gnutls_system_mutex_lock;
-mutex_unlock_func gnutls_mutex_unlock = gnutls_system_mutex_unlock;
 
 /**
  * gnutls_global_set_mutex:
diff --git a/lib/locks.h b/lib/locks.h
index 7fc31c0..0a91d2f 100644
--- a/lib/locks.h
+++ b/lib/locks.h
@@ -4,21 +4,9 @@
 #include <gnutls/gnutls.h>
 #include <gnutls_int.h>
 
-#ifdef _WIN32
-# define HAVE_WIN32_LOCKS
-#else
-# ifdef HAVE_LIBPTHREAD
-#  define HAVE_PTHREAD_LOCKS
-# else
-#  define HAVE_NO_LOCKS
-# endif
-#endif
-
 extern mutex_init_func gnutls_mutex_init;
 extern mutex_deinit_func gnutls_mutex_deinit;
 extern mutex_lock_func gnutls_mutex_lock;
 extern mutex_unlock_func gnutls_mutex_unlock;
 
-int _gnutls_atfork(void (*prepare)(void), void (*parent)(void), void 
(*child)(void));
-
 #endif
diff --git a/lib/pakchois/pakchois.c b/lib/pakchois/pakchois.c
index 45cd130..6785416 100644
--- a/lib/pakchois/pakchois.c
+++ b/lib/pakchois/pakchois.c
@@ -46,6 +46,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include "../locks.h"
+#include "../system.h"
 #include "dlopen.h"
 
 #ifdef HAVE_WORDEXP
diff --git a/lib/locks.c b/lib/system.c
similarity index 70%
copy from lib/locks.c
copy to lib/system.c
index 30ffd53..8e33090 100644
--- a/lib/locks.c
+++ b/lib/system.c
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2010
- * Free Software Foundation, Inc.
+ * Copyright (C) 2010 Free Software Foundation, Inc.
  *
  * Author: Nikos Mavrogiannopoulos
  *
@@ -23,17 +22,85 @@
  *
  */
 
+#include <system.h>
 #include <gnutls_int.h>
 #include <gnutls_errors.h>
-#include <libtasn1.h>
-#include <gnutls_dh.h>
-#include <random.h>
 
-#include <locks.h>
+#include <errno.h>
+
+#ifdef _WIN32
+# include <windows.h>
+
+#else
+# ifdef HAVE_PTHREAD_LOCKS
+#  include <pthread.h>
+# endif
+#endif
+
+/* We need to disable gnulib's replacement wrappers to get native
+   Windows interfaces. */
+#undef recv
+#undef send
+
+/* System specific function wrappers.
+ */
+
+/* wrappers for write() and writev()
+ */
+#ifdef _WIN32
+
+int system_errno(gnutls_transport_ptr)
+{
+  int tmperr = WSAGetLastError ();
+  int ret = 0;
+  switch (tmperr)
+    {
+        case WSAEWOULDBLOCK:
+          ret = EAGAIN;
+          break;
+        case WSAEINTR:
+          ret = EINTR;
+          break;
+        default:
+          ret = EIO;
+          break;
+     }
+   WSASetLastError (tmperr);
+
+  return ret;
+}
+
+ssize_t system_write(gnutls_transport_ptr ptr, const void* data, size_t 
data_size)
+{
+  return send( GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0);
+}
+#else /* POSIX */
+int system_errno(gnutls_transport_ptr ptr)
+{
+  return errno;
+}
+
+ssize_t system_writev(gnutls_transport_ptr ptr, const giovec_t * iovec, int 
iovec_cnt)
+{
+  return writev(GNUTLS_POINTER_TO_INT(ptr), (struct iovec*) iovec, iovec_cnt);
+
+}
+#endif
+
+ssize_t system_read(gnutls_transport_ptr ptr, void* data, size_t data_size)
+{
+  return recv( GNUTLS_POINTER_TO_INT(ptr), data, data_size, 0);
+}
+
+ssize_t system_read_peek(gnutls_transport_ptr ptr, void* data, size_t 
data_size)
+{
+  return recv( GNUTLS_POINTER_TO_INT(ptr), data, data_size, MSG_PEEK);
+}
+
+/* Thread stuff */
 
 #ifdef HAVE_WIN32_LOCKS
 
-# include <windows.h>
 
 /* FIXME: win32 locks are untested */
 static int gnutls_system_mutex_init (void **priv)
@@ -80,7 +147,6 @@ int _gnutls_atfork(void (*prepare)(void), void 
(*parent)(void), void (*child)(vo
 #endif /* WIN32_LOCKS */
 
 #ifdef HAVE_PTHREAD_LOCKS
-# include <pthread.h>
 
 static int gnutls_system_mutex_init (void **priv)
 {
@@ -173,31 +239,3 @@ mutex_deinit_func gnutls_mutex_deinit = 
gnutls_system_mutex_deinit;
 mutex_lock_func gnutls_mutex_lock = gnutls_system_mutex_lock;
 mutex_unlock_func gnutls_mutex_unlock = gnutls_system_mutex_unlock;
 
-/**
- * gnutls_global_set_mutex:
- * @init: mutex initialization function
- * @deinit: mutex deinitialization function
- * @lock: mutex locking function
- * @unlock: mutex unlocking function
- *
- * With this function you are allowed to override the default mutex
- * locks used in some parts of gnutls and dependent libraries. This function
- * should be used if you have complete control of your program and libraries.
- * Do not call this function from a library. Instead only initialize gnutls and
- * the default OS mutex locks will be used.
- * 
- * This function must be called before gnutls_global_init().
- *
- **/
-void gnutls_global_set_mutex(mutex_init_func init, mutex_deinit_func deinit, 
-        mutex_lock_func lock, mutex_unlock_func unlock)
-{
-  if (init == NULL || deinit == NULL || lock == NULL  || unlock == NULL)
-    return;
-
-  gnutls_mutex_init = init;
-  gnutls_mutex_deinit = deinit;
-  gnutls_mutex_lock = lock;
-  gnutls_mutex_unlock = unlock;
-}
-
diff --git a/lib/system.h b/lib/system.h
new file mode 100644
index 0000000..c18e74b
--- /dev/null
+++ b/lib/system.h
@@ -0,0 +1,33 @@
+#ifndef SYSTEM_H
+# define SYSTEM_H
+
+#include <gnutls_int.h>
+
+#ifndef _WIN32
+# include <sys/uio.h> /* for writev */
+#endif
+
+int system_errno(gnutls_transport_ptr);
+
+#ifdef _WIN32
+ssize_t system_write(gnutls_transport_ptr ptr, const void* data, size_t 
data_size);
+#else
+# define HAVE_WRITEV
+ssize_t system_writev(gnutls_transport_ptr ptr, const giovec_t * iovec, int 
iovec_cnt);
+#endif
+ssize_t system_read(gnutls_transport_ptr ptr, void* data, size_t data_size);
+ssize_t system_read_peek(gnutls_transport_ptr ptr, void* data, size_t 
data_size);
+
+#endif
+
+#ifdef _WIN32
+# define HAVE_WIN32_LOCKS
+#else
+# ifdef HAVE_LIBPTHREAD
+#  define HAVE_PTHREAD_LOCKS
+# else
+#  define HAVE_NO_LOCKS
+# endif
+#endif
+
+int _gnutls_atfork(void (*prepare)(void), void (*parent)(void), void 
(*child)(void));
diff --git a/libextra/gnutls_ia.c b/libextra/gnutls_ia.c
index f3f1e4a..e2ff0d9 100644
--- a/libextra/gnutls_ia.c
+++ b/libextra/gnutls_ia.c
@@ -97,7 +97,7 @@ _gnutls_send_inner_application (gnutls_session_t session,
       memcpy (p + 4, data, sizeofdata);
     }
 
-  len = _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1, p, plen);
+  len = _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1, p, plen, 
MBUFFER_FLUSH);
 
   if (p)
     gnutls_free (p);
diff --git a/src/serv.c b/src/serv.c
index eb7b892..a6ed9c5 100644
--- a/src/serv.c
+++ b/src/serv.c
@@ -735,6 +735,24 @@ listen_socket (const char *name, int listen_port)
   return 0;
 }
 
+/* strips \r\n from the end of the string 
+ */
+static void strip (char* data)
+{
+int i;
+int len = strlen(data);
+
+  for (i=0;i<len;i++)
+    {
+      if (data[i] == '\r' && data[i+1] == '\n' && data[i+1] == 0)
+        {
+          data[i] = '\n';
+          data[i+1] = 0;
+          break;
+        }
+    }
+}
+
 static void
 get_response (gnutls_session_t session, char *request,
              char **response, int *response_length)
@@ -764,6 +782,7 @@ get_response (gnutls_session_t session, char *request,
     }
   else
     {
+      strip(request);
       fprintf (stderr, "received: %s\n", request);
       if (request[0] == request[1] && request[0] == '*')
        {


hooks/post-receive
-- 
GNU gnutls



reply via email to

[Prev in Thread] Current Thread [Next in Thread]