2019-03-11 03:26:37 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
/* Win95 Sockets module
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "primpl.h"
|
|
|
|
|
|
|
|
#define READ_FD 1
|
|
|
|
#define WRITE_FD 2
|
|
|
|
#define CONNECT_FD 3
|
|
|
|
|
|
|
|
static PRInt32 socket_io_wait(
|
2020-03-12 10:40:28 -07:00
|
|
|
PROsfd osfd,
|
2019-03-11 03:26:37 -07:00
|
|
|
PRInt32 fd_type,
|
|
|
|
PRIntervalTime timeout);
|
|
|
|
|
|
|
|
|
|
|
|
/* --- SOCKET IO --------------------------------------------------------- */
|
|
|
|
|
|
|
|
static PRBool socketFixInet6RcvBuf = PR_FALSE;
|
|
|
|
|
|
|
|
void _PR_MD_InitSockets(void)
|
|
|
|
{
|
|
|
|
OSVERSIONINFO osvi;
|
|
|
|
|
|
|
|
memset(&osvi, 0, sizeof(osvi));
|
|
|
|
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
|
|
|
GetVersionEx(&osvi);
|
|
|
|
|
|
|
|
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
|
|
|
|
{
|
|
|
|
/* if Windows XP (32-bit) */
|
|
|
|
socketFixInet6RcvBuf = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _PR_MD_CleanupSockets(void)
|
|
|
|
{
|
|
|
|
socketFixInet6RcvBuf = PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PROsfd
|
|
|
|
_PR_MD_SOCKET(int af, int type, int flags)
|
|
|
|
{
|
|
|
|
SOCKET sock;
|
|
|
|
u_long one = 1;
|
|
|
|
|
|
|
|
sock = socket(af, type, flags);
|
|
|
|
|
2020-03-12 10:40:28 -07:00
|
|
|
if (sock == INVALID_SOCKET )
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
_PR_MD_MAP_SOCKET_ERROR(WSAGetLastError());
|
|
|
|
return (PROsfd)sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Make the socket Non-Blocking
|
|
|
|
*/
|
|
|
|
if (ioctlsocket( sock, FIONBIO, &one) != 0)
|
|
|
|
{
|
|
|
|
PR_SetError(PR_UNKNOWN_ERROR, WSAGetLastError());
|
|
|
|
closesocket(sock);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (af == AF_INET6 && socketFixInet6RcvBuf)
|
|
|
|
{
|
|
|
|
int bufsize;
|
|
|
|
int len = sizeof(bufsize);
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
/* Windows XP 32-bit returns an error on getpeername() for AF_INET6
|
|
|
|
* sockets if the receive buffer size is greater than 65535 before
|
|
|
|
* the connection is initiated. The default receive buffer size may
|
|
|
|
* be 128000 so fix it here to always be <= 65535. See bug 513659
|
|
|
|
* and IBM DB2 support technote "Receive/Send IPv6 Socket Size
|
|
|
|
* Problem in Windows XP SP2 & SP3".
|
|
|
|
*/
|
|
|
|
rv = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, &len);
|
|
|
|
if (rv == 0 && bufsize > 65535)
|
|
|
|
{
|
|
|
|
bufsize = 65535;
|
|
|
|
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (PROsfd)sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** _MD_CloseSocket() -- Close a socket
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
PRInt32
|
|
|
|
_MD_CloseSocket(PROsfd osfd)
|
|
|
|
{
|
|
|
|
PRInt32 rv;
|
|
|
|
|
|
|
|
rv = closesocket((SOCKET) osfd );
|
2020-03-12 10:40:28 -07:00
|
|
|
if (rv < 0) {
|
2019-03-11 03:26:37 -07:00
|
|
|
_PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
2019-03-11 03:26:37 -07:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
_MD_SocketAvailable(PRFileDesc *fd)
|
|
|
|
{
|
|
|
|
PRInt32 result;
|
|
|
|
|
|
|
|
if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) {
|
|
|
|
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
PROsfd _MD_Accept(
|
2020-03-12 10:40:28 -07:00
|
|
|
PRFileDesc *fd,
|
|
|
|
PRNetAddr *raddr,
|
2019-03-11 03:26:37 -07:00
|
|
|
PRUint32 *rlen,
|
|
|
|
PRIntervalTime timeout )
|
|
|
|
{
|
|
|
|
PROsfd osfd = fd->secret->md.osfd;
|
|
|
|
SOCKET sock;
|
|
|
|
PRInt32 rv, err;
|
|
|
|
|
2020-03-12 10:40:28 -07:00
|
|
|
while ((sock = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1)
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
err = WSAGetLastError();
|
|
|
|
if ((err == WSAEWOULDBLOCK) && (!fd->secret->nonblocking))
|
|
|
|
{
|
|
|
|
if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_PR_MD_MAP_ACCEPT_ERROR(err);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(sock);
|
|
|
|
} /* end _MD_accept() */
|
|
|
|
|
|
|
|
PRInt32
|
2020-03-12 10:40:28 -07:00
|
|
|
_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen,
|
2019-03-11 03:26:37 -07:00
|
|
|
PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
PROsfd osfd = fd->secret->md.osfd;
|
|
|
|
PRInt32 rv;
|
|
|
|
int err;
|
|
|
|
|
2020-03-12 10:40:28 -07:00
|
|
|
if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1)
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
err = WSAGetLastError();
|
|
|
|
if ((!fd->secret->nonblocking) && (err == WSAEWOULDBLOCK))
|
|
|
|
{
|
|
|
|
rv = socket_io_wait(osfd, CONNECT_FD, timeout);
|
|
|
|
if ( rv < 0 )
|
|
|
|
{
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PR_ASSERT(rv > 0);
|
|
|
|
/* it's connected */
|
|
|
|
return(0);
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
2019-03-11 03:26:37 -07:00
|
|
|
}
|
|
|
|
_PR_MD_MAP_CONNECT_ERROR(err);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
|
|
|
|
{
|
|
|
|
PRInt32 rv;
|
|
|
|
|
|
|
|
rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen);
|
|
|
|
|
|
|
|
if (rv == SOCKET_ERROR) {
|
|
|
|
_PR_MD_MAP_BIND_ERROR(WSAGetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
_PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog)
|
|
|
|
{
|
|
|
|
PRInt32 rv;
|
|
|
|
|
|
|
|
rv = listen(fd->secret->md.osfd, backlog);
|
|
|
|
|
|
|
|
if (rv == SOCKET_ERROR) {
|
|
|
|
_PR_MD_MAP_DEFAULT_ERROR(WSAGetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
2020-03-12 10:40:28 -07:00
|
|
|
_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
|
2019-03-11 03:26:37 -07:00
|
|
|
PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
PROsfd osfd = fd->secret->md.osfd;
|
|
|
|
PRInt32 rv, err;
|
|
|
|
int osflags;
|
|
|
|
|
|
|
|
if (0 == flags) {
|
|
|
|
osflags = 0;
|
|
|
|
} else {
|
|
|
|
PR_ASSERT(PR_MSG_PEEK == flags);
|
|
|
|
osflags = MSG_PEEK;
|
|
|
|
}
|
2020-03-12 10:40:28 -07:00
|
|
|
while ((rv = recv( osfd, buf, amount, osflags)) == -1)
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
2020-03-12 10:40:28 -07:00
|
|
|
if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
|
2019-03-11 03:26:37 -07:00
|
|
|
&& (!fd->secret->nonblocking))
|
|
|
|
{
|
|
|
|
rv = socket_io_wait(osfd, READ_FD, timeout);
|
|
|
|
if ( rv < 0 )
|
|
|
|
{
|
|
|
|
return -1;
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
_PR_MD_MAP_RECV_ERROR(err);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} /* end while() */
|
|
|
|
return(rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
|
|
|
|
PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
PROsfd osfd = fd->secret->md.osfd;
|
|
|
|
PRInt32 rv, err;
|
|
|
|
PRInt32 bytesSent = 0;
|
|
|
|
|
2020-03-12 10:40:28 -07:00
|
|
|
while(bytesSent < amount )
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
2020-03-12 10:40:28 -07:00
|
|
|
while ((rv = send( osfd, buf, amount, 0 )) == -1)
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
2020-03-12 10:40:28 -07:00
|
|
|
if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
|
2019-03-11 03:26:37 -07:00
|
|
|
&& (!fd->secret->nonblocking))
|
|
|
|
{
|
|
|
|
rv = socket_io_wait(osfd, WRITE_FD, timeout);
|
|
|
|
if ( rv < 0 )
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
|
|
|
else
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
_PR_MD_MAP_SEND_ERROR(err);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bytesSent += rv;
|
|
|
|
if (fd->secret->nonblocking)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2020-03-12 10:40:28 -07:00
|
|
|
if (bytesSent < amount)
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
rv = socket_io_wait(osfd, WRITE_FD, timeout);
|
|
|
|
if ( rv < 0 )
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bytesSent;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
_PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
|
|
|
|
const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
PROsfd osfd = fd->secret->md.osfd;
|
|
|
|
PRInt32 rv, err;
|
|
|
|
PRInt32 bytesSent = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
while ((rv = sendto( osfd, buf, amount, 0, (struct sockaddr *) addr,
|
2020-03-12 10:40:28 -07:00
|
|
|
addrlen)) == -1)
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
2020-03-12 10:40:28 -07:00
|
|
|
if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
|
2019-03-11 03:26:37 -07:00
|
|
|
&& (!fd->secret->nonblocking))
|
|
|
|
{
|
|
|
|
rv = socket_io_wait(osfd, WRITE_FD, timeout);
|
|
|
|
if ( rv < 0 )
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
|
|
|
else
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
_PR_MD_MAP_SENDTO_ERROR(err);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bytesSent += rv;
|
|
|
|
if (fd->secret->nonblocking)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2020-03-12 10:40:28 -07:00
|
|
|
if (bytesSent < amount)
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
rv = socket_io_wait(osfd, WRITE_FD, timeout);
|
2020-03-12 10:40:28 -07:00
|
|
|
if (rv < 0)
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while(bytesSent < amount);
|
|
|
|
return bytesSent;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(_WIN64)
|
|
|
|
|
|
|
|
static PRCallOnceType _pr_has_connectex_once;
|
|
|
|
typedef BOOL (PASCAL FAR * _pr_win_connectex_ptr)(_In_ SOCKET s, _In_reads_bytes_(namelen) const struct sockaddr FAR *name, _In_ int namelen, _In_reads_bytes_opt_(dwSendDataLength) PVOID lpSendBuffer, _In_ DWORD dwSendDataLength, _Out_ LPDWORD lpdwBytesSent, _Inout_ LPOVERLAPPED lpOverlapped);
|
|
|
|
|
|
|
|
#ifndef WSAID_CONNECTEX
|
|
|
|
#define WSAID_CONNECTEX \
|
|
|
|
{0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}
|
|
|
|
#endif
|
|
|
|
#ifndef SIO_GET_EXTENSION_FUNCTION_POINTER
|
|
|
|
#define SIO_GET_EXTENSION_FUNCTION_POINTER 0xC8000006
|
|
|
|
#endif
|
|
|
|
#ifndef TCP_FASTOPEN
|
|
|
|
#define TCP_FASTOPEN 15
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef SO_UPDATE_CONNECT_CONTEXT
|
|
|
|
#define SO_UPDATE_CONNECT_CONTEXT 0x7010
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static _pr_win_connectex_ptr _pr_win_connectex = NULL;
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK _pr_set_connectex(void)
|
|
|
|
{
|
|
|
|
_pr_win_connectex = NULL;
|
|
|
|
SOCKET sock;
|
|
|
|
PRInt32 dwBytes;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* Dummy socket needed for WSAIoctl */
|
|
|
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
2020-03-12 10:40:28 -07:00
|
|
|
if (sock == INVALID_SOCKET) {
|
2019-03-11 03:26:37 -07:00
|
|
|
return PR_SUCCESS;
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
2019-03-11 03:26:37 -07:00
|
|
|
|
|
|
|
GUID guid = WSAID_CONNECTEX;
|
|
|
|
rc = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
|
|
|
|
&guid, sizeof(guid),
|
|
|
|
&_pr_win_connectex, sizeof(_pr_win_connectex),
|
|
|
|
&dwBytes, NULL, NULL);
|
|
|
|
if (rc != 0) {
|
|
|
|
_pr_win_connectex = NULL;
|
|
|
|
return PR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = closesocket(sock);
|
|
|
|
return PR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
_PR_MD_TCPSENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
|
|
|
|
const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
if (!_fd_waiting_for_overlapped_done_lock) {
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PR_CallOnce(&_pr_has_connectex_once, _pr_set_connectex) != PR_SUCCESS) {
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_pr_win_connectex == NULL) {
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PROsfd osfd = fd->secret->md.osfd;
|
|
|
|
PRInt32 rv, err;
|
|
|
|
PRInt32 bytesSent = 0;
|
|
|
|
DWORD rvSent;
|
|
|
|
|
|
|
|
BOOL option = 1;
|
|
|
|
rv = setsockopt((SOCKET)osfd, IPPROTO_TCP, TCP_FASTOPEN, (char*)&option, sizeof(option));
|
|
|
|
if (rv != 0) {
|
|
|
|
err = WSAGetLastError();
|
|
|
|
PR_LOG(_pr_io_lm, PR_LOG_MIN,
|
|
|
|
("_PR_MD_TCPSENDTO error set opt TCP_FASTOPEN failed %d\n", err));
|
|
|
|
if (err == WSAENOPROTOOPT) {
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
} else {
|
|
|
|
_PR_MD_MAP_SETSOCKOPT_ERROR(err);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ConnectEx requires the socket to be initially bound. We will use INADDR_ANY. */
|
|
|
|
PRNetAddr bindAddr;
|
|
|
|
memset(&bindAddr, 0, sizeof(bindAddr));
|
|
|
|
bindAddr.raw.family = addr->raw.family;
|
|
|
|
|
|
|
|
rv = bind((SOCKET)osfd, (const struct sockaddr *)&(bindAddr.inet), PR_NETADDR_SIZE(&bindAddr));
|
|
|
|
if (rv != 0) {
|
|
|
|
err = WSAGetLastError();
|
|
|
|
PR_LOG(_pr_io_lm, PR_LOG_MIN,
|
|
|
|
("_PR_MD_TCPSENDTO error bind failed %d\n", err));
|
|
|
|
_PR_MD_MAP_SETSOCKOPT_ERROR(err);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_LOG(_pr_io_lm, PR_LOG_MIN,
|
|
|
|
("_PR_MD_TCPSENDTO calling _pr_win_connectex %d %p\n", amount, (char*)buf));
|
|
|
|
|
|
|
|
rvSent = 0;
|
|
|
|
memset(&fd->secret->ol, 0, sizeof(fd->secret->ol));
|
|
|
|
/* ConnectEx return TRUE on a success and FALSE on an error. */
|
|
|
|
if (_pr_win_connectex( (SOCKET)osfd, (struct sockaddr *) addr,
|
|
|
|
addrlen, buf, amount,
|
|
|
|
&rvSent, &fd->secret->ol) == TRUE) {
|
|
|
|
/* When ConnectEx is used, all previously set socket options and
|
|
|
|
* property are not enabled and to enable them
|
|
|
|
* SO_UPDATE_CONNECT_CONTEXT option need to be set. */
|
|
|
|
rv = setsockopt((SOCKET)osfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
|
|
|
|
if (rv != 0) {
|
|
|
|
err = WSAGetLastError();
|
|
|
|
PR_LOG(_pr_io_lm, PR_LOG_MIN,
|
2020-03-12 10:40:28 -07:00
|
|
|
("_PR_MD_TCPSENDTO setting SO_UPDATE_CONNECT_CONTEXT failed %d\n", err));
|
2019-03-11 03:26:37 -07:00
|
|
|
_PR_MD_MAP_SETSOCKOPT_ERROR(err);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* We imitate Linux here. SendTo will return number of bytes send but
|
|
|
|
* it can not return connection success at the same time, so we return
|
|
|
|
* number of bytes send and "connection success" will be return on the
|
|
|
|
* connectcontinue. */
|
|
|
|
fd->secret->alreadyConnected = PR_TRUE;
|
|
|
|
return rvSent;
|
|
|
|
} else {
|
|
|
|
err = WSAGetLastError();
|
|
|
|
PR_LOG(_pr_io_lm, PR_LOG_MIN,
|
|
|
|
("_PR_MD_TCPSENDTO error _pr_win_connectex failed %d\n", err));
|
|
|
|
if (err != ERROR_IO_PENDING) {
|
|
|
|
_PR_MD_MAP_CONNECT_ERROR(err);
|
|
|
|
return -1;
|
|
|
|
} else if (fd->secret->nonblocking) {
|
|
|
|
/* Remember that overlapped structure is set. We will need to get
|
|
|
|
* the final result of ConnectEx call. */
|
|
|
|
fd->secret->overlappedActive = PR_TRUE;
|
|
|
|
|
|
|
|
/* ConnectEx will copy supplied data to a internal buffer and send
|
|
|
|
* them during Fast Open or after connect. Therefore we can assumed
|
|
|
|
* this data already send. */
|
|
|
|
if (amount > 0) {
|
2020-03-12 10:40:28 -07:00
|
|
|
return amount;
|
2019-03-11 03:26:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
_PR_MD_MAP_CONNECT_ERROR(WSAEWOULDBLOCK);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
// err is ERROR_IO_PENDING and socket is blocking, so query
|
|
|
|
// GetOverlappedResult.
|
|
|
|
err = ERROR_IO_INCOMPLETE;
|
|
|
|
while (err == ERROR_IO_INCOMPLETE) {
|
|
|
|
rv = socket_io_wait(osfd, WRITE_FD, timeout);
|
|
|
|
if ( rv < 0 ) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
rv = GetOverlappedResult(osfd, &fd->secret->ol, &rvSent, FALSE);
|
|
|
|
if ( rv == TRUE ) {
|
|
|
|
return rvSent;
|
|
|
|
} else {
|
|
|
|
err = WSAGetLastError();
|
|
|
|
if (err != ERROR_IO_INCOMPLETE) {
|
|
|
|
_PR_MD_MAP_CONNECT_ERROR(err);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
|
|
|
|
PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
PROsfd osfd = fd->secret->md.osfd;
|
|
|
|
PRInt32 rv, err;
|
|
|
|
|
|
|
|
while ((rv = recvfrom( osfd, buf, amount, 0, (struct sockaddr *) addr,
|
2020-03-12 10:40:28 -07:00
|
|
|
addrlen)) == -1)
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
2020-03-12 10:40:28 -07:00
|
|
|
if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
|
2019-03-11 03:26:37 -07:00
|
|
|
&& (!fd->secret->nonblocking))
|
|
|
|
{
|
|
|
|
rv = socket_io_wait(osfd, READ_FD, timeout);
|
|
|
|
if ( rv < 0)
|
|
|
|
{
|
|
|
|
return -1;
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
_PR_MD_MAP_RECVFROM_ERROR(err);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
int index;
|
|
|
|
int sent = 0;
|
|
|
|
int rv;
|
|
|
|
|
2020-03-12 10:40:28 -07:00
|
|
|
for (index=0; index < iov_size; index++)
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout);
|
2020-03-12 10:40:28 -07:00
|
|
|
if (rv > 0) {
|
2019-03-11 03:26:37 -07:00
|
|
|
sent += rv;
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
|
|
|
if ( rv != iov[index].iov_len )
|
2019-03-11 03:26:37 -07:00
|
|
|
{
|
|
|
|
if (rv < 0)
|
|
|
|
{
|
|
|
|
if (fd->secret->nonblocking
|
|
|
|
&& (PR_GetError() == PR_WOULD_BLOCK_ERROR)
|
|
|
|
&& (sent > 0))
|
|
|
|
{
|
|
|
|
return sent;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Only a nonblocking socket can have partial sends */
|
|
|
|
PR_ASSERT(fd->secret->nonblocking);
|
|
|
|
return sent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sent;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
_PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
|
|
|
|
{
|
2020-03-12 10:40:28 -07:00
|
|
|
PRInt32 rv;
|
2019-03-11 03:26:37 -07:00
|
|
|
|
|
|
|
rv = shutdown(fd->secret->md.osfd, how);
|
2020-03-12 10:40:28 -07:00
|
|
|
if (rv < 0) {
|
2019-03-11 03:26:37 -07:00
|
|
|
_PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError());
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
2019-03-11 03:26:37 -07:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRStatus
|
|
|
|
_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
|
|
|
|
{
|
|
|
|
PRInt32 rv;
|
|
|
|
|
|
|
|
rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
|
|
|
|
if (rv==0) {
|
|
|
|
return PR_SUCCESS;
|
|
|
|
} else {
|
|
|
|
_PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError());
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRStatus
|
|
|
|
_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
|
|
|
|
{
|
|
|
|
PRInt32 rv;
|
|
|
|
|
|
|
|
rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
|
|
|
|
if (rv==0) {
|
|
|
|
return PR_SUCCESS;
|
|
|
|
} else {
|
|
|
|
_PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError());
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRStatus
|
|
|
|
_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
|
|
|
|
{
|
|
|
|
PRInt32 rv;
|
|
|
|
|
|
|
|
rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
|
|
|
|
if (rv==0) {
|
|
|
|
return PR_SUCCESS;
|
|
|
|
} else {
|
|
|
|
_PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRStatus
|
|
|
|
_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
|
|
|
|
{
|
|
|
|
PRInt32 rv;
|
|
|
|
|
|
|
|
rv = setsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
|
|
|
|
if (rv==0) {
|
|
|
|
return PR_SUCCESS;
|
|
|
|
} else {
|
|
|
|
_PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError());
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_MD_MakeNonblock(PRFileDesc *f)
|
|
|
|
{
|
|
|
|
return; /* do nothing */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* socket_io_wait --
|
|
|
|
*
|
|
|
|
* Wait for socket i/o, periodically checking for interrupt.
|
|
|
|
*
|
|
|
|
* This function returns 1 on success. On failure, it returns
|
|
|
|
* -1 and sets the error codes. It never returns 0.
|
|
|
|
*/
|
|
|
|
#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5
|
|
|
|
|
|
|
|
static PRInt32 socket_io_wait(
|
2020-03-12 10:40:28 -07:00
|
|
|
PROsfd osfd,
|
2019-03-11 03:26:37 -07:00
|
|
|
PRInt32 fd_type,
|
|
|
|
PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
PRInt32 rv = -1;
|
|
|
|
struct timeval tv;
|
|
|
|
PRThread *me = _PR_MD_CURRENT_THREAD();
|
|
|
|
PRIntervalTime elapsed, remaining;
|
|
|
|
PRBool wait_for_remaining;
|
|
|
|
fd_set rd_wr, ex;
|
|
|
|
int err, len;
|
|
|
|
|
|
|
|
switch (timeout) {
|
|
|
|
case PR_INTERVAL_NO_WAIT:
|
|
|
|
PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
|
|
|
|
break;
|
|
|
|
case PR_INTERVAL_NO_TIMEOUT:
|
|
|
|
/*
|
|
|
|
* This is a special case of the 'default' case below.
|
|
|
|
* Please see the comments there.
|
|
|
|
*/
|
|
|
|
tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
FD_ZERO(&rd_wr);
|
|
|
|
FD_ZERO(&ex);
|
|
|
|
do {
|
|
|
|
FD_SET(osfd, &rd_wr);
|
|
|
|
FD_SET(osfd, &ex);
|
|
|
|
switch( fd_type )
|
|
|
|
{
|
|
|
|
case READ_FD:
|
|
|
|
rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv);
|
|
|
|
break;
|
|
|
|
case WRITE_FD:
|
|
|
|
rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv);
|
|
|
|
break;
|
|
|
|
case CONNECT_FD:
|
|
|
|
rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
PR_ASSERT(0);
|
|
|
|
break;
|
|
|
|
} /* end switch() */
|
|
|
|
if (rv == -1 )
|
|
|
|
{
|
|
|
|
_PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( rv > 0 && fd_type == CONNECT_FD )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Call Sleep(0) to work around a Winsock timing bug.
|
|
|
|
*/
|
|
|
|
Sleep(0);
|
|
|
|
if (FD_ISSET((SOCKET)osfd, &ex))
|
|
|
|
{
|
|
|
|
len = sizeof(err);
|
|
|
|
if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
|
2020-03-12 10:40:28 -07:00
|
|
|
(char *) &err, &len) == SOCKET_ERROR)
|
|
|
|
{
|
2019-03-11 03:26:37 -07:00
|
|
|
_PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
2020-03-12 10:40:28 -07:00
|
|
|
if (err != 0) {
|
2019-03-11 03:26:37 -07:00
|
|
|
_PR_MD_MAP_CONNECT_ERROR(err);
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
|
|
|
else {
|
2019-03-11 03:26:37 -07:00
|
|
|
PR_SetError(PR_UNKNOWN_ERROR, 0);
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
2019-03-11 03:26:37 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (FD_ISSET((SOCKET)osfd, &rd_wr))
|
|
|
|
{
|
|
|
|
/* it's connected */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
PR_ASSERT(0);
|
|
|
|
}
|
|
|
|
if (_PR_PENDING_INTERRUPT(me)) {
|
|
|
|
me->flags &= ~_PR_INTERRUPT;
|
|
|
|
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
|
|
|
|
rv = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (rv == 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
remaining = timeout;
|
|
|
|
FD_ZERO(&rd_wr);
|
|
|
|
FD_ZERO(&ex);
|
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* We block in _MD_SELECT for at most
|
|
|
|
* _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
|
|
|
|
* so that there is an upper limit on the delay
|
|
|
|
* before the interrupt bit is checked.
|
|
|
|
*/
|
|
|
|
wait_for_remaining = PR_TRUE;
|
|
|
|
tv.tv_sec = PR_IntervalToSeconds(remaining);
|
|
|
|
if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
|
|
|
|
wait_for_remaining = PR_FALSE;
|
|
|
|
tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
} else {
|
|
|
|
tv.tv_usec = PR_IntervalToMicroseconds(
|
2020-03-12 10:40:28 -07:00
|
|
|
remaining -
|
|
|
|
PR_SecondsToInterval(tv.tv_sec));
|
2019-03-11 03:26:37 -07:00
|
|
|
}
|
|
|
|
FD_SET(osfd, &rd_wr);
|
|
|
|
FD_SET(osfd, &ex);
|
|
|
|
switch( fd_type )
|
|
|
|
{
|
|
|
|
case READ_FD:
|
|
|
|
rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv);
|
|
|
|
break;
|
|
|
|
case WRITE_FD:
|
|
|
|
rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv);
|
|
|
|
break;
|
|
|
|
case CONNECT_FD:
|
|
|
|
rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
PR_ASSERT(0);
|
|
|
|
break;
|
|
|
|
} /* end switch() */
|
|
|
|
if (rv == -1)
|
|
|
|
{
|
|
|
|
_PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( rv > 0 && fd_type == CONNECT_FD )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Call Sleep(0) to work around a Winsock timing bug.
|
|
|
|
*/
|
|
|
|
Sleep(0);
|
|
|
|
if (FD_ISSET((SOCKET)osfd, &ex))
|
|
|
|
{
|
|
|
|
len = sizeof(err);
|
|
|
|
if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
|
2020-03-12 10:40:28 -07:00
|
|
|
(char *) &err, &len) == SOCKET_ERROR)
|
|
|
|
{
|
2019-03-11 03:26:37 -07:00
|
|
|
_PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
2020-03-12 10:40:28 -07:00
|
|
|
if (err != 0) {
|
2019-03-11 03:26:37 -07:00
|
|
|
_PR_MD_MAP_CONNECT_ERROR(err);
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
|
|
|
else {
|
2019-03-11 03:26:37 -07:00
|
|
|
PR_SetError(PR_UNKNOWN_ERROR, 0);
|
2020-03-12 10:40:28 -07:00
|
|
|
}
|
2019-03-11 03:26:37 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (FD_ISSET((SOCKET)osfd, &rd_wr))
|
|
|
|
{
|
|
|
|
/* it's connected */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
PR_ASSERT(0);
|
|
|
|
}
|
|
|
|
if (_PR_PENDING_INTERRUPT(me)) {
|
|
|
|
me->flags &= ~_PR_INTERRUPT;
|
|
|
|
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
|
|
|
|
rv = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We loop again if _MD_SELECT timed out and the
|
|
|
|
* timeout deadline has not passed yet.
|
|
|
|
*/
|
|
|
|
if (rv == 0 )
|
|
|
|
{
|
|
|
|
if (wait_for_remaining) {
|
|
|
|
elapsed = remaining;
|
|
|
|
} else {
|
2020-03-12 10:40:28 -07:00
|
|
|
elapsed = PR_SecondsToInterval(tv.tv_sec)
|
|
|
|
+ PR_MicrosecondsToInterval(tv.tv_usec);
|
2019-03-11 03:26:37 -07:00
|
|
|
}
|
|
|
|
if (elapsed >= remaining) {
|
|
|
|
PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
|
|
|
|
rv = -1;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
remaining = remaining - elapsed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (rv == 0 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return(rv);
|
|
|
|
} /* end socket_io_wait() */
|