Quellcode durchsuchen

sendfile needs to be trunkated to chunks <2GB even on 64 bit Linux

This limit has been found by experiment on an x86_64 GNU/Linux
(Ubuntu 15.04, Linux 3.19.0-21-generic) system.

See also #143
bel2125 vor 10 Jahren
Ursprung
Commit
31a9758c7d
1 geänderte Dateien mit 22 neuen und 8 gelöschten Zeilen
  1. 22 8
      src/civetweb.c

+ 22 - 8
src/civetweb.c

@@ -5246,18 +5246,32 @@ static void send_file_data(struct mg_connection *conn,
 	} else if (len > 0 && filep->fp != NULL) {
 /* file stored on disk */
 #if defined(LINUX)
-		/* TODO: Test sendfile for Linux */
+		/* TODO (high): Test sendfile for Linux */
 		if (conn->throttle == 0 && conn->ssl == 0) {
-			off_t offs = (off_t)offset;
-			ssize_t sent = sendfile(
-			    conn->client.sock, fileno(filep->fp), &offs, (size_t)len);
-			if (sent > 0) {
-				conn->num_bytes_sent += sent;
+			off_t sf_offs = (off_t)offset;
+			ssize_t sf_sent;
+			int sf_file = fileno(filep->fp);
+
+
+			do {
+				/* 2147479552 (0x7FFFF000) is a limit found by experiment on 64 bit Linux */
+				ssize_t sf_tosend = (size_t) ((len<0x7FFFF000) ? len : 0x7FFFF000);
+				sf_sent = sendfile(
+				    conn->client.sock, sf_file, &sf_offs, sf_tosend);
+				if (sf_sent>0) {
+					conn->num_bytes_sent += sf_sent;
+					len -= sf_sent;
+					offset += sf_sent;
+				}
+
+			} while ((len>0) && (sf_sent>=0));
+
+			if (sf_sent > 0) {
 				return; /* OK */
 			}
-			/* sent<0 means error --> try classic way */
+			/* sf_sent<0 means error, thus fall back to the classic way */
 			mg_cry(conn,
-			       "%s: sendfile() failed: %s (trying read/write)",
+			       "%s: sendfile() failed: %s (now trying read+write)",
 			       __func__,
 			       strerror(ERRNO));
 		}