[gnutls-dev] Re: Gnutls4win: Problem with custom push/pull functions, errno and Visual Studio (Workaround included)

Simon Josefsson jas at extundo.com
Mon Nov 6 12:47:46 CET 2006


Tim Kosse <tim.kosse at filezilla-project.org> writes:

> What if errno != 0 prior to calling the push function and the push
> function just sets session->internals.errnum to 0?
> I think errno has to be initialized with 0 as well.

Standard Unix API semantics is that errno must be set when the
function returns negative, and the code in gnutls checks the return
value before using the value in errno.  However, it seems harmless to
set errno to 0 before the call, and it might catch errors in custom
push/pull functions.  So how about this patch?

Thanks,
Simon

--- gnutls_buffers.c	13 Aug 2006 17:05:52 +0200	2.128
+++ gnutls_buffers.c	06 Nov 2006 12:46:08 +0100	
@@ -77,6 +77,58 @@
 # include <io_debug.h>
 #endif
 
+/**
+ * gnutls_transport_set_errno:
+ * @session: is a #gnutls_session_t structure.
+ * @err: error value to store in session-specific errno variable.
+ *
+ * Store @err in the session-specific errno variable.  Useful values
+ * for @err is EAGAIN and EINTR, other values are treated will be
+ * treated as real errors in the push/pull function.
+ *
+ * This function is useful in replacement push/pull functions set by
+ * gnutls_transport_set_push_function and
+ * gnutls_transport_set_pullpush_function under Windows, where the
+ * replacement push/pull may not have access to the same @errno
+ * variable that is used by GnuTLS (e.g., the application is linked to
+ * msvcr71.dll and gnutls is linked to msvcrt.dll).
+ *
+ * If you don't have the @session variable easily accessible from the
+ * push/pull function, and don't worry about thread conflicts, you can
+ * also use gnutls_transport_set_global_errno().
+ **/
+void
+gnutls_transport_set_errno (gnutls_session_t session, int err)
+{
+  session->internals.errnum = err;
+}
+
+/**
+ * gnutls_transport_set_global_errno:
+ * @err: error value to store in global errno variable.
+ *
+ * Store @err in the global errno variable.  Useful values for @err is
+ * EAGAIN and EINTR, other values are treated will be treated as real
+ * errors in the push/pull function.
+ *
+ * This function is useful in replacement push/pull functions set by
+ * gnutls_transport_set_push_function and
+ * gnutls_transport_set_pullpush_function under Windows, where the
+ * replacement push/pull may not have access to the same @errno
+ * variable that is used by GnuTLS (e.g., the application is linked to
+ * msvcr71.dll and gnutls is linked to msvcrt.dll).
+ *
+ * Whether this function is thread safe or not depends on whether the
+ * global variable errno is thread safe, some system libraries make it
+ * a thread-local variable.  When feasible, using the guaranteed
+ * thread-safe gnutls_transport_set_errno() may be better.
+ **/
+void
+gnutls_transport_set_global_errno (int err)
+{
+  errno = err;
+}
+
 /* Buffers received packets of type APPLICATION DATA and
  * HANDSHAKE DATA.
  */
@@ -264,6 +316,9 @@
   while (left > 0)
     {
 
+      session->internals.errnum = 0;
+      errno = 0;
+
       if (session->internals._gnutls_pull_func == NULL)
 	i = recv (GNUTLS_POINTER_TO_INT(fd), &ptr[sizeOfPtr - left],
 		  left, flags);
@@ -274,10 +329,13 @@
 
       if (i < 0)
 	{
-	  _gnutls_read_log ("READ: %d returned from %d, errno=%d\n", i,
-			    fd, errno);
+	  int err = session->internals.errnum ? session->internals.errnum
+	    : errno;
+
+	  _gnutls_read_log ("READ: %d returned from %d, errno=%d gerrno=%d\n",
+			    i, fd, errno, session->internals.errnum);
 
-	  if (errno == EAGAIN || errno == EINTR)
+	  if (err == EAGAIN || err == EINTR)
 	    {
 	      if (sizeOfPtr - left > 0)
 		{
@@ -289,7 +347,7 @@
 		}
 	      gnutls_assert ();
 
-	      return RET (errno);
+	      return RET (err);
 	    }
 	  else
 	    {
@@ -701,6 +759,9 @@
   while (left > 0)
     {
 
+      session->internals.errnum = 0;
+      errno = 0;
+
       if (session->internals._gnutls_push_func == NULL)
 	i = send (GNUTLS_POINTER_TO_INT(fd), &ptr[n - left], left, 0);
       else
@@ -708,7 +769,10 @@
 
       if (i == -1)
 	{
-	  if (errno == EAGAIN || errno == EINTR)
+	  int err = session->internals.errnum ? session->internals.errnum
+	    : errno;
+
+	  if (err == EAGAIN || err == EINTR)
 	    {
 	      session->internals.record_send_buffer_prev_size += n - left;
 
@@ -726,7 +790,7 @@
 		("WRITE: Interrupted. Stored %d bytes to buffer. Already sent %d bytes.\n",
 		 left, n - left);
 
-	      retval = RET (errno);
+	      retval = RET (err);
 
 	      return retval;
 	    }




More information about the Gnutls-devel mailing list