mirror of
https://github.com/dashr9230/SA-MP.git
synced 2025-09-19 20:26:14 +08:00
Revert RakNet source files back to the original v2.518 state
* Add RakNet source files to the VS project
This commit is contained in:
@ -1,17 +1,267 @@
|
||||
// TODO: Implement TCPInterface.cpp
|
||||
/// \file
|
||||
/// \brief A simple TCP based server allowing sends and receives. Can be connected to by a telnet client.
|
||||
///
|
||||
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
|
||||
///
|
||||
/// Usage of RakNet is subject to the appropriate license agreement.
|
||||
/// Creative Commons Licensees are subject to the
|
||||
/// license found at
|
||||
/// http://creativecommons.org/licenses/by-nc/2.5/
|
||||
/// Single application licensees are subject to the license found at
|
||||
/// http://www.rakkarsoft.com/SingleApplicationLicense.html
|
||||
/// Custom license users are subject to the terms therein.
|
||||
/// GPL license users are subject to the GNU General Public
|
||||
/// License as published by the Free
|
||||
/// Software Foundation; either version 2 of the License, or (at your
|
||||
/// option) any later version.
|
||||
|
||||
#include "TCPInterface.h"
|
||||
#ifdef _WIN32
|
||||
//#include <Shlwapi.h>
|
||||
#include <process.h>
|
||||
#else
|
||||
#ifdef _COMPATIBILITY_2
|
||||
#include "Compatibility2Includes.h"
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#define closesocket close
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
unsigned __stdcall UpdateTCPInterfaceLoop( LPVOID arguments );
|
||||
#else
|
||||
#define closesocket close
|
||||
void* UpdateTCPInterfaceLoop( void* arguments );
|
||||
#endif
|
||||
|
||||
#include "RakSleep.h"
|
||||
|
||||
#ifdef _DO_PRINTF
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( push )
|
||||
#endif
|
||||
|
||||
TCPInterface::TCPInterface()
|
||||
{
|
||||
}
|
||||
isStarted=false;
|
||||
threadRunning=false;
|
||||
listenSocket=(SOCKET)-1;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
WSADATA winsockInfo;
|
||||
if ( WSAStartup( MAKEWORD( 2, 2 ), &winsockInfo ) != 0 )
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_COMPATIBILITY_1) && defined(_DEBUG)
|
||||
DWORD dwIOError = GetLastError();
|
||||
LPVOID messageBuffer;
|
||||
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, dwIOError, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
|
||||
( LPTSTR ) & messageBuffer, 0, NULL );
|
||||
// something has gone wrong here...
|
||||
printf( "WSAStartup failed:Error code - %d\n%s", dwIOError, messageBuffer );
|
||||
//Free the buffer.
|
||||
LocalFree( messageBuffer );
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
TCPInterface::~TCPInterface()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
bool TCPInterface::Start(unsigned short port, unsigned short maxIncomingConnections)
|
||||
{
|
||||
if (isStarted)
|
||||
return false;
|
||||
|
||||
isStarted=true;
|
||||
|
||||
if (maxIncomingConnections>0)
|
||||
{
|
||||
listenSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if ((int)listenSocket <0)
|
||||
return false;
|
||||
|
||||
struct sockaddr_in serverAddress;
|
||||
serverAddress.sin_family = AF_INET;
|
||||
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
serverAddress.sin_port = htons(port);
|
||||
|
||||
if (bind(listenSocket,(struct sockaddr *) &serverAddress,sizeof(serverAddress)) < 0)
|
||||
return false;
|
||||
|
||||
listen(listenSocket, maxIncomingConnections);
|
||||
}
|
||||
|
||||
// Start the update thread
|
||||
#ifdef _WIN32
|
||||
unsigned threadId = 0;
|
||||
threadHandle = ( HANDLE ) _beginthreadex( NULL, 0, UpdateTCPInterfaceLoop, this, 0, &threadId );
|
||||
|
||||
//SetThreadPriority(threadHandle, THREAD_PRIORITY_BELOW_NORMAL);
|
||||
|
||||
if ( threadHandle == 0 )
|
||||
return false;
|
||||
CloseHandle( threadHandle );
|
||||
threadHandle = 0;
|
||||
#else
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init( &attr );
|
||||
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
|
||||
|
||||
// sched_param sp;
|
||||
// sp.sched_priority = sched_get_priority_min(SCHED_OTHER);
|
||||
// pthread_attr_setschedparam(&attr, &sp);
|
||||
|
||||
int error;
|
||||
error = pthread_create( &threadHandle, &attr, &UpdateTCPInterfaceLoop, this );
|
||||
if ( error )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
void TCPInterface::Stop(void)
|
||||
{
|
||||
if (isStarted==false)
|
||||
return;
|
||||
|
||||
isStarted=false;
|
||||
|
||||
if (listenSocket!=(SOCKET)-1)
|
||||
{
|
||||
closesocket(listenSocket);
|
||||
listenSocket=(SOCKET)-1;
|
||||
}
|
||||
|
||||
// Wait for the thread to stop
|
||||
while ( threadRunning )
|
||||
RakSleep(15);
|
||||
|
||||
// Stuff from here on to the end of the function is not threadsafe
|
||||
unsigned i;
|
||||
for (i=0; i < remoteClients.Size(); i++)
|
||||
{
|
||||
closesocket(remoteClients[i]->socket);
|
||||
delete remoteClients[i];
|
||||
}
|
||||
remoteClients.Clear();
|
||||
|
||||
outgoingMessages.Clear();
|
||||
incomingMessages.Clear();
|
||||
newConnections.Clear();
|
||||
newRemoteClients.Clear();
|
||||
lostConnections.Clear();
|
||||
requestedCloseConnections.Clear();
|
||||
}
|
||||
PlayerID TCPInterface::Connect(const char* host, unsigned short remotePort)
|
||||
{
|
||||
sockaddr_in serverAddress;
|
||||
|
||||
#if !defined(_COMPATIBILITY_1)
|
||||
struct hostent * server;
|
||||
server = gethostbyname(host);
|
||||
if (server == NULL)
|
||||
return UNASSIGNED_PLAYER_ID;
|
||||
#endif
|
||||
|
||||
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0)
|
||||
return UNASSIGNED_PLAYER_ID;
|
||||
|
||||
memset(&serverAddress, 0, sizeof(serverAddress));
|
||||
serverAddress.sin_family = AF_INET;
|
||||
serverAddress.sin_port = htons( remotePort );
|
||||
|
||||
|
||||
#if !defined(_COMPATIBILITY_1)
|
||||
memcpy((char *)&serverAddress.sin_addr.s_addr, (char *)server->h_addr, server->h_length);
|
||||
#else
|
||||
serverAddress.sin_addr.s_addr = inet_addr( host );
|
||||
#endif
|
||||
|
||||
// This is blocking but whatever. If I need it non-blocking I will make it so later.
|
||||
if ( connect( sockfd, ( struct sockaddr * ) &serverAddress, sizeof( struct sockaddr ) ) != 0 )
|
||||
{
|
||||
closesocket(sockfd);
|
||||
return UNASSIGNED_PLAYER_ID;
|
||||
}
|
||||
|
||||
waitForClient=true;
|
||||
RemoteClient *remoteClient;
|
||||
remoteClient = new RemoteClient;
|
||||
remoteClient->socket=sockfd;
|
||||
remoteClient->playerId.binaryAddress=inet_addr(host);
|
||||
remoteClient->playerId.port=remotePort;
|
||||
RemoteClient **temp = newRemoteClients.WriteLock();
|
||||
*temp=remoteClient;
|
||||
newRemoteClients.WriteUnlock();
|
||||
while (waitForClient);
|
||||
{
|
||||
RakSleep(30);
|
||||
}
|
||||
return remoteClient->playerId;
|
||||
}
|
||||
void TCPInterface::Send( const char *data, unsigned length, PlayerID playerId )
|
||||
{
|
||||
if (isStarted==false)
|
||||
return;
|
||||
if (remoteClients.Size()==0)
|
||||
return;
|
||||
if (data==0)
|
||||
return;
|
||||
Packet *p=outgoingMessages.WriteLock();
|
||||
p->length=length;
|
||||
p->data = new unsigned char [p->length];
|
||||
memcpy(p->data, data, p->length);
|
||||
p->playerId=playerId;
|
||||
outgoingMessages.WriteUnlock();
|
||||
}
|
||||
Packet* TCPInterface::Receive( void )
|
||||
{
|
||||
if (isStarted==false)
|
||||
return 0;
|
||||
return incomingMessages.ReadLock();
|
||||
}
|
||||
void TCPInterface::CloseConnection( PlayerID playerId )
|
||||
{
|
||||
if (isStarted==false)
|
||||
return;
|
||||
if (playerId==UNASSIGNED_PLAYER_ID)
|
||||
return;
|
||||
PlayerID *id = requestedCloseConnections.WriteLock();
|
||||
*id=playerId;
|
||||
requestedCloseConnections.WriteUnlock();
|
||||
}
|
||||
void TCPInterface::DeallocatePacket( Packet *packet )
|
||||
{
|
||||
assert(incomingMessages.CheckReadUnlockOrder(packet));
|
||||
delete [] packet->data;
|
||||
incomingMessages.ReadUnlock();
|
||||
}
|
||||
PlayerID TCPInterface::HasNewConnection(void)
|
||||
{
|
||||
PlayerID *out;
|
||||
out = newConnections.ReadLock();
|
||||
if (out)
|
||||
{
|
||||
newConnections.ReadUnlock();
|
||||
return *out;
|
||||
}
|
||||
else
|
||||
{
|
||||
return UNASSIGNED_PLAYER_ID;
|
||||
}
|
||||
}
|
||||
PlayerID TCPInterface::HasLostConnection(void)
|
||||
{
|
||||
PlayerID *out;
|
||||
@ -26,3 +276,240 @@ PlayerID TCPInterface::HasLostConnection(void)
|
||||
return UNASSIGNED_PLAYER_ID;
|
||||
}
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( disable : 4100 ) // warning C4100: <variable name> : unreferenced formal parameter
|
||||
#endif
|
||||
void TCPInterface::DeleteRemoteClient(RemoteClient *remoteClient, fd_set *exceptionFD)
|
||||
{
|
||||
// FD_CLR(remoteClient->socket, exceptionFD);
|
||||
closesocket(remoteClient->socket);
|
||||
//shutdown(remoteClient->socket, SD_SEND);
|
||||
delete remoteClient;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
unsigned __stdcall UpdateTCPInterfaceLoop( LPVOID arguments )
|
||||
#else
|
||||
void* UpdateTCPInterfaceLoop( void* arguments )
|
||||
#endif
|
||||
{
|
||||
TCPInterface * sts = ( TCPInterface * ) arguments;
|
||||
RemoteClient *remoteClient;
|
||||
RemoteClient **otherThreadClient;
|
||||
const int BUFF_SIZE=8096;
|
||||
char data[ BUFF_SIZE ];
|
||||
Packet *p;
|
||||
PlayerID *playerId;
|
||||
fd_set readFD, exceptionFD;
|
||||
sts->threadRunning=true;
|
||||
|
||||
sockaddr_in sockAddr;
|
||||
int sockAddrSize = sizeof(sockAddr);
|
||||
|
||||
unsigned i;
|
||||
int len;
|
||||
SOCKET newSock;
|
||||
timeval tv;
|
||||
int selectResult;
|
||||
tv.tv_sec=0;
|
||||
tv.tv_usec=25000;
|
||||
|
||||
while (sts->isStarted)
|
||||
{
|
||||
p=sts->outgoingMessages.ReadLock();
|
||||
while (p)
|
||||
{
|
||||
if (p->playerId==UNASSIGNED_PLAYER_ID)
|
||||
{
|
||||
// Send to all
|
||||
for (i=0; i < sts->remoteClients.Size(); i++)
|
||||
send(sts->remoteClients[i]->socket, (const char*)p->data, p->length, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Send to this player
|
||||
for (i=0; i < sts->remoteClients.Size(); i++)
|
||||
if (sts->remoteClients[i]->playerId==p->playerId )
|
||||
send(sts->remoteClients[i]->socket, (const char*)p->data, p->length, 0);
|
||||
}
|
||||
sts->outgoingMessages.ReadUnlock();
|
||||
p=sts->outgoingMessages.ReadLock();
|
||||
}
|
||||
|
||||
otherThreadClient=sts->newRemoteClients.ReadLock();
|
||||
if (otherThreadClient)
|
||||
{
|
||||
sts->remoteClients.Insert(*otherThreadClient);
|
||||
sts->newRemoteClients.ReadUnlock();
|
||||
sts->waitForClient=false;
|
||||
}
|
||||
|
||||
playerId=sts->requestedCloseConnections.ReadLock();
|
||||
if (playerId)
|
||||
{
|
||||
for (i=0; i < sts->remoteClients.Size(); i++)
|
||||
{
|
||||
if (sts->remoteClients[i]->playerId==*playerId )
|
||||
{
|
||||
playerId=sts->lostConnections.WriteLock();
|
||||
*playerId=sts->remoteClients[i]->playerId;
|
||||
sts->lostConnections.WriteUnlock();
|
||||
|
||||
sts->DeleteRemoteClient(sts->remoteClients[i], &exceptionFD);
|
||||
sts->remoteClients.RemoveAtIndex(i);
|
||||
|
||||
|
||||
/*
|
||||
playerId=sts->lostConnections.WriteLock();
|
||||
*playerId=sts->remoteClients[i]->playerId;
|
||||
sts->lostConnections.WriteUnlock();
|
||||
sts->remoteClients.Del(i);
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sts->requestedCloseConnections.ReadUnlock();
|
||||
}
|
||||
|
||||
// Reset readFD and exceptionFD since select seems to clear it
|
||||
FD_ZERO(&readFD);
|
||||
FD_ZERO(&exceptionFD);
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
|
||||
#endif
|
||||
if (sts->listenSocket!=(SOCKET)-1)
|
||||
{
|
||||
FD_SET(sts->listenSocket, &readFD);
|
||||
FD_SET(sts->listenSocket, &exceptionFD);
|
||||
}
|
||||
|
||||
for (i=0; i < sts->remoteClients.Size(); i++)
|
||||
{
|
||||
FD_SET(sts->remoteClients[i]->socket, &readFD);
|
||||
FD_SET(sts->remoteClients[i]->socket, &exceptionFD);
|
||||
}
|
||||
|
||||
selectResult=select(0, &readFD, 0, &exceptionFD, &tv);
|
||||
|
||||
if (selectResult > 0)
|
||||
{
|
||||
if (sts->listenSocket!=(SOCKET)-1 && FD_ISSET(sts->listenSocket, &readFD))
|
||||
{
|
||||
newSock = accept(sts->listenSocket, (sockaddr*)&sockAddr, (socklen_t*)&sockAddrSize);
|
||||
|
||||
if (newSock != INVALID_SOCKET)
|
||||
{
|
||||
remoteClient = new RemoteClient;
|
||||
remoteClient->socket=newSock;
|
||||
remoteClient->playerId.binaryAddress=sockAddr.sin_addr.s_addr;
|
||||
remoteClient->playerId.port=ntohs( sockAddr.sin_port);
|
||||
sts->remoteClients.Insert(remoteClient);
|
||||
playerId=sts->newConnections.WriteLock();
|
||||
*playerId=remoteClient->playerId;
|
||||
sts->newConnections.WriteUnlock();
|
||||
|
||||
FD_SET(newSock, &readFD);
|
||||
FD_SET(newSock, &exceptionFD);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _DO_PRINTF
|
||||
printf("Error: connection failed\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (sts->listenSocket!=(SOCKET)-1 && FD_ISSET(sts->listenSocket, &exceptionFD))
|
||||
{
|
||||
#ifdef _DO_PRINTF
|
||||
int err;
|
||||
int errlen = sizeof(err);
|
||||
getsockopt(sts->listenSocket, SOL_SOCKET, SO_ERROR,(char*)&err, &errlen);
|
||||
printf("Socket error %s on listening socket\n", err);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
i=0;
|
||||
while (i < sts->remoteClients.Size())
|
||||
{
|
||||
if (FD_ISSET(sts->remoteClients[i]->socket, &exceptionFD))
|
||||
{
|
||||
#ifdef _DO_PRINTF
|
||||
if (sts->listenSocket!=(SOCKET)-1)
|
||||
{
|
||||
int err;
|
||||
int errlen = sizeof(err);
|
||||
getsockopt(sts->listenSocket, SOL_SOCKET, SO_ERROR,(char*)&err, &errlen);
|
||||
in_addr in;
|
||||
in.s_addr = sts->remoteClients[i]->playerId.binaryAddress;
|
||||
printf("Socket error %i on %s:%i\n", err,inet_ntoa( in ), sts->remoteClients[i]->playerId.port );
|
||||
}
|
||||
|
||||
#endif
|
||||
// Connection lost abruptly
|
||||
playerId=sts->lostConnections.WriteLock();
|
||||
*playerId=sts->remoteClients[i]->playerId;
|
||||
sts->lostConnections.WriteUnlock();
|
||||
sts->DeleteRemoteClient(sts->remoteClients[i], &exceptionFD);
|
||||
sts->remoteClients.RemoveAtIndex(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FD_ISSET(sts->remoteClients[i]->socket, &readFD))
|
||||
{
|
||||
// if recv returns 0 this was a graceful close
|
||||
len=recv(sts->remoteClients[i]->socket, data, BUFF_SIZE, 0);
|
||||
if (len>0)
|
||||
{
|
||||
p=sts->incomingMessages.WriteLock();
|
||||
p->data = new unsigned char[len+1];
|
||||
memcpy(p->data, data, len);
|
||||
p->data[len]=0; // Null terminate this so we can print it out as regular strings. This is different from RakNet which does not do this.
|
||||
p->length=len;
|
||||
p->playerId=sts->remoteClients[i]->playerId;
|
||||
sts->incomingMessages.WriteUnlock();
|
||||
i++; // Nothing deleted so increment the index
|
||||
}
|
||||
else
|
||||
{
|
||||
// Connection lost gracefully
|
||||
playerId=sts->lostConnections.WriteLock();
|
||||
*playerId=sts->remoteClients[i]->playerId;
|
||||
sts->lostConnections.WriteUnlock();
|
||||
sts->DeleteRemoteClient(sts->remoteClients[i], &exceptionFD);
|
||||
sts->remoteClients.RemoveAtIndex(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
i++; // Nothing deleted so increment the index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selectResult==0)
|
||||
{
|
||||
// No input - sleep for a while
|
||||
RakSleep(50);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FD_CLOSE? closesocket(remoteClient->socket);
|
||||
|
||||
#if defined(_DO_PRINTF) && defined(_WIN32)
|
||||
DWORD dwIOError = WSAGetLastError();
|
||||
printf("Socket error %i\n", dwIOError);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
sts->threadRunning=false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user