62
62
#if HAVE_SYS_FILIO_H
63
63
#include <sys/filio.h>
64
64
#endif
65
+ #if HAVE_LINUX_ERRQUEUE_H
66
+ #include <linux/errqueue.h>
67
+ #endif
68
+
65
69
66
70
#if HAVE_KQUEUE
67
71
#if KEVENT_HAS_VOID_UDATA
@@ -1325,7 +1329,11 @@ int32_t SystemNative_SetSendTimeout(intptr_t socket, int32_t millisecondsTimeout
1325
1329
1326
1330
static int8_t ConvertSocketFlagsPalToPlatform (int32_t palFlags , int * platformFlags )
1327
1331
{
1328
- const int32_t SupportedFlagsMask = SocketFlags_MSG_OOB | SocketFlags_MSG_PEEK | SocketFlags_MSG_DONTROUTE | SocketFlags_MSG_TRUNC | SocketFlags_MSG_CTRUNC ;
1332
+ const int32_t SupportedFlagsMask =
1333
+ #ifdef MSG_ERRQUEUE
1334
+ SocketFlags_MSG_ERRQUEUE |
1335
+ #endif
1336
+ SocketFlags_MSG_OOB | SocketFlags_MSG_PEEK | SocketFlags_MSG_DONTROUTE | SocketFlags_MSG_TRUNC | SocketFlags_MSG_CTRUNC | SocketFlags_MSG_DONTWAIT ;
1329
1337
1330
1338
if ((palFlags & ~SupportedFlagsMask ) != 0 )
1331
1339
{
@@ -1335,9 +1343,15 @@ static int8_t ConvertSocketFlagsPalToPlatform(int32_t palFlags, int* platformFla
1335
1343
* platformFlags = ((palFlags & SocketFlags_MSG_OOB ) == 0 ? 0 : MSG_OOB ) |
1336
1344
((palFlags & SocketFlags_MSG_PEEK ) == 0 ? 0 : MSG_PEEK ) |
1337
1345
((palFlags & SocketFlags_MSG_DONTROUTE ) == 0 ? 0 : MSG_DONTROUTE ) |
1346
+ ((palFlags & SocketFlags_MSG_DONTWAIT ) == 0 ? 0 : MSG_DONTWAIT ) |
1338
1347
((palFlags & SocketFlags_MSG_TRUNC ) == 0 ? 0 : MSG_TRUNC ) |
1339
1348
((palFlags & SocketFlags_MSG_CTRUNC ) == 0 ? 0 : MSG_CTRUNC );
1340
-
1349
+ #ifdef MSG_ERRQUEUE
1350
+ if ((palFlags & SocketFlags_MSG_ERRQUEUE ) != 0 )
1351
+ {
1352
+ * platformFlags |= MSG_ERRQUEUE ;
1353
+ }
1354
+ #endif
1341
1355
return true;
1342
1356
}
1343
1357
@@ -1381,6 +1395,51 @@ int32_t SystemNative_Receive(intptr_t socket, void* buffer, int32_t bufferLen, i
1381
1395
return SystemNative_ConvertErrorPlatformToPal (errno );
1382
1396
}
1383
1397
1398
+ int32_t SystemNative_ReceiveSocketError (intptr_t socket , MessageHeader * messageHeader )
1399
+ {
1400
+ int fd = ToFileDescriptor (socket );
1401
+ ssize_t res ;
1402
+
1403
+ #if HAVE_LINUX_ERRQUEUE_H
1404
+ char buffer [sizeof (struct sock_extended_err ) + sizeof (struct sockaddr_storage )];
1405
+ messageHeader -> ControlBufferLen = sizeof (buffer );
1406
+ messageHeader -> ControlBuffer = (void * )buffer ;
1407
+
1408
+ struct msghdr header ;
1409
+ ConvertMessageHeaderToMsghdr (& header , messageHeader , fd );
1410
+
1411
+ while ((res = recvmsg (fd , & header , SocketFlags_MSG_DONTWAIT | SocketFlags_MSG_ERRQUEUE )) < 0 && errno == EINTR );
1412
+
1413
+ struct cmsghdr * cmsg ;
1414
+ for (cmsg = CMSG_FIRSTHDR (& header ); cmsg ; cmsg = GET_CMSG_NXTHDR (& header , cmsg ))
1415
+ {
1416
+ if (cmsg -> cmsg_level == SOL_IP && cmsg -> cmsg_type == IP_RECVERR )
1417
+ {
1418
+ struct sock_extended_err * e = (struct sock_extended_err * )CMSG_DATA (cmsg );
1419
+ if (e -> ee_origin == SO_EE_ORIGIN_ICMP )
1420
+ {
1421
+ int size = (int )(cmsg -> cmsg_len - sizeof (struct sock_extended_err ));
1422
+ messageHeader -> SocketAddressLen = size < messageHeader -> SocketAddressLen ? size : messageHeader -> SocketAddressLen ;
1423
+ memcpy (messageHeader -> SocketAddress , (struct sockaddr_in * )(e + 1 ), (size_t )messageHeader -> SocketAddressLen );
1424
+ return Error_SUCCESS ;
1425
+ }
1426
+ }
1427
+ }
1428
+ #else
1429
+ res = -1 ;
1430
+ errno = ENOTSUP ;
1431
+ #endif
1432
+
1433
+ messageHeader -> SocketAddressLen = 0 ;
1434
+
1435
+ if (res != -1 )
1436
+ {
1437
+ return Error_SUCCESS ;
1438
+ }
1439
+
1440
+ return SystemNative_ConvertErrorPlatformToPal (errno );
1441
+ }
1442
+
1384
1443
int32_t SystemNative_ReceiveMessage (intptr_t socket , MessageHeader * messageHeader , int32_t flags , int64_t * received )
1385
1444
{
1386
1445
if (messageHeader == NULL || received == NULL || messageHeader -> SocketAddressLen < 0 ||
0 commit comments