@@ -696,6 +696,27 @@ void SocketImpl::sendUrgent(unsigned char data)
696
696
}
697
697
698
698
699
+
700
+
701
+ std::streamsize SocketImpl::sendFile (FileInputStream& fileInputStream, std::streamoff offset, std::streamsize count)
702
+ {
703
+ if (!getBlocking ()) throw NetException (" sendFile() not supported for non-blocking sockets" );
704
+
705
+ #ifdef POCO_HAVE_SENDFILE
706
+ if (secure ())
707
+ {
708
+ return sendFileBlockwise (fileInputStream, offset, count);
709
+ }
710
+ else
711
+ {
712
+ return sendFileNative (fileInputStream, offset, count);
713
+ }
714
+ #else
715
+ return sendFileBlockwise (fileInputStream, offset, count);
716
+ #endif
717
+ }
718
+
719
+
699
720
int SocketImpl::available ()
700
721
{
701
722
int result = 0 ;
@@ -1424,13 +1445,16 @@ void SocketImpl::error(int code, const std::string& arg)
1424
1445
throw IOException (NumberFormatter::format (code), arg, code);
1425
1446
}
1426
1447
}
1448
+
1449
+
1427
1450
#ifdef POCO_HAVE_SENDFILE
1428
1451
#ifdef POCO_OS_FAMILY_WINDOWS
1429
- Poco::Int64 SocketImpl::sendFile (FileInputStream &fileInputStream, Poco::UInt64 offset)
1452
+
1453
+
1454
+ std::streamsize SocketImpl::sendFileNative (FileInputStream& fileInputStream, std::streamoff offset, std::streamsize count)
1430
1455
{
1431
1456
FileIOS::NativeHandle fd = fileInputStream.nativeHandle ();
1432
- UInt64 fileSize = fileInputStream.size ();
1433
- std::streamoff sentSize = fileSize - offset;
1457
+ if (count == 0 ) count = fileInputStream.size () - offset;
1434
1458
LARGE_INTEGER offsetHelper;
1435
1459
offsetHelper.QuadPart = offset;
1436
1460
OVERLAPPED overlapped;
@@ -1441,57 +1465,75 @@ Poco::Int64 SocketImpl::sendFile(FileInputStream &fileInputStream, Poco::UInt64
1441
1465
if (overlapped.hEvent == nullptr )
1442
1466
{
1443
1467
int err = GetLastError ();
1444
- error (err, std::string ( " [sendfile error] " ) + Error::getMessage (err) );
1468
+ error (err);
1445
1469
}
1446
- bool result = TransmitFile (_sockfd, fd, sentSize , 0 , &overlapped, nullptr , 0 );
1470
+ bool result = TransmitFile (_sockfd, fd, count , 0 , &overlapped, nullptr , 0 );
1447
1471
if (!result)
1448
1472
{
1449
1473
int err = WSAGetLastError ();
1450
- if ((err != ERROR_IO_PENDING) && (WSAGetLastError () != WSA_IO_PENDING)) {
1474
+ if ((err != ERROR_IO_PENDING) && (WSAGetLastError () != WSA_IO_PENDING))
1475
+ {
1451
1476
CloseHandle (overlapped.hEvent );
1452
- error (err, std::string ( " [sendfile error] " ) + Error::getMessage (err) );
1477
+ error (err);
1453
1478
}
1454
1479
WaitForSingleObject (overlapped.hEvent , INFINITE);
1455
1480
}
1456
1481
CloseHandle (overlapped.hEvent );
1457
- return sentSize ;
1482
+ return count ;
1458
1483
}
1484
+
1485
+
1459
1486
#else
1460
- Int64 _sendfile (poco_socket_t sd, FileIOS::NativeHandle fd, UInt64 offset, std::streamoff sentSize)
1487
+
1488
+
1489
+ namespace
1461
1490
{
1462
- Int64 sent = 0 ;
1463
- #ifdef __USE_LARGEFILE64
1464
- sent = sendfile64 (sd, fd, (off64_t *)&offset, sentSize);
1465
- #else
1466
- #if POCO_OS == POCO_OS_LINUX && !defined(POCO_EMSCRIPTEN)
1467
- sent = sendfile (sd, fd, (off_t *)&offset, sentSize);
1468
- #elif POCO_OS == POCO_OS_MAC_OS_X
1469
- int result = sendfile (fd, sd, offset, &sentSize, nullptr , 0 );
1470
- if (result < 0 )
1471
- {
1472
- sent = -1 ;
1473
- }
1474
- else
1491
+ std::streamsize sendFileUnix (poco_socket_t sd, FileIOS::NativeHandle fd, std::streamsize offset, std::streamoff count)
1475
1492
{
1476
- sent = sentSize;
1477
- }
1478
- #else
1479
- throw Poco::NotImplementedException (" sendfile not implemented for this platform" );
1480
- #endif
1481
- #endif
1482
- if (errno == EAGAIN || errno == EWOULDBLOCK)
1483
- {
1484
- sent = 0 ;
1485
- }
1486
- return sent;
1493
+ Int64 sent = 0 ;
1494
+ #ifdef __USE_LARGEFILE64
1495
+ sent = sendfile64 (sd, fd, (off64_t *) &offset, count);
1496
+ #else
1497
+ #if POCO_OS == POCO_OS_LINUX && !defined(POCO_EMSCRIPTEN)
1498
+ sent = sendfile (sd, fd, (off_t *) &offset, count);
1499
+ #elif POCO_OS == POCO_OS_MAC_OS_X
1500
+ int result = sendfile (fd, sd, offset, &count, NULL , 0 );
1501
+ if (result < 0 )
1502
+ {
1503
+ sent = -1 ;
1504
+ }
1505
+ else
1506
+ {
1507
+ sent = count;
1508
+ }
1509
+ #elif POCO_OS == POCO_OS_FREE_BSD
1510
+ int result = sendfile (fd, sd, offset, &count, NULL , NULL , 0 );
1511
+ if (result < 0 )
1512
+ {
1513
+ sent = -1 ;
1514
+ }
1515
+ else
1516
+ {
1517
+ sent = count;
1518
+ }
1519
+ #else
1520
+ throw Poco::NotImplementedException (" sendfile not implemented for this platform" );
1521
+ #endif
1522
+ #endif
1523
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
1524
+ {
1525
+ sent = 0 ;
1526
+ }
1527
+ return sent;
1528
+ }
1487
1529
}
1488
1530
1489
- Int64 SocketImpl::sendFile (FileInputStream &fileInputStream, UInt64 offset)
1531
+
1532
+ std::streamsize SocketImpl::sendFileNative (FileInputStream& fileInputStream, std::streamoff offset, std::streamsize count)
1490
1533
{
1491
1534
FileIOS::NativeHandle fd = fileInputStream.nativeHandle ();
1492
- UInt64 fileSize = fileInputStream.size ();
1493
- std::streamoff sentSize = fileSize - offset;
1494
- Int64 sent = 0 ;
1535
+ if (count == 0 ) count = fileInputStream.size () - offset;
1536
+ std::streamsize sent = 0 ;
1495
1537
struct sigaction sa, old_sa;
1496
1538
sa.sa_handler = SIG_IGN;
1497
1539
sigemptyset (&sa.sa_mask );
@@ -1500,20 +1542,53 @@ Int64 SocketImpl::sendFile(FileInputStream &fileInputStream, UInt64 offset)
1500
1542
while (sent == 0 )
1501
1543
{
1502
1544
errno = 0 ;
1503
- sent = _sendfile (_sockfd, fd, offset, sentSize );
1545
+ sent = sendFileUnix (_sockfd, fd, offset, count );
1504
1546
if (sent < 0 )
1505
1547
{
1506
- error (errno, std::string ( " [sendfile error] " ) + Error::getMessage (errno) );
1548
+ error (errno);
1507
1549
}
1508
1550
}
1509
- if (old_sa.sa_handler == SIG_ERR)
1551
+ if (old_sa.sa_handler == SIG_ERR)
1510
1552
{
1511
1553
old_sa.sa_handler = SIG_DFL;
1512
1554
}
1513
1555
sigaction (SIGPIPE, &old_sa, nullptr );
1514
1556
return sent;
1515
1557
}
1558
+
1559
+
1516
1560
#endif // POCO_OS_FAMILY_WINDOWS
1517
1561
#endif // POCO_HAVE_SENDFILE
1518
1562
1563
+
1564
+ std::streamsize SocketImpl::sendFileBlockwise (FileInputStream& fileInputStream, std::streamoff offset, std::streamsize count)
1565
+ {
1566
+ fileInputStream.seekg (offset, std::ios_base::beg);
1567
+ Poco::Buffer<char > buffer (8192 );
1568
+ std::size_t bufferSize = buffer.size ();
1569
+ if (count > 0 && bufferSize > count) bufferSize = count;
1570
+
1571
+ std::streamsize len = 0 ;
1572
+ fileInputStream.read (buffer.begin (), bufferSize);
1573
+ std::streamsize n = fileInputStream.gcount ();
1574
+ while (n > 0 && (count == 0 || len < count))
1575
+ {
1576
+ len += n;
1577
+ sendBytes (buffer.begin (), n);
1578
+ if (count > 0 && len < count)
1579
+ {
1580
+ const std::size_t remaining = count - len;
1581
+ if (bufferSize > remaining) bufferSize = remaining;
1582
+ }
1583
+ if (fileInputStream)
1584
+ {
1585
+ fileInputStream.read (buffer.begin (), bufferSize);
1586
+ n = fileInputStream.gcount ();
1587
+ }
1588
+ else n = 0 ;
1589
+ }
1590
+ return len;
1591
+ }
1592
+
1593
+
1519
1594
} } // namespace Poco::Net
0 commit comments