1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-14 19:57:17 +01:00
SqMod/module/Vendor/SimpleSocket/PassiveSocket.cpp
2020-04-27 10:25:29 +03:00

329 lines
12 KiB
C++

/*---------------------------------------------------------------------------*/
/* */
/* PassiveSocket.cpp - Passive Socket Implementation */
/* */
/* Author : Mark Carrier (mark@carrierlabs.com) */
/* */
/*---------------------------------------------------------------------------*/
/* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. The name "CarrierLabs" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* mark@carrierlabs.com.
*
* THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/
#include "PassiveSocket.h"
CPassiveSocket::CPassiveSocket(CSocketType nType) : CSimpleSocket(nType)
{
}
bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, uint16_t nPort)
{
bool bRetVal = false;
#ifdef _WIN32
ULONG inAddr;
#else
in_addr_t inAddr;
#endif
//--------------------------------------------------------------------------
// Set the following socket option SO_REUSEADDR. This will allow the file
// descriptor to be reused immediately after the socket is closed instead
// of setting in a TIMED_WAIT state.
//--------------------------------------------------------------------------
memset(&m_stMulticastGroup,0,sizeof(m_stMulticastGroup));
m_stMulticastGroup.sin_family = AF_INET;
m_stMulticastGroup.sin_port = htons(nPort);
//--------------------------------------------------------------------------
// If no IP Address (interface ethn) is supplied, or the loop back is
// specified then bind to any interface, else bind to specified interface.
//--------------------------------------------------------------------------
if ((pInterface == NULL) || (!strlen(pInterface)))
{
m_stMulticastGroup.sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
if ((inAddr = inet_addr(pInterface)) != INADDR_NONE)
{
m_stMulticastGroup.sin_addr.s_addr = inAddr;
}
}
//--------------------------------------------------------------------------
// Bind to the specified port
//--------------------------------------------------------------------------
if (bind(m_socket, (struct sockaddr *)&m_stMulticastGroup, sizeof(m_stMulticastGroup)) == 0)
{
//----------------------------------------------------------------------
// Join the multicast group
//----------------------------------------------------------------------
m_stMulticastRequest.imr_multiaddr.s_addr = inet_addr(pGroup);
m_stMulticastRequest.imr_interface.s_addr = m_stMulticastGroup.sin_addr.s_addr;
if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(void *)&m_stMulticastRequest,
sizeof(m_stMulticastRequest)) == CSimpleSocket::SocketSuccess)
{
bRetVal = true;
}
m_timer.SetEndTime();
}
m_timer.Initialize();
m_timer.SetStartTime();
//--------------------------------------------------------------------------
// If there was a socket error then close the socket to clean out the
// connection in the backlog.
//--------------------------------------------------------------------------
TranslateSocketError();
if (bRetVal == false)
{
Close();
}
return bRetVal;
}
//------------------------------------------------------------------------------
//
// Listen() -
//
//------------------------------------------------------------------------------
bool CPassiveSocket::Listen(const char *pAddr, uint16_t nPort, int32_t nConnectionBacklog)
{
bool bRetVal = false;
#ifdef _WIN32
ULONG inAddr;
#else
in_addr_t inAddr;
int32_t nReuse;
nReuse = IPTOS_LOWDELAY;
//--------------------------------------------------------------------------
// Set the following socket option SO_REUSEADDR. This will allow the file
// descriptor to be reused immediately after the socket is closed instead
// of setting in a TIMED_WAIT state.
//--------------------------------------------------------------------------
SETSOCKOPT(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&nReuse, sizeof(int32_t));
SETSOCKOPT(m_socket, IPPROTO_TCP, IP_TOS, &nReuse, sizeof(int32_t));
#endif
memset(&m_stServerSockaddr,0,sizeof(m_stServerSockaddr));
m_stServerSockaddr.sin_family = AF_INET;
m_stServerSockaddr.sin_port = htons(nPort);
//--------------------------------------------------------------------------
// If no IP Address (interface ethn) is supplied, or the loop back is
// specified then bind to any interface, else bind to specified interface.
//--------------------------------------------------------------------------
if ((pAddr == NULL) || (!strlen(pAddr)))
{
m_stServerSockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
if ((inAddr = inet_addr(pAddr)) != INADDR_NONE)
{
m_stServerSockaddr.sin_addr.s_addr = inAddr;
}
}
m_timer.Initialize();
m_timer.SetStartTime();
//--------------------------------------------------------------------------
// Bind to the specified port
//--------------------------------------------------------------------------
if (bind(m_socket, (struct sockaddr *)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError)
{
if (m_nSocketType == CSimpleSocket::SocketTypeTcp)
{
if (listen(m_socket, nConnectionBacklog) != CSimpleSocket::SocketError)
{
bRetVal = true;
}
}
else
{
bRetVal = true;
}
}
m_timer.SetEndTime();
//--------------------------------------------------------------------------
// If there was a socket error then close the socket to clean out the
// connection in the backlog.
//--------------------------------------------------------------------------
TranslateSocketError();
if (bRetVal == false)
{
CSocketError err = GetSocketError();
Close();
SetSocketError(err);
}
return bRetVal;
}
//------------------------------------------------------------------------------
//
// Accept() -
//
//------------------------------------------------------------------------------
CActiveSocket *CPassiveSocket::Accept()
{
uint32_t nSockLen;
CActiveSocket *pClientSocket = NULL;
SOCKET socket = CSimpleSocket::SocketError;
if (m_nSocketType != CSimpleSocket::SocketTypeTcp)
{
SetSocketError(CSimpleSocket::SocketProtocolError);
return pClientSocket;
}
pClientSocket = new CActiveSocket();
//--------------------------------------------------------------------------
// Wait for incoming connection.
//--------------------------------------------------------------------------
if (pClientSocket != NULL)
{
CSocketError socketErrno = SocketSuccess;
m_timer.Initialize();
m_timer.SetStartTime();
nSockLen = sizeof(m_stClientSockaddr);
do
{
errno = 0;
socket = accept(m_socket, (struct sockaddr *)&m_stClientSockaddr, (socklen_t *)&nSockLen);
if (socket != -1)
{
pClientSocket->SetSocketHandle(socket);
pClientSocket->TranslateSocketError();
socketErrno = pClientSocket->GetSocketError();
socklen_t nSockLen = sizeof(struct sockaddr);
//-------------------------------------------------------------
// Store client and server IP and port information for this
// connection.
//-------------------------------------------------------------
getpeername(m_socket, (struct sockaddr *)&pClientSocket->m_stClientSockaddr, &nSockLen);
memcpy((void *)&pClientSocket->m_stClientSockaddr, (void *)&m_stClientSockaddr, nSockLen);
memset(&pClientSocket->m_stServerSockaddr, 0, nSockLen);
getsockname(m_socket, (struct sockaddr *)&pClientSocket->m_stServerSockaddr, &nSockLen);
}
else
{
TranslateSocketError();
socketErrno = GetSocketError();
}
} while (socketErrno == CSimpleSocket::SocketInterrupted);
m_timer.SetEndTime();
if (socketErrno != CSimpleSocket::SocketSuccess)
{
delete pClientSocket;
pClientSocket = NULL;
}
}
return pClientSocket;
}
//------------------------------------------------------------------------------
//
// Send() - Send data on a valid socket
//
//------------------------------------------------------------------------------
int32_t CPassiveSocket::Send(const uint8_t *pBuf, size_t bytesToSend)
{
SetSocketError(SocketSuccess);
m_nBytesSent = 0;
switch(m_nSocketType)
{
case CSimpleSocket::SocketTypeUdp:
{
if (IsSocketValid())
{
if ((bytesToSend > 0) && (pBuf != NULL))
{
m_timer.Initialize();
m_timer.SetStartTime();
m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0,
(const sockaddr *)&m_stClientSockaddr,
sizeof(m_stClientSockaddr));
m_timer.SetEndTime();
if (m_nBytesSent == CSimpleSocket::SocketError)
{
TranslateSocketError();
}
}
}
break;
}
case CSimpleSocket::SocketTypeTcp:
CSimpleSocket::Send(pBuf, bytesToSend);
break;
default:
SetSocketError(SocketProtocolError);
break;
}
return m_nBytesSent;
}