Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 4a9976e

Browse files
committed
Bug 1310197 - Implement fast open nspr part. r=mcmanus,bagder
1 parent f513cbe commit 4a9976e

9 files changed

Lines changed: 403 additions & 1 deletion

File tree

build/moz.configure/init.configure

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,13 @@ set_config('HAVE_64BIT_BUILD', have_64_bit)
504504
set_define('HAVE_64BIT_BUILD', have_64_bit)
505505
add_old_configure_assignment('HAVE_64BIT_BUILD', have_64_bit)
506506

507+
@depends(host)
508+
def host_os_kernel_major_version(host):
509+
versions = host.raw_os.split('.')
510+
version = ''.join(x for x in versions[0] if x.isdigit())
511+
return version
512+
513+
set_config('HOST_MAJOR_VERSION', host_os_kernel_major_version)
507514

508515
# Autoconf needs these set
509516
@depends(host)

config/external/nspr/pr/moz.build

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ elif CONFIG['OS_TARGET'] in ('FreeBSD', 'OpenBSD', 'NetBSD'):
4040
SOURCES += ['/nsprpub/pr/src/md/unix/%s.c' % CONFIG['OS_TARGET'].lower()]
4141
elif CONFIG['OS_TARGET'] == 'Darwin':
4242
OS_LIBS += ['-framework CoreServices']
43+
if CONFIG['HOST_MAJOR_VERSION'] == '15':
44+
DEFINES.update(
45+
HAS_CONNECTX=True,
46+
)
4347
DEFINES.update(
4448
DARWIN=True,
4549
HAVE_BSD_FLOCK=True,

nsprpub/configure

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6560,6 +6560,11 @@ fi
65606560
65616561
$as_echo "#define HAVE_POINTER_LOCALTIME_R 1" >>confdefs.h
65626562
6563+
HOST_DARWIN_MAJOR=`echo "$build_os" | sed -E -e 's/^darwin([0-9]+).*$/\1/'`
6564+
if test "$HOST_DARWIN_MAJOR" -ge 15 ; then
6565+
$as_echo "#define HAS_CONNECTX 1" >>confdefs.h
6566+
fi
6567+
65636568
AS='$(CC) -x assembler-with-cpp'
65646569
CFLAGS="$CFLAGS -Wall -fno-common"
65656570
case "${target_cpu}" in

nsprpub/configure.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,6 +1384,11 @@ case "$target" in
13841384
AC_DEFINE(HAVE_BSD_FLOCK)
13851385
AC_DEFINE(HAVE_SOCKLEN_T)
13861386
AC_DEFINE(HAVE_POINTER_LOCALTIME_R)
1387+
changequote(,)
1388+
HOST_DARWIN_MAJOR=`echo "$build_os" | sed -E -e 's/^darwin([0-9]+).*$/\1/'`
1389+
changequote([,])
1390+
if test "$HOST_DARWIN_MAJOR" -ge 15 ; then
1391+
AC_DEFINE(HAS_CONNECTX)
13871392
AS='$(CC) -x assembler-with-cpp'
13881393
CFLAGS="$CFLAGS -Wall -fno-common"
13891394
case "${target_cpu}" in

nsprpub/pr/include/md/_win95.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@ extern void _MD_MakeNonblock(PRFileDesc *f);
290290
extern PRInt32 _MD_CloseSocket(PROsfd osfd);
291291
#define _MD_CLOSE_SOCKET _MD_CloseSocket
292292
#define _MD_SENDTO _PR_MD_SENDTO
293+
#ifdef _WIN64
294+
#define _MD_TCPSENDTO _PR_MD_TCPSENDTO
295+
#endif
293296
#define _MD_RECVFROM _PR_MD_RECVFROM
294297
#define _MD_SOCKETPAIR(s, type, proto, sv) -1
295298
#define _MD_GETSOCKNAME _PR_MD_GETSOCKNAME

nsprpub/pr/include/private/primpl.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,13 @@ extern PRInt32 _PR_MD_SENDTO(
12251225
const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout);
12261226
#define _PR_MD_SENDTO _MD_SENDTO
12271227

1228+
#if defined(_WIN64) && defined(WIN95)
1229+
extern PRInt32 _PR_MD_TCPSENDTO(
1230+
PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
1231+
const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout);
1232+
#define _PR_MD_TCPSENDTO _MD_TCPSENDTO
1233+
#endif
1234+
12281235
extern PRInt32 _PR_MD_SOCKETPAIR(int af, int type, int flags, PROsfd *osfd);
12291236
#define _PR_MD_SOCKETPAIR _MD_SOCKETPAIR
12301237

@@ -1747,6 +1754,18 @@ struct PRFilePrivate {
17471754
* requires knowing the address family of the
17481755
* socket, we save the address family here. */
17491756
#endif
1757+
1758+
#if defined(_WIN64)
1759+
/* This is necessary for TCP Fast Open. TCP Fast Open in windows must
1760+
* use ConnectEx function which uses OVERLAPPED. TCPSendTo will call
1761+
* ConnectEx to send fast open data. If ConnectEx returns
1762+
* ERROR_IO_PENDING we need to save OVERLAPPED structure and we will
1763+
* use it in ConnectContinue to get the final result of ConnectEx.
1764+
*/
1765+
PRBool alreadyConnected;
1766+
PRBool overlappedActive;
1767+
OVERLAPPED ol;
1768+
#endif
17501769
};
17511770

17521771
#ifdef _WIN64

nsprpub/pr/src/io/prsocket.c

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77

88
#include <string.h>
99

10+
#if defined(_WIN64)
11+
#ifndef SO_UPDATE_CONNECT_CONTEXT
12+
#define SO_UPDATE_CONNECT_CONTEXT 0x7010
13+
#endif
14+
#endif
15+
1016
/************************************************************************/
1117

1218
/* These two functions are only used in assertions. */
@@ -286,6 +292,48 @@ static PRStatus PR_CALLBACK SocketConnectContinue(
286292
}
287293
return PR_SUCCESS;
288294

295+
#elif defined(_WIN64)
296+
if ((out_flags & PR_POLL_WRITE) && fd->secret->alreadyConnected) {
297+
fd->secret->alreadyConnected = PR_FALSE;
298+
return PR_SUCCESS;
299+
}
300+
// TCP Fast Open on Windows must use ConnectEx, which uses overlapped
301+
// input/output.
302+
// To get result we need to use GetOverlappedResult.
303+
if (fd->secret->overlappedActive) {
304+
PR_ASSERT(fd->secret->nonblocking);
305+
PRInt32 rvSent;
306+
if (GetOverlappedResult(osfd, &fd->secret->ol, &rvSent, FALSE) == TRUE)
307+
{
308+
fd->secret->overlappedActive = FALSE;
309+
PR_LOG(_pr_io_lm, PR_LOG_MIN,
310+
("SocketConnectContinue GetOverlappedResult succeeded\n"));
311+
// When ConnectEx is used, all previously set socket options and
312+
// property are not enabled and to enable them
313+
// SO_UPDATE_CONNECT_CONTEXT option need to be set.
314+
if (setsockopt((SOCKET)osfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) != 0) {
315+
err = WSAGetLastError();
316+
PR_LOG(_pr_io_lm, PR_LOG_MIN,
317+
("SocketConnectContinue setting SO_UPDATE_CONNECT_CONTEXT failed %d\n", err));
318+
_PR_MD_MAP_SETSOCKOPT_ERROR(err);
319+
return PR_FAILURE;
320+
}
321+
return PR_SUCCESS;
322+
} else {
323+
err = WSAGetLastError();
324+
PR_LOG(_pr_io_lm, PR_LOG_MIN,
325+
("SocketConnectContinue GetOverlappedResult failed %d\n", err));
326+
if (err != ERROR_IO_PENDING) {
327+
_PR_MD_MAP_CONNECT_ERROR(err);
328+
fd->secret->overlappedActive = FALSE;
329+
return PR_FAILURE;
330+
} else {
331+
PR_SetError(PR_IN_PROGRESS_ERROR, 0);
332+
return PR_FAILURE;
333+
}
334+
}
335+
}
336+
289337
#elif defined(WIN32) || defined(WIN16)
290338

291339
if (out_flags & PR_POLL_EXCEPT) {
@@ -768,6 +816,56 @@ static PRInt32 PR_CALLBACK SocketSendTo(
768816
return count;
769817
}
770818

819+
#if defined(_WIN64) && defined(WIN95)
820+
static PRInt32 PR_CALLBACK SocketTCPSendTo(
821+
PRFileDesc *fd, const void *buf, PRInt32 amount,
822+
PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
823+
{
824+
PRInt32 temp, count;
825+
const PRNetAddr *addrp = addr;
826+
#if defined(_PR_INET6)
827+
PRNetAddr addrCopy;
828+
#endif
829+
PRThread *me = _PR_MD_CURRENT_THREAD();
830+
831+
if (_PR_PENDING_INTERRUPT(me)) {
832+
me->flags &= ~_PR_INTERRUPT;
833+
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
834+
return -1;
835+
}
836+
if (_PR_IO_PENDING(me)) {
837+
PR_SetError(PR_IO_PENDING_ERROR, 0);
838+
return -1;
839+
}
840+
841+
PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
842+
#if defined(_PR_INET6)
843+
if (addr->raw.family == PR_AF_INET6) {
844+
addrCopy = *addr;
845+
addrCopy.raw.family = AF_INET6;
846+
addrp = &addrCopy;
847+
}
848+
#endif
849+
850+
count = 0;
851+
while (amount > 0) {
852+
temp = _PR_MD_TCPSENDTO(fd, buf, amount, flags,
853+
addrp, PR_NETADDR_SIZE(addr), timeout);
854+
if (temp < 0) {
855+
count = -1;
856+
break;
857+
}
858+
count += temp;
859+
if (fd->secret->nonblocking) {
860+
break;
861+
}
862+
buf = (const void*) ((const char*)buf + temp);
863+
amount -= temp;
864+
}
865+
return count;
866+
}
867+
#endif
868+
771869
static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
772870
PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
773871
{
@@ -1066,6 +1164,14 @@ static PRInt16 PR_CALLBACK SocketPoll(
10661164
PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
10671165
{
10681166
*out_flags = 0;
1167+
#if defined(_WIN64)
1168+
if (in_flags & PR_POLL_WRITE) {
1169+
if (fd->secret->alreadyConnected) {
1170+
out_flags = PR_POLL_WRITE;
1171+
return PR_POLL_WRITE;
1172+
}
1173+
}
1174+
#endif
10691175
return in_flags;
10701176
} /* SocketPoll */
10711177

@@ -1090,7 +1196,11 @@ static PRIOMethods tcpMethods = {
10901196
SocketRecv,
10911197
SocketSend,
10921198
(PRRecvfromFN)_PR_InvalidInt,
1199+
#if defined(_WIN64) && defined(WIN95)
1200+
SocketTCPSendTo, // This is for fast open. We imitate Linux interface.
1201+
#else
10931202
(PRSendtoFN)_PR_InvalidInt,
1203+
#endif
10941204
SocketPoll,
10951205
SocketAcceptRead,
10961206
SocketTransmitFile,

0 commit comments

Comments
 (0)