summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDragana Damjanovic <dd.mozilla@gmail.com>2021-06-09 16:21:38 +0000
committerDragana Damjanovic <dd.mozilla@gmail.com>2021-06-09 16:21:38 +0000
commit1d4e53982bd859a32df415f4994cfb162bd730d7 (patch)
tree25be47b311ecf7831454debc8bf8757f5451584b
parent7d8d4535c0b843e647586df079a757894a048238 (diff)
downloadnspr-hg-1d4e53982bd859a32df415f4994cfb162bd730d7.tar.gz
Bug 1713681 - Add set/getsockopt for the don't-fragment option. r=kaie,bwc,valentin
Differential Revision: https://phabricator.services.mozilla.com/D116658
-rw-r--r--pr/include/prio.h2
-rw-r--r--pr/src/io/prmapopt.c82
-rw-r--r--pr/src/pthreads/ptio.c47
-rw-r--r--pr/tests/sockopt.c5
4 files changed, 134 insertions, 2 deletions
diff --git a/pr/include/prio.h b/pr/include/prio.h
index d5cff257..8b331a32 100644
--- a/pr/include/prio.h
+++ b/pr/include/prio.h
@@ -205,6 +205,7 @@ typedef enum PRSockOption
PR_SockOpt_Broadcast, /* enable broadcast */
PR_SockOpt_Reuseport, /* allow local address & port reuse on
* platforms that support it */
+ PR_SockOpt_DontFrag, /* Do not fragment flag */
PR_SockOpt_Last
} PRSockOption;
@@ -230,6 +231,7 @@ typedef struct PRSocketOptionData
PRBool reuse_addr; /* Allow local address reuse */
PRBool reuse_port; /* Allow local address & port reuse on
* platforms that support it */
+ PRBool dont_fragment; /* Do not fragment flag */
PRBool keep_alive; /* Keep connections alive */
PRBool mcast_loopback; /* IP multicast loopback */
PRBool no_delay; /* Don't delay send to coalesce packets */
diff --git a/pr/src/io/prmapopt.c b/pr/src/io/prmapopt.c
index b6653e4b..375a73d2 100644
--- a/pr/src/io/prmapopt.c
+++ b/pr/src/io/prmapopt.c
@@ -33,6 +33,15 @@
#include "primpl.h"
+#if defined(LINUX) || defined(ANDROID)
+#include <netinet/in.h>
+#endif
+
+#ifdef DARWIN
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#endif
+
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
#endif
@@ -174,6 +183,28 @@ PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionDat
(char*)&data->value.mcast_if.inet.ip, &length);
break;
}
+ case PR_SockOpt_DontFrag:
+ {
+#if !defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)
+ PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
+ rv = PR_FAILURE;
+#else
+#ifdef WIN32 /* Winsock */
+ DWORD value;
+#else
+ PRIntn value;
+#endif
+ length = sizeof(value);
+ rv = _PR_MD_GETSOCKOPT(
+ fd, level, name, (char*)&value, &length);
+#if defined(WIN32) || defined(DARWIN)
+ data->value.dont_fragment = value;
+#else
+ data->value.dont_fragment = (value == IP_PMTUDISC_DO) ? 1 : 0;
+#endif
+#endif /* !(!defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)) */
+ break;
+ }
default:
PR_NOT_REACHED("Unknown socket option");
break;
@@ -306,6 +337,27 @@ PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOpt
sizeof(data->value.mcast_if.inet.ip));
break;
}
+ case PR_SockOpt_DontFrag:
+ {
+#if !defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)
+ PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
+ rv = PR_FAILURE;
+#else
+#if defined(WIN32) /* Winsock */
+ DWORD value;
+ value = (data->value.dont_fragment) ? 1 : 0;
+#elif defined(LINUX) || defined(ANDROID)
+ PRIntn value;
+ value = (data->value.dont_fragment) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
+#elif defined(DARWIN)
+ PRIntn value;
+ value = data->value.dont_fragment;
+#endif
+ rv = _PR_MD_SETSOCKOPT(
+ fd, level, name, (char*)&value, sizeof(value));
+#endif /* !(!defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)) */
+ break;
+ }
default:
PR_NOT_REACHED("Unknown socket option");
break;
@@ -400,6 +452,23 @@ PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOpt
#define IP_TOS _PR_NO_SUCH_SOCKOPT
#endif
+/* set/get IP do not fragment */
+#if defined(WIN32)
+#ifndef IP_DONTFRAGMENT
+#define IP_DONTFRAGMENT _PR_NO_SUCH_SOCKOPT
+#endif
+
+#elif defined(LINUX) || defined(ANDROID)
+#ifndef IP_MTU_DISCOVER
+#define IP_MTU_DISCOVER _PR_NO_SUCH_SOCKOPT
+#endif
+
+#elif defined(DARWIN)
+#ifndef IP_DONTFRAG
+#define IP_DONTFRAG _PR_NO_SUCH_SOCKOPT
+#endif
+#endif
+
#ifndef TCP_NODELAY /* don't delay to coalesce data */
#define TCP_NODELAY _PR_NO_SUCH_SOCKOPT
#endif
@@ -424,14 +493,23 @@ PRStatus _PR_MapOptionName(
0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
- TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST, SO_REUSEPORT
+ TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST, SO_REUSEPORT,
+#if defined(WIN32)
+ IP_DONTFRAGMENT,
+#elif defined(LINUX) || defined(ANDROID)
+ IP_MTU_DISCOVER,
+#elif defined(DARWIN)
+ IP_DONTFRAG,
+#else
+ _PR_NO_SUCH_SOCKOPT,
+#endif
};
static PRInt32 socketLevels[PR_SockOpt_Last] =
{
0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
- IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET, SOL_SOCKET
+ IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET, SOL_SOCKET, IPPROTO_IP
};
if ((optname < PR_SockOpt_Linger)
diff --git a/pr/src/pthreads/ptio.c b/pr/src/pthreads/ptio.c
index 3ad2d80a..a2bc3e71 100644
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -155,6 +155,15 @@ static ssize_t (*pt_aix_sendfile_fptr)() = NULL;
#include "primpl.h"
+#if defined(LINUX) || defined(ANDROID)
+#include <netinet/in.h>
+#endif
+
+#ifdef DARWIN
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#endif
+
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
#endif
@@ -3146,6 +3155,25 @@ static PRStatus pt_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
|| (sizeof(data->value.mcast_if.inet.ip) == length));
break;
}
+ case PR_SockOpt_DontFrag:
+ {
+#if !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)
+ PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
+ rv = PR_FAILURE;
+#else
+ PRIntn value;
+ length = sizeof(value);
+ rv = getsockopt(
+ fd->secret->md.osfd, level, name, (char*)&value,
+ &length);
+#if defined(DARWIN)
+ data->value.dont_fragment = value;
+#else
+ data->value.dont_fragment = (value == IP_PMTUDISC_DO) ? 1 : 0;
+#endif
+#endif /* !(!defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)) */
+ break;
+ }
default:
PR_NOT_REACHED("Unknown socket option");
break;
@@ -3259,6 +3287,25 @@ static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *dat
sizeof(data->value.mcast_if.inet.ip));
break;
}
+ case PR_SockOpt_DontFrag:
+ {
+#if !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)
+ PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
+ rv = PR_FAILURE;
+#else
+ PRIntn value;
+#if defined(LINUX) || defined(ANDROID)
+ value = (data->value.dont_fragment) ? IP_PMTUDISC_DO
+ : IP_PMTUDISC_DONT;
+#elif defined(DARWIN)
+ value = data->value.dont_fragment;
+#endif
+ rv = setsockopt(
+ fd->secret->md.osfd, level, name, (char*)&value,
+ sizeof(value));
+#endif /* !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)) */
+ break;
+ }
default:
PR_NOT_REACHED("Unknown socket option");
break;
diff --git a/pr/tests/sockopt.c b/pr/tests/sockopt.c
index 540a19b9..d1a04451 100644
--- a/pr/tests/sockopt.c
+++ b/pr/tests/sockopt.c
@@ -61,6 +61,7 @@ int main(int argc, char **argv)
"PR_SockOpt_MaxSegment", /* maximum segment size */
"PR_SockOpt_Broadcast", /* Enable broadcast */
"PR_SockOpt_Reuseport", /* allow local address & port reuse */
+ "PR_SockOpt_DontFrag", /* do not fragment */
"PR_SockOpt_Last"
};
@@ -144,6 +145,10 @@ int main(int argc, char **argv)
data.value.reuse_port = PR_TRUE;
break;
#endif
+ case PR_SockOpt_DontFrag:
+ data.value.dont_fragment = PR_TRUE;
+ break;
+
default: continue;
}