]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
non-KTLS sendfile
authorFrantisek Krenzelok <krenzelok.frantisek@gmail.com>
Wed, 16 Feb 2022 10:23:36 +0000 (11:23 +0100)
committerFrantisek Krenzelok <krenzelok.frantisek@gmail.com>
Wed, 23 Feb 2022 13:28:22 +0000 (14:28 +0100)
Added: sendfile API functionality for non KTLS enabled builds.
Signed-off-by: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
lib/record.c

index 920a60f29a8434e2d1769d8c03046882b6b3cde3..08dd8e9aaa9c24f8adb15e277d93d25dc4311eef 100644 (file)
@@ -55,7 +55,7 @@
 #include <xsize.h>
 #include "locks.h"
 #include "system/ktls.h"
-#include <sys/sendfile.h>
+
 
 struct tls_record_st {
        uint16_t header_size;
@@ -2138,23 +2138,81 @@ ssize_t gnutls_record_send_early_data(gnutls_session_t session,
  * gnutls_record_send_file:
  * @session: is a #gnutls_session_t type.
  * @fd: file descriptor from which to read data.
- * @offset: position in file from which to start reading.
+ * @offset: Is relative to file offset, denotes the starting location for reading.
  *          after function returns, it point to position following
  *          last read byte.
- * @count: is the length of the data to be read from file and send.
+ * @count: is the length of the data in bytes to be read from file and send.
+ *
+ * This function sends data from @fd. If KTLS (kernel TLS) is enabled, it will use the
+ * sendfile() system call to avoid overhead of copying data between user space and the
+ * kernel. Otherwise, this functionality is only emulated by calling read() and
+ * gnutls_record_send() in a loop; thus it will not work in non-blocking mode. If this
+ * limitation matters, check whether KTLS is enabled using
+ * gnutls_transport_is_ktls_enabled().
  *
- * sends data via sendfile function.
+ * if @offset is NULL then file offset is incremented by number of bytes send, otherwise file offset
+ * remains unchanged.
  *
  * Returns: The number of bytes sent, or a negative error code.
  **/
 ssize_t gnutls_record_send_file(gnutls_session_t session, int fd,
                off_t *offset, size_t count)
 {
+       int ret;
+       size_t buf_len, data_to_send;
+       size_t send = 0;
+       uint8_t *buf;
+
        if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND)) {
                return _gnutls_ktls_send_file(session, fd, offset, count);
-       } else {
-               return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
        }
+
+       if (offset != NULL && lseek(fd, *offset, SEEK_CUR) == -1)
+                       return GNUTLS_E_FILE_ERROR;
+
+       buf_len = MIN(count, MAX(max_record_send_size(session, NULL), 512));
+
+       buf = malloc(buf_len);
+       if (buf == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+
+       while (send < count) {
+               if (count - send < buf_len)
+                       buf_len = count - send;
+
+               ret = read(fd, buf, buf_len);
+               if (ret == 0) //eof
+                       break;
+               else if (ret == -1){
+                       ret = GNUTLS_E_FILE_ERROR;
+                       goto end;
+               }
+
+               data_to_send = ret;
+               while (data_to_send > 0) {
+                       ret = gnutls_record_send(session, buf, data_to_send);
+                       if (ret < 0) {
+                               if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
+                                       continue;
+                               else
+                                       goto end;
+                       }
+                       data_to_send -= ret;
+               }
+               send += ret;
+       }
+       if (offset != NULL){
+               *offset += send;
+               lseek(fd, -(*offset), SEEK_CUR);
+       }
+
+       ret = send;
+
+  end:
+       free(buf);
+       return ret;
 }
 
 /**