Selaa lähdekoodia

Refactoring: moved send_/recv_param_adapter() to connection.c and send_/recv_tls_adapter() to connection_https.c

Evgeny Grin (Karlson2k) 8 vuotta sitten
vanhempi
sitoutus
be855dd3d8
3 muutettua tiedostoa jossa 269 lisäystä ja 269 poistoa
  1. 164 0
      src/microhttpd/connection.c
  2. 105 0
      src/microhttpd/connection_https.c
  3. 0 269
      src/microhttpd/daemon.c

+ 164 - 0
src/microhttpd/connection.c

@@ -109,6 +109,168 @@
 #define DEBUG_SEND_DATA MHD_NO
 
 
+/**
+ * Callback for receiving data from the socket.
+ *
+ * @param connection the MHD connection structure
+ * @param other where to write received data to
+ * @param i maximum size of other (in bytes)
+ * @return number of bytes actually received
+ */
+static ssize_t
+recv_param_adapter (struct MHD_Connection *connection,
+                    void *other,
+                    size_t i)
+{
+  ssize_t ret;
+
+  if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
+       (MHD_CONNECTION_CLOSED == connection->state) )
+    {
+      MHD_socket_set_error_ (MHD_SCKT_ENOTCONN_);
+      return -1;
+    }
+  if (i > MHD_SCKT_SEND_MAX_SIZE_)
+    i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */
+
+  ret = MHD_recv_ (connection->socket_fd,
+                   other,
+                   i);
+#ifdef EPOLL_SUPPORT
+  if (0 > ret)
+    {
+      /* Got EAGAIN --- no longer read-ready */
+      if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
+        connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
+    }
+  else if (i > (size_t)ret)
+    connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
+#endif
+  return ret;
+}
+
+
+/**
+ * Callback for writing data to the socket.
+ *
+ * @param connection the MHD connection structure
+ * @param other data to write
+ * @param i number of bytes to write
+ * @return actual number of bytes written
+ */
+static ssize_t
+send_param_adapter (struct MHD_Connection *connection,
+                    const void *other,
+                    size_t i)
+{
+  ssize_t ret;
+  int err;
+
+  if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
+       (MHD_CONNECTION_CLOSED == connection->state) )
+    {
+      MHD_socket_set_error_ (MHD_SCKT_ENOTCONN_);
+      return -1;
+    }
+  if (i > MHD_SCKT_SEND_MAX_SIZE_)
+    i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */
+
+#if LINUX
+  if ( (connection->write_buffer_append_offset ==
+        connection->write_buffer_send_offset) &&
+       (NULL != connection->response) &&
+       (MHD_resp_sender_sendfile == connection->resp_sender) )
+    {
+      /* can use sendfile */
+      int file_fd = connection->response->fd;
+      uint64_t left;
+      uint64_t offsetu64;
+#ifndef HAVE_SENDFILE64
+      off_t offset;
+#else  /* HAVE_SENDFILE64 */
+      off64_t offset;
+#endif /* HAVE_SENDFILE64 */
+      offsetu64 = connection->response_write_position + connection->response->fd_off;
+      left = connection->response->total_size - connection->response_write_position;
+      ret = 0;
+#ifndef HAVE_SENDFILE64
+      if ((uint64_t)OFF_T_MAX < offsetu64)
+        MHD_socket_set_error_to_ENOMEM ();
+      else
+        {
+          offset = (off_t) offsetu64;
+          ret = sendfile (connection->socket_fd,
+                          file_fd,
+                          &offset,
+                          left);
+        }
+#else  /* HAVE_SENDFILE64 */
+      if ((uint64_t)OFF64_T_MAX < offsetu64)
+        MHD_socket_set_error_to_ENOMEM ();
+      else
+        {
+          offset = (off64_t) offsetu64;
+          ret = sendfile64 (connection->socket_fd,
+                            file_fd,
+                            &offset,
+                            left);
+        }
+#endif /* HAVE_SENDFILE64 */
+      if (0 < ret)
+        {
+          /* write successful */
+#ifdef EPOLL_SUPPORT
+          if (left > (uint64_t)ret)
+            connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+#endif /* EPOLL_SUPPORT */
+          return ret;
+        }
+      err = MHD_socket_get_error_();
+#ifdef EPOLL_SUPPORT
+      if ( (0 > ret) && (MHD_SCKT_ERR_IS_EAGAIN_(err)) )
+        {
+          /* EAGAIN --- no longer write-ready */
+          connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+        }
+#endif
+      if (MHD_SCKT_ERR_IS_EINTR_ (err) ||
+          MHD_SCKT_ERR_IS_EAGAIN_ (err))
+        return 0;
+      if (MHD_SCKT_ERR_IS_(err,
+                           MHD_SCKT_EBADF_))
+        return -1;
+      /* sendfile() failed with EINVAL if mmap()-like operations are not
+         supported for FD or other 'unusual' errors occurred, so we should try
+         to fall back to 'SEND'; see also this thread for info on
+         odd libc/Linux behavior with sendfile:
+         http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */
+      connection->resp_sender = MHD_resp_sender_std;
+    }
+#endif
+  ret = MHD_send_ (connection->socket_fd,
+                   other,
+                   i);
+  err = MHD_socket_get_error_();
+#ifdef EPOLL_SUPPORT
+  if (0 > ret)
+    {
+      /* EAGAIN --- no longer write-ready */
+      if (MHD_SCKT_ERR_IS_EAGAIN_(err))
+        connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+    }
+  else if (i > (size_t)ret)
+    connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+#endif
+  /* Handle broken kernel / libc, returning -1 but not setting errno;
+     kill connection as that should be safe; reported on mailinglist here:
+     http://lists.gnu.org/archive/html/libmicrohttpd/2014-10/msg00023.html */
+  if ( (0 > ret) &&
+       (0 == err) )
+    MHD_socket_set_error_ (MHD_SCKT_ECONNRESET_);
+  return ret;
+}
+
+
 /**
  * Check whether is possible to force push socket buffer content as
  * partial packet.
@@ -3445,6 +3607,8 @@ MHD_set_http_callbacks_ (struct MHD_Connection *connection)
 {
   connection->read_handler = &MHD_connection_handle_read;
   connection->write_handler = &MHD_connection_handle_write;
+  connection->recv_cls = &recv_param_adapter;
+  connection->send_cls = &send_param_adapter;
 }
 
 

+ 105 - 0
src/microhttpd/connection_https.c

@@ -35,6 +35,109 @@
 #include <gnutls/gnutls.h>
 
 
+/**
+ * Callback for receiving data from the socket.
+ *
+ * @param connection the MHD_Connection structure
+ * @param other where to write received data to
+ * @param i maximum size of other (in bytes)
+ * @return number of bytes actually received
+ */
+static ssize_t
+recv_tls_adapter (struct MHD_Connection *connection,
+                  void *other,
+                  size_t i)
+{
+  ssize_t res;
+
+  if (i > SSIZE_MAX)
+    i = SSIZE_MAX;
+
+  res = gnutls_record_recv (connection->tls_session,
+                            other,
+                            i);
+  if ( (GNUTLS_E_AGAIN == res) ||
+       (GNUTLS_E_INTERRUPTED == res) )
+    {
+      MHD_socket_set_error_ (MHD_SCKT_EINTR_);
+#ifdef EPOLL_SUPPORT
+      if (GNUTLS_E_AGAIN == res)
+        connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
+#endif
+      return -1;
+    }
+  if (res < 0)
+    {
+      /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
+         disrupted); set errno to something caller will interpret
+         correctly as a hard error */
+      MHD_socket_set_error_ (MHD_SCKT_ECONNRESET_);
+      connection->tls_read_ready = false;
+      return res;
+    }
+
+#ifdef EPOLL_SUPPORT
+  /* If data not available to fill whole buffer - socket is not read ready anymore. */
+  if (i > (size_t)res)
+    connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
+#endif /* EPOLL_SUPPORT */
+
+  /* Check whether TLS buffers still have some unread data. */
+  connection->tls_read_ready = ( ((size_t)res == i) &&
+                                 (0 != gnutls_record_check_pending (connection->tls_session)) );
+  return res;
+}
+
+
+/**
+ * Callback for writing data to the socket.
+ *
+ * @param connection the MHD connection structure
+ * @param other data to write
+ * @param i number of bytes to write
+ * @return actual number of bytes written
+ */
+static ssize_t
+send_tls_adapter (struct MHD_Connection *connection,
+                  const void *other,
+                  size_t i)
+{
+  ssize_t res;
+
+  if (i > SSIZE_MAX)
+    i = SSIZE_MAX;
+
+  res = gnutls_record_send (connection->tls_session,
+                            other,
+                            i);
+  if ( (GNUTLS_E_AGAIN == res) ||
+       (GNUTLS_E_INTERRUPTED == res) )
+    {
+      MHD_socket_set_error_ (MHD_SCKT_EINTR_);
+#ifdef EPOLL_SUPPORT
+      if (GNUTLS_E_AGAIN == res)
+        connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+#endif
+      return -1;
+    }
+  if (res < 0)
+    {
+      /* some other GNUTLS error, should set 'errno'; as we do not
+         really understand the error (not listed in GnuTLS
+         documentation explicitly), we set 'errno' to something that
+         will cause the connection to fail. */
+      MHD_socket_set_error_ (MHD_SCKT_ECONNRESET_);
+      return -1;
+    }
+#ifdef EPOLL_SUPPORT
+  /* If NOT all available data was sent - socket is not write ready anymore. */
+  if (i > (size_t)res)
+    connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+#endif /* EPOLL_SUPPORT */
+  return res;
+}
+
+
 /**
  * Give gnuTLS chance to work on the TLS handshake.
  *
@@ -130,6 +233,8 @@ MHD_set_https_callbacks (struct MHD_Connection *connection)
 {
   connection->read_handler = &MHD_tls_connection_handle_read;
   connection->write_handler = &MHD_tls_connection_handle_write;
+  connection->recv_cls = &recv_tls_adapter;
+  connection->send_cls = &send_tls_adapter;
 }
 
 

+ 0 - 269
src/microhttpd/daemon.c

@@ -430,109 +430,6 @@ MHD_ip_limit_del (struct MHD_Daemon *daemon,
 
 
 #ifdef HTTPS_SUPPORT
-/**
- * Callback for receiving data from the socket.
- *
- * @param connection the MHD_Connection structure
- * @param other where to write received data to
- * @param i maximum size of other (in bytes)
- * @return number of bytes actually received
- */
-static ssize_t
-recv_tls_adapter (struct MHD_Connection *connection,
-                  void *other,
-                  size_t i)
-{
-  ssize_t res;
-
-  if (i > SSIZE_MAX)
-    i = SSIZE_MAX;
-
-  res = gnutls_record_recv (connection->tls_session,
-                            other,
-                            i);
-  if ( (GNUTLS_E_AGAIN == res) ||
-       (GNUTLS_E_INTERRUPTED == res) )
-    {
-      MHD_socket_set_error_ (MHD_SCKT_EINTR_);
-#ifdef EPOLL_SUPPORT
-      if (GNUTLS_E_AGAIN == res)
-        connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
-#endif
-      return -1;
-    }
-  if (res < 0)
-    {
-      /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
-	 disrupted); set errno to something caller will interpret
-	 correctly as a hard error */
-      MHD_socket_set_error_ (MHD_SCKT_ECONNRESET_);
-      connection->tls_read_ready = false;
-      return res;
-    }
-
-#ifdef EPOLL_SUPPORT
-  /* If data not available to fill whole buffer - socket is not read ready anymore. */
-  if (i > (size_t)res)
-    connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
-#endif /* EPOLL_SUPPORT */
-
-  /* Check whether TLS buffers still have some unread data. */
-  connection->tls_read_ready = ( ((size_t)res == i) &&
-                                 (0 != gnutls_record_check_pending (connection->tls_session)) );
-  return res;
-}
-
-
-/**
- * Callback for writing data to the socket.
- *
- * @param connection the MHD connection structure
- * @param other data to write
- * @param i number of bytes to write
- * @return actual number of bytes written
- */
-static ssize_t
-send_tls_adapter (struct MHD_Connection *connection,
-                  const void *other,
-                  size_t i)
-{
-  ssize_t res;
-
-  if (i > SSIZE_MAX)
-    i = SSIZE_MAX;
-
-  res = gnutls_record_send (connection->tls_session,
-                            other,
-                            i);
-  if ( (GNUTLS_E_AGAIN == res) ||
-       (GNUTLS_E_INTERRUPTED == res) )
-    {
-      MHD_socket_set_error_ (MHD_SCKT_EINTR_);
-#ifdef EPOLL_SUPPORT
-      if (GNUTLS_E_AGAIN == res)
-        connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
-#endif
-      return -1;
-    }
-  if (res < 0)
-    {
-      /* some other GNUTLS error, should set 'errno'; as we do not
-         really understand the error (not listed in GnuTLS
-         documentation explicitly), we set 'errno' to something that
-         will cause the connection to fail. */
-      MHD_socket_set_error_ (MHD_SCKT_ECONNRESET_);
-      return -1;
-    }
-#ifdef EPOLL_SUPPORT
-  /* If NOT all available data was sent - socket is not write ready anymore. */
-  if (i > (size_t)res)
-    connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
-#endif /* EPOLL_SUPPORT */
-  return res;
-}
-
-
 /**
  * Read and setup our certificate and key.
  *
@@ -2139,168 +2036,6 @@ exit:
 }
 
 
-/**
- * Callback for receiving data from the socket.
- *
- * @param connection the MHD connection structure
- * @param other where to write received data to
- * @param i maximum size of other (in bytes)
- * @return number of bytes actually received
- */
-static ssize_t
-recv_param_adapter (struct MHD_Connection *connection,
-		    void *other,
-		    size_t i)
-{
-  ssize_t ret;
-
-  if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
-       (MHD_CONNECTION_CLOSED == connection->state) )
-    {
-      MHD_socket_set_error_ (MHD_SCKT_ENOTCONN_);
-      return -1;
-    }
-  if (i > MHD_SCKT_SEND_MAX_SIZE_)
-    i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */
-
-  ret = MHD_recv_ (connection->socket_fd,
-                   other,
-                   i);
-#ifdef EPOLL_SUPPORT
-  if (0 > ret)
-    {
-      /* Got EAGAIN --- no longer read-ready */
-      if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()))
-        connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
-    }
-  else if (i > (size_t)ret)
-    connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
-#endif
-  return ret;
-}
-
-
-/**
- * Callback for writing data to the socket.
- *
- * @param connection the MHD connection structure
- * @param other data to write
- * @param i number of bytes to write
- * @return actual number of bytes written
- */
-static ssize_t
-send_param_adapter (struct MHD_Connection *connection,
-                    const void *other,
-		    size_t i)
-{
-  ssize_t ret;
-  int err;
-
-  if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
-       (MHD_CONNECTION_CLOSED == connection->state) )
-    {
-      MHD_socket_set_error_ (MHD_SCKT_ENOTCONN_);
-      return -1;
-    }
-  if (i > MHD_SCKT_SEND_MAX_SIZE_)
-    i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */
-
-#if LINUX
-  if ( (connection->write_buffer_append_offset ==
-	connection->write_buffer_send_offset) &&
-       (NULL != connection->response) &&
-       (MHD_resp_sender_sendfile == connection->resp_sender) )
-    {
-      /* can use sendfile */
-      int file_fd = connection->response->fd;
-      uint64_t left;
-      uint64_t offsetu64;
-#ifndef HAVE_SENDFILE64
-      off_t offset;
-#else  /* HAVE_SENDFILE64 */
-      off64_t offset;
-#endif /* HAVE_SENDFILE64 */
-      offsetu64 = connection->response_write_position + connection->response->fd_off;
-      left = connection->response->total_size - connection->response_write_position;
-      ret = 0;
-#ifndef HAVE_SENDFILE64
-      if ((uint64_t)OFF_T_MAX < offsetu64)
-        MHD_socket_set_error_to_ENOMEM ();
-      else
-        {
-          offset = (off_t) offsetu64;
-          ret = sendfile (connection->socket_fd,
-                          file_fd,
-                          &offset,
-                          left);
-        }
-#else  /* HAVE_SENDFILE64 */
-      if ((uint64_t)OFF64_T_MAX < offsetu64)
-        MHD_socket_set_error_to_ENOMEM ();
-      else
-        {
-          offset = (off64_t) offsetu64;
-          ret = sendfile64 (connection->socket_fd,
-                            file_fd,
-                            &offset,
-                            left);
-        }
-#endif /* HAVE_SENDFILE64 */
-      if (0 < ret)
-        {
-          /* write successful */
-#ifdef EPOLL_SUPPORT
-          if (left > (uint64_t)ret)
-            connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
-#endif /* EPOLL_SUPPORT */
-          return ret;
-        }
-      err = MHD_socket_get_error_();
-#ifdef EPOLL_SUPPORT
-      if ( (0 > ret) && (MHD_SCKT_ERR_IS_EAGAIN_(err)) )
-        {
-          /* EAGAIN --- no longer write-ready */
-          connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
-        }
-#endif
-      if (MHD_SCKT_ERR_IS_EINTR_ (err) ||
-          MHD_SCKT_ERR_IS_EAGAIN_ (err))
-	return 0;
-      if (MHD_SCKT_ERR_IS_(err,
-                           MHD_SCKT_EBADF_))
-	return -1;
-      /* sendfile() failed with EINVAL if mmap()-like operations are not
-	 supported for FD or other 'unusual' errors occurred, so we should try
-	 to fall back to 'SEND'; see also this thread for info on
-	 odd libc/Linux behavior with sendfile:
-	 http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */
-      connection->resp_sender = MHD_resp_sender_std;
-    }
-#endif
-  ret = MHD_send_ (connection->socket_fd,
-                   other,
-                   i);
-  err = MHD_socket_get_error_();
-#ifdef EPOLL_SUPPORT
-  if (0 > ret)
-    {
-      /* EAGAIN --- no longer write-ready */
-      if (MHD_SCKT_ERR_IS_EAGAIN_(err))
-        connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
-    }
-  else if (i > (size_t)ret)
-    connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
-#endif
-  /* Handle broken kernel / libc, returning -1 but not setting errno;
-     kill connection as that should be safe; reported on mailinglist here:
-     http://lists.gnu.org/archive/html/libmicrohttpd/2014-10/msg00023.html */
-  if ( (0 > ret) &&
-       (0 == err) )
-    MHD_socket_set_error_ (MHD_SCKT_ECONNRESET_);
-  return ret;
-}
-
-
 /**
  * Free resources associated with all closed connections.
  * (destroy responses, free buffers, etc.).  All closed
@@ -2523,14 +2258,10 @@ internal_add_connection (struct MHD_Daemon *daemon,
     {
       /* set default connection handlers  */
       MHD_set_http_callbacks_ (connection);
-      connection->recv_cls = &recv_param_adapter;
-      connection->send_cls = &send_param_adapter;
     }
   else
     {
 #ifdef HTTPS_SUPPORT
-      connection->recv_cls = &recv_tls_adapter;
-      connection->send_cls = &send_tls_adapter;
       connection->state = MHD_TLS_CONNECTION_INIT;
       MHD_set_https_callbacks (connection);
       gnutls_init (&connection->tls_session,