📄 rvsocket.c
字号:
sin->sin_family = AF_INET;
sin->sin_port = htons(ipv4Addr->port);
sin->sin_addr.s_addr = RvAddressIpv4GetIp(ipv4Addr);
*socklen = sizeof(struct sockaddr_in);
/* We use htons and not our internal RvConvertHostToNetwork16() since Tru64
doesn't work properly otherwise */
}
}
break;
#if RV_SOCKET_HAS_IPV6
case RV_ADDRESS_TYPE_IPV6:
{
struct sockaddr_in6 *sin= (struct sockaddr_in6 *)sockaddr;
RvUint8 ip[16];
RvUint16 port;
RvUint32 flowInfo;
RvUint32 scopeId;
res = RvAddressGetIpv6(address, ip, &port, &flowInfo, &scopeId);
if (res == RV_OK)
{
memset((char *)sin, 0, sizeof(sin));
sin->sin6_family = AF_INET6;
memcpy(&(sin->sin6_addr), ip, sizeof(ip));
sin->sin6_scope_id = scopeId;
sin->sin6_flowinfo = flowInfo;
sin->sin6_port= htons(port);
}
}
break;
#endif /* RV_SOCKET_HAS_IPV6 */
default:
res = RvSocketErrorCode(RV_ERROR_BADPARAM);
break;
}
return res;
}
/********************************************************************************************
* RvSocketAddressToSockAddr
*
* purpose : Set the port inside a sockaddr struct to a specified port value
* input : sockaddr - Socket address to modify
* port - Port to set in address
* output : None
* return : RV_OK on success, other on failure
********************************************************************************************/
static RvStatus RvSocketSockAddrSetPort(
IN RV_SOCKADDR_PTR sockaddr,
IN RvUint port)
{
switch (sockaddr->sa_family)
{
case AF_INET:
{
RvUint16 port16 = (RvUint16)port;
struct sockaddr_in* sin = (struct sockaddr_in *)sockaddr;
sin->sin_port = htons(port16);
}
break;
#if RV_SOCKET_HAS_IPV6
case AF_INET6:
{
RvUint16 port16 = (RvUint16)port;
struct sockaddr_in6 *sin= (struct sockaddr_in6 *)sockaddr;
sin->sin6_port= htons(port16);
}
break;
#endif
default:
return RvSocketErrorCode(RV_ERROR_UNKNOWN);
}
return RV_OK;
}
/********************************************************************************************
*
* Public functions
*
********************************************************************************************/
RvStatus RvSocketInit(void)
{
RvStatus status;
RvUint16 endianTest = 1;
/* Make sure we've compiled this with the right endian */
#if (RV_ARCH_ENDIAN == RV_ARCH_LITTLE_ENDIAN)
if (endianTest == RvConvertHostToNetwork16(endianTest))
return RvSocketErrorCode(RV_ERROR_NOTSUPPORTED);
#elif (RV_ARCH_ENDIAN == RV_ARCH_BIG_ENDIAN)
if (endianTest != RvConvertHostToNetwork16(endianTest))
return RvSocketErrorCode(RV_ERROR_NOTSUPPORTED);
#endif
status = RvSocketSharerInit();
if (status != RV_OK)
return status;
status = RvLogSourceConstruct(RvLogGet(), &rvSocketLogSource, RV_LOG_LIBCODE_CCORE, "SOCKET", "Sockets interface");
if (status != RV_OK)
{
RvSocketSharerEnd();
return status;
}
#if (RV_SOCKET_TYPE == RV_SOCKET_NUCLEUS)
#define MAX_TIMERS_PER_THREAD 100
/* Create the default ephemeral port range for NUCLEUS */
status = RvPortRangeConstruct(&RvSocketPortRange, 49152, 65535);
/* timer initialization */
RvTimerInit();
status = RvTimerQueueConstruct(&timerQueue, RV_TIMER_QTYPE_FIXED, MAX_TIMERS_PER_THREAD, 0, 0, 0, 40, NULL);
RvMemoryAlloc(NULL, (void **)&nuConInfo, (RvSize_t)(sizeof(connectionInfo)*RvSelectGetMaxFileDescriptors()));
if (nuConInfo == NULL)
return RvSocketErrorCode(RV_ERROR_UNKNOWN);
memset(nuConInfo, 0, (RvSize_t)(sizeof(nuConInfo)*RvSelectGetMaxFileDescriptors()));
#elif (RV_SOCKET_TYPE == RV_SOCKET_BSD)
#if (RV_OS_TYPE != RV_OS_TYPE_WINCE) && (RV_OS_TYPE != RV_OS_TYPE_OSE)
/* Catch SIGPIPE signals and ignore them instead of core-dumping */
if (signal(SIGPIPE, RvSocketHandleSigPipe) == SIG_ERR)
status = RvSocketErrorCode(RV_ERROR_UNKNOWN);
#endif
#endif
if (status != RV_OK)
{
RvLogSourceDestruct(RvLogGet(), &rvSocketLogSource);
RvSocketSharerEnd();
}
return status;
}
RvStatus RvSocketEnd(void)
{
RvStatus status;
RvLogSourceDestruct(RvLogGet(), &rvSocketLogSource);
status = RvSocketSharerEnd();
#if (RV_SOCKET_TYPE == RV_SOCKET_NUCLEUS)
status = RvPortRangeDestruct(&RvSocketPortRange);
/* end timer module */
status = RvTimerQueueStop(&timerQueue);
RvMemoryFree(nuConInfo);
#endif
return status;
}
/* ================================================================ */
/* ==== General functions (used by both TCP and UDP protocols) ==== */
/* ================================================================ */
/********************************************************************************************
* RvSocketConstruct
*
* purpose : Allocate a new socket.
* input : sock - pointer to the socket info.
* addressType - IPv4 or IPv6.
* protocolType - TCP or UDP.
* output : None
* return : RV_OK on success, other on failure
********************************************************************************************/
RVCOREAPI
RvStatus RVCALLCONV RvSocketConstruct(
IN RvSocket* sock,
IN RvInt addressType,
IN RvSocketProtocol protocolType)
{
RvStatus res;
#if defined(RV_OTHERCHECK)
if ((protocolType != RvSocketProtocolUdp) && (protocolType != RvSocketProtocolTcp))
return RvSocketErrorCode(RV_ERROR_BADPARAM);
#endif
#if (RV_SOCKET_USE_SHARER == 1)
res = RvSocketSharerConstruct(sock, addressType, protocolType);
#else
res = RvSocketConstructHere(sock, addressType, protocolType);
#endif
RvLogDebug(&rvSocketLogSource, (&rvSocketLogSource,
"RvSocketConstruct(socket=%d,type=%d,protocol=%d)=%d", *sock, addressType, protocolType, res));
return res;
}
/********************************************************************************************
* RvSocketShutdown
*
* purpose : Shutdown a TCP socket. This function should be called before calling
* RvSocketDestruct() for TCP sockets.
* input : sock - Socket to shutdown
* cleanSocket - RV_TRUE if you want to clean the socket before shutting it down.
* this will try to receive from the socket some buffers.
* It is suggested to set this value to RV_TRUE.
* output : None
* return : RV_OK on success, other on failure
********************************************************************************************/
RVCOREAPI
RvStatus RVCALLCONV RvSocketShutdown(
IN RvSocket* sock,
IN RvBool cleanSocket)
{
RvSocket ourSocket;
RvStatus ret;
ret = RvSocketSharerShare(sock, &ourSocket);
if (ret != RV_OK)
return ret;
#if (RV_SOCKET_TYPE != RV_SOCKET_NUCLEUS)
if (shutdown(ourSocket, SD_SEND) < 0)
ret = RvSocketErrorCode(RV_ERROR_UNKNOWN);
RvSocketSharerClose(&ourSocket);
if (cleanSocket)
{
RvUint8 tmpBuffer[128];
RvInt safetyCounter = 10;
RvSize_t bytesReceived = 1;
ret = RV_OK;
/* Clean the socket as much as we can */
while ((safetyCounter > 0) && (ret == RV_OK) && (bytesReceived > 0))
{
ret = RvSocketReceiveBuffer(sock, tmpBuffer, sizeof(tmpBuffer), &bytesReceived, NULL);
safetyCounter--;
}
}
#else
if (nuConInfo[ourSocket].timer != NULL)
RvTimerCancel(nuConInfo[ourSocket].timer, RV_TIMER_CANCEL_NONBLOCKING);
if (nuConInfo[ourSocket].socketState == RvSocketState_Connecting)
NU_Abort(ourSocket);
if (nuConInfo[ourSocket].threadState == RvThreadState_Stopped)
RvSocketTaskClean(ourSocket);
nuConInfo[ourSocket].socketState = RvSocketState_Closing;
/* todo: Make sure the following if statement is ok */
if (nuConInfo[ourSocket].threadState == RvThreadState_Idle)
{
RvThreadConstruct(&(nuConInfo[ourSocket].threadId), RvSocketEventsTask, (void*)&ourSocket);
ret = RvThreadStart(&(nuConInfo[ourSocket].threadId));
if (ret>=0)
nuConInfo[ourSocket].threadState = RvThreadState_Running;
}
#endif /* (RV_SOCKET_TYPE != RV_SOCKET_NUCLEUS) */
RvLogDebug(&rvSocketLogSource, (&rvSocketLogSource,
"RvSocketShutdown(socket=%d,clean=%d)=%d", *sock, cleanSocket, ret));
return ret;
}
/********************************************************************************************
* RvSocketDestruct
*
* purpose : Close a socket.
* input : sock - Socket to shutdown
* cleanSocket - RV_TRUE if you want to clean the socket before shutting it down.
* this will try to receive from the socket some buffers.
* It is suggested to set this value to RV_TRUE for TCP sockets.
* It should be set to RV_FALSE for UDP sockets.
* portRange - Port range to return this socket's port to. If NULL, the
* socket's port will not be added to any port range object.
* output : None
* return : RV_OK on success, other on failure
********************************************************************************************/
RVCOREAPI
RvStatus RVCALLCONV RvSocketDestruct(
IN RvSocket* sock,
IN RvBool cleanSocket,
IN RvPortRange* portRange)
{
RvStatus res = RV_OK;
/* todo: add sharer */
#if (RV_SOCKET_TYPE == RV_SOCKET_NUCLEUS)
/* In NUCLEUS, we make sure to have a portRange. If none is supplied, we just use
the static one declared and used in this module. */
if (portRange == NULL)
portRange = &RvSocketPortRange;
#endif
if (portRange != NULL)
{
/* We should try and return this socket's port to the port-range object */
RvAddress localAddress;
RvUint16 port;
res = RvSocketErrorCode(RV_ERROR_UNKNOWN);
if (RvSocketGetLocalAddress(sock, &localAddress) == RV_OK)
{
port = RvAddressGetIpPort(&localAddress);
if (port > 0)
{
RvUint fromPort, toPort;
/* Make sure this one is within the range we're dealing with */
res = RvPortRangeGetRange(portRange, &fromPort, &toPort);
if (res == RV_OK)
{
/* Add this port to list of available ports */
res = RvPortRangeReleasePort(portRange, (RvUint)port);
}
}
}
}
#if (RV_SOCKET_TYPE != RV_SOCKET_NUCLEUS)
if (cleanSocket)
{
RvUint8 tmpBuffer[128];
RvInt safetyCounter = 10;
RvSize_t bytesReceived = 1;
RvStatus res = RV_OK;
/* Clean the socket as much as we can */
while ((safetyCounter > 0) && (res == RV_OK) && (bytesReceived > 0))
{
res = RvSocketReceiveBuffer(sock, tmpBuffer, sizeof(tmpBuffer), &bytesReceived, NULL);
safetyCounter--;
}
}
/* todo: RvSocketSharerDestruct */
if (RvSocketClose(*sock) < 0)
{
RvLogDebug(&rvSocketLogSource, (&rvSocketLogSource,
"RvSocketDestruct: Error closing socket=%d (%d)", *sock, RvSocketErrNo));
res = RvSocketErrorCode(RV_ERROR_UNKNOWN);
}
#else
RvSocketTaskClean(*sock);
if (nuConInfo[*sock].socketState != RvSocketState_Closed)
{
NU_Abort(*sock);
RvSocketClose(*sock);
nuConInfo[*sock].socketState = RvSocketState_Closed;
}
if (nuConInfo[*sock].timer != NULL)
{
RvTimerCancel(nuConInfo[*sock].timer, RV_TIMER_CANCEL_NONBLOCKING);
nuConInfo[*sock].timer = NULL;
}
memset(nuConInfo+*sock,0,sizeof(nuConInfo[*sock]));
#endif /* (RV_SOCKET_TYPE != RV_SOCKET_NUCLEUS) */
RvLogDebug(&rvSocketLogSource, (&rvSocketLogSource,
"RvSocketDestruct(socket=%d,clean=%d,range=0x%p)=%d", *sock, cleanSocket, portRange, res));
return res;
}
/********************************************************************************************
* RvSocketBind
*
* purpose : Bind a socket to a local address
* input : sock - Socket to bind
* address - Address to bind socket to
* portRange - Port range to use if address states an ANY port.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -