📄 socket_win.c
字号:
/*=============================================================================
socket_win.c
===============================================================================
This is the implementation of TSocket for a Windows Winsock socket.
=============================================================================*/
#include "xmlrpc_config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <winsock.h>
#include "xmlrpc-c/util_int.h"
#include "mallocvar.h"
#include "trace.h"
#include "socket.h"
struct socketWin {
/*----------------------------------------------------------------------------
The properties/state of a TSocket unique to a Unix TSocket.
-----------------------------------------------------------------------------*/
SOCKET fd;
abyss_bool userSuppliedWinsock;
/* 'socket' was supplied by the user; it belongs to him */
};
void
SocketWinInit(abyss_bool * const succeededP) {
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 0);
err = WSAStartup(wVersionRequested, &wsaData);
*succeededP = (err == 0);
}
void
SocketWinTerm(void) {
WSACleanup();
}
static SocketDestroyImpl socketDestroy;
static SocketWriteImpl socketWrite;
static SocketReadImpl socketRead;
static SocketConnectImpl socketConnect;
static SocketBindImpl socketBind;
static SocketListenImpl socketListen;
static SocketAcceptImpl socketAccept;
static SocketErrorImpl socketError;
static SocketWaitImpl socketWait;
static SocketAvailableReadBytesImpl socketAvailableReadBytes;
static SocketGetPeerNameImpl socketGetPeerName;
static struct TSocketVtbl const vtbl = {
&socketDestroy,
&socketWrite,
&socketRead,
&socketConnect,
&socketBind,
&socketListen,
&socketAccept,
&socketError,
&socketWait,
&socketAvailableReadBytes,
&socketGetPeerName
};
void
SocketWinCreate(TSocket ** const socketPP) {
struct socketWin * socketWinP;
MALLOCVAR(socketWinP);
if (socketWinP) {
SOCKET rc;
rc = socket(AF_INET, SOCK_STREAM, 0);
if (rc < 0)
*socketPP = NULL;
else {
socketWinP->fd = rc;
socketWinP->userSuppliedWinsock = FALSE;
{
int32_t n = 1;
int rc;
rc = setsockopt(socketWinP->fd, SOL_SOCKET, SO_REUSEADDR,
(char*)&n, sizeof(n));
if (rc < 0)
*socketPP = NULL;
else
SocketCreate(&vtbl, socketWinP, socketPP);
}
if (!*socketPP)
closesocket(socketWinP->fd);
}
if (!*socketPP)
free(socketWinP);
} else
*socketPP = NULL;
}
void
SocketWinCreateWinsock(SOCKET const winsock,
TSocket ** const socketPP) {
struct socketWin * socketWinP;
MALLOCVAR(socketWinP);
if (socketWinP) {
socketWinP->fd = winsock;
socketWinP->userSuppliedWinsock = TRUE;
SocketCreate(&vtbl, socketWinP, socketPP);
if (!*socketPP)
free(socketWinP);
} else
*socketPP = NULL;
}
void
socketDestroy(TSocket * const socketP) {
struct socketWin * const socketWinP = socketP->implP;
if (!socketWinP->userSuppliedWinsock)
closesocket(socketWinP->fd);
free(socketWinP);
}
void
socketWrite(TSocket * const socketP,
const unsigned char * const buffer,
uint32_t const len,
abyss_bool * const failedP) {
struct socketWin * const socketWinP = socketP->implP;
size_t bytesLeft;
abyss_bool error;
assert(sizeof(size_t) >= sizeof(len));
for (bytesLeft = len, error = FALSE;
bytesLeft > 0 && !error;
) {
size_t const maxSend = (size_t)(-1) >> 1;
int rc;
rc = send(socketWinP->fd, &buffer[len-bytesLeft],
MIN(maxSend, bytesLeft), 0);
if (rc <= 0)
/* 0 means connection closed; < 0 means severe error */
error = TRUE;
else
bytesLeft -= rc;
}
*failedP = error;
}
uint32_t
socketRead(TSocket * const socketP,
char * const buffer,
uint32_t const len) {
struct socketWin * const socketWinP = socketP->implP;
int rc;
rc = recv(socketWinP->fd, buffer, len, 0);
return rc;
}
abyss_bool
socketConnect(TSocket * const socketP,
TIPAddr * const addrP,
uint16_t const portNumber) {
struct socketWin * const socketWinP = socketP->implP;
struct sockaddr_in name;
int rc;
name.sin_family = AF_INET;
name.sin_port = htons(portNumber);
name.sin_addr = *addrP;
rc = connect(socketWinP->fd, (struct sockaddr *)&name, sizeof(name));
return rc != -1;
}
abyss_bool
socketBind(TSocket * const socketP,
TIPAddr * const addrP,
uint16_t const portNumber) {
struct socketWin * const socketWinP = socketP->implP;
struct sockaddr_in name;
int rc;
name.sin_family = AF_INET;
name.sin_port = htons(portNumber);
if (addrP)
name.sin_addr = *addrP;
else
name.sin_addr.s_addr = INADDR_ANY;
rc = bind(socketWinP->fd, (struct sockaddr *)&name, sizeof(name));
return (rc != -1);
}
abyss_bool
socketListen(TSocket * const socketP,
uint32_t const backlog) {
struct socketWin * const socketWinP = socketP->implP;
int32_t const minus1 = -1;
int rc;
/* Disable the Nagle algorithm to make persistant connections faster */
setsockopt(socketWinP->fd, IPPROTO_TCP,TCP_NODELAY,
(const char *)&minus1, sizeof(minus1));
rc = listen(socketWinP->fd, backlog);
return (rc != -1);
}
static void
socketAccept(TSocket * const listenSocketP,
abyss_bool * const connectedP,
abyss_bool * const failedP,
TSocket ** const acceptedSocketPP,
TIPAddr * const ipAddrP) {
/*----------------------------------------------------------------------------
Accept a connection on the listening socket 'listenSocketP'. Return as
*acceptedSocketPP the socket for the accepted connection.
If no connection is waiting on 'listenSocketP', wait until one is.
If we receive a signal while waiting, return immediately.
Return *connectedP true iff we accepted a connection. Return
*failedP true iff we were unable to accept a connection for some
reason other than that we were interrupted. Return both false if
our wait for a connection was interrupted by a signal.
-----------------------------------------------------------------------------*/
struct socketWin * const listenSocketWinP = listenSocketP->implP;
abyss_bool connected, failed, interrupted;
connected = FALSE;
failed = FALSE;
interrupted = FALSE;
while (!connected && !failed && !interrupted) {
struct sockaddr_in sa;
socklen_t size = sizeof(sa);
int rc;
rc = accept(listenSocketWinP->fd, (struct sockaddr *)&sa, &size);
if (rc >= 0) {
SOCKET const acceptedWinsock = rc;
struct socketWin * acceptedSocketWinP;
MALLOCVAR(acceptedSocketWinP);
if (acceptedSocketWinP) {
acceptedSocketWinP->fd = acceptedWinsock;
acceptedSocketWinP->userSuppliedWinsock = FALSE;
SocketCreate(&vtbl, acceptedSocketWinP, acceptedSocketPP);
if (!*acceptedSocketPP)
failed = TRUE;
else {
connected = TRUE;
*ipAddrP = sa.sin_addr;
}
if (failed)
free(acceptedSocketWinP);
} else
failed = TRUE;
if (failed)
closesocket(acceptedWinsock);
} else if (socketError(NULL) == WSAEINTR)
interrupted = TRUE;
else
failed = TRUE;
}
*failedP = failed;
*connectedP = connected;
}
static uint32_t
socketWait(TSocket * const socketP,
abyss_bool const rd,
abyss_bool const wr,
uint32_t const timems) {
struct socketWin * const socketWinP = socketP->implP;
fd_set rfds, wfds;
TIMEVAL tv;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
if (rd)
FD_SET(socketWinP->fd, &rfds);
if (wr)
FD_SET(socketWinP->fd, &wfds);
tv.tv_sec = timems / 1000;
tv.tv_usec = timems % 1000;
for (;;) {
int rc;
rc = select(socketWinP->fd + 1, &rfds, &wfds, NULL,
(timems == TIME_INFINITE ? NULL : &tv));
switch(rc) {
case 0: /* time out */
return 0;
case -1: /* socket error */
if (socketError(NULL) == WSAEINTR)
break;
return 0;
default:
if (FD_ISSET(socketWinP->fd, &rfds))
return 1;
if (FD_ISSET(socketWinP->fd, &wfds))
return 2;
return 0;
}
}
}
static uint32_t
socketAvailableReadBytes(TSocket * const socketP) {
struct socketWin * const socketWinP = socketP->implP;
uint32_t x;
int rc;
rc = ioctlsocket(socketWinP->fd, FIONREAD, &x);
return rc == 0 ? x : 0;
}
static void
socketGetPeerName(TSocket * const socketP,
TIPAddr * const ipAddrP,
uint16_t * const portNumberP,
abyss_bool * const successP) {
struct socketWin * const socketWinP = socketP->implP;
socklen_t addrlen;
int rc;
struct sockaddr sockAddr;
addrlen = sizeof(sockAddr);
rc = getpeername(socketWinP->fd, &sockAddr, &addrlen);
if (rc < 0) {
TraceMsg("getpeername() failed. errno=%d (%s)",
errno, strerror(errno));
*successP = FALSE;
} else {
if (addrlen != sizeof(sockAddr)) {
TraceMsg("getpeername() returned a socket address of the wrong "
"size: %u. Expected %u", addrlen, sizeof(sockAddr));
*successP = FALSE;
} else {
if (sockAddr.sa_family != AF_INET) {
TraceMsg("Socket does not use the Inet (IP) address "
"family. Instead it uses family %d",
sockAddr.sa_family);
*successP = FALSE;
} else {
struct sockaddr_in * const sockAddrInP = (struct sockaddr_in *)
&sockAddr;
*ipAddrP = sockAddrInP->sin_addr;
*portNumberP = sockAddrInP->sin_port;
*successP = TRUE;
}
}
}
}
static uint32_t
socketError(TSocket * const socketP) {
return (uint32_t)WSAGetLastError();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -