mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00
343 lines
7.6 KiB
C
343 lines
7.6 KiB
C
/*
|
|
GameSpy GT2 SDK
|
|
Dan "Mr. Pants" Schoenblum
|
|
dan@gamespy.com
|
|
|
|
Copyright 2002 GameSpy Industries, Inc
|
|
|
|
devsupport@gamespy.com
|
|
*/
|
|
|
|
#include "gt2Connection.h"
|
|
#include "gt2Socket.h"
|
|
#include "gt2Message.h"
|
|
#include "gt2Callback.h"
|
|
#include "gt2Utility.h"
|
|
#include <stdlib.h>
|
|
|
|
GT2Result gti2NewOutgoingConnection(GT2Socket socket, GT2Connection * connection, unsigned int ip, unsigned short port)
|
|
{
|
|
GT2Result result;
|
|
|
|
// create the object
|
|
result = gti2NewSocketConnection(socket, connection, ip, port);
|
|
if(result != GT2Success)
|
|
return result;
|
|
|
|
// set initial states
|
|
(*connection)->state = GTI2AwaitingServerChallenge;
|
|
(*connection)->initiated = GT2True;
|
|
|
|
return GT2Success;
|
|
}
|
|
|
|
GT2Result gti2NewIncomingConnection(GT2Socket socket, GT2Connection * connection, unsigned int ip, unsigned short port)
|
|
{
|
|
GT2Result result;
|
|
|
|
// create the object
|
|
result = gti2NewSocketConnection(socket, connection, ip, port);
|
|
if(result != GT2Success)
|
|
return result;
|
|
|
|
// set initial states
|
|
(*connection)->state = GTI2AwaitingClientChallenge;
|
|
(*connection)->initiated = GT2False;
|
|
|
|
return GT2Success;
|
|
}
|
|
|
|
GT2Result gti2StartConnectionAttempt
|
|
(
|
|
GT2Connection connection,
|
|
const GT2Byte * message,
|
|
int len,
|
|
GT2ConnectionCallbacks * callbacks
|
|
)
|
|
{
|
|
char challenge[GTI2_CHALLENGE_LEN];
|
|
|
|
// check the message and len
|
|
gti2MessageCheck(&message, &len);
|
|
|
|
// copy off the message
|
|
if(len > 0)
|
|
{
|
|
connection->initialMessage = (char *)gsimalloc((unsigned int)len);
|
|
if(!connection->initialMessage)
|
|
return GT2OutOfMemory;
|
|
|
|
memcpy(connection->initialMessage, message, (unsigned int)len);
|
|
connection->initialMessageLen = len;
|
|
}
|
|
|
|
// copy the callbacks
|
|
if(callbacks)
|
|
connection->callbacks = *callbacks;
|
|
|
|
// generate a challenge
|
|
gti2GetChallenge((GT2Byte *)challenge);
|
|
|
|
// generate and store the expected response
|
|
gti2GetResponse((GT2Byte *)connection->response, (GT2Byte *)challenge);
|
|
|
|
// send the client challenge
|
|
gti2SendClientChallenge(connection, challenge);
|
|
|
|
// update our state
|
|
connection->state = GTI2AwaitingServerChallenge;
|
|
|
|
return GT2Success;
|
|
}
|
|
|
|
GT2Bool gti2AcceptConnection(GT2Connection connection, GT2ConnectionCallbacks * callbacks)
|
|
{
|
|
// was the connection already closed?
|
|
if(connection->freeAtAcceptReject)
|
|
{
|
|
// clear the flag
|
|
connection->freeAtAcceptReject = GT2False;
|
|
|
|
// let the app know if was already closed
|
|
return GT2False;
|
|
}
|
|
|
|
// make sure this flag gets cleared
|
|
connection->freeAtAcceptReject = GT2False;
|
|
|
|
// check that we're still awaiting this
|
|
if(connection->state != GTI2AwaitingAcceptReject)
|
|
return GT2False;
|
|
|
|
// let the other side know
|
|
gti2SendAccept(connection);
|
|
|
|
// update our state
|
|
connection->state = GTI2Connected;
|
|
|
|
// store the callbacks
|
|
if(callbacks)
|
|
connection->callbacks = *callbacks;
|
|
|
|
return GT2True;
|
|
}
|
|
|
|
void gti2RejectConnection(GT2Connection connection, const GT2Byte * message, int len)
|
|
{
|
|
// make sure this flag gets cleared
|
|
connection->freeAtAcceptReject = GT2False;
|
|
|
|
// check that we're still awaiting this
|
|
if(connection->state != GTI2AwaitingAcceptReject)
|
|
return;
|
|
|
|
// check the message and len
|
|
gti2MessageCheck(&message, &len);
|
|
|
|
// let the other side know
|
|
gti2SendReject(connection, message, len);
|
|
|
|
// update our state
|
|
connection->state = GTI2Closing;
|
|
}
|
|
|
|
GT2Bool gti2ConnectionSendData(GT2Connection connection, const GT2Byte * message, int len)
|
|
{
|
|
// send the data on the socket
|
|
if(!gti2SocketSend(connection->socket, connection->ip, connection->port, message, len))
|
|
return GT2False;
|
|
|
|
// mark the time (used for keep-alives)
|
|
connection->lastSend = current_time();
|
|
|
|
return GT2True;
|
|
}
|
|
|
|
static GT2Bool gti2CheckTimeout(GT2Connection connection, gsi_time now)
|
|
{
|
|
// are we still trying to connect?
|
|
if(connection->state < GTI2Connected)
|
|
{
|
|
GT2Bool timedOut = GT2False;
|
|
|
|
// is this the initiator
|
|
if(connection->initiated)
|
|
{
|
|
// do we have a timeout?
|
|
if(connection->timeout)
|
|
{
|
|
// check the time taken against the timeout
|
|
if((now - connection->startTime) > connection->timeout)
|
|
timedOut = GT2True;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// don't time them out if they're waiting for us
|
|
if(connection->state < GTI2AwaitingAcceptReject)
|
|
{
|
|
// check the time taken against the timeout
|
|
if((now - connection->startTime) > GTI2_SERVER_TIMEOUT)
|
|
timedOut = GT2True;
|
|
}
|
|
}
|
|
|
|
// check if we timed out
|
|
if(timedOut)
|
|
{
|
|
// let them know
|
|
gti2SendClosed(connection);
|
|
|
|
// mark it as closed
|
|
gti2ConnectionClosed(connection);
|
|
|
|
// call the callback
|
|
if(!gti2ConnectedCallback(connection, GT2TimedOut, NULL, 0))
|
|
return GT2False;
|
|
}
|
|
}
|
|
|
|
return GT2True;
|
|
}
|
|
|
|
static GT2Bool gti2SendRetries(GT2Connection connection, gsi_time now)
|
|
{
|
|
int i;
|
|
int len;
|
|
GTI2OutgoingBufferMessage * message;
|
|
|
|
// go through the list of outgoing messages awaiting confirmation
|
|
len = ArrayLength(connection->outgoingBufferMessages);
|
|
for(i = 0 ; i < len ; i++)
|
|
{
|
|
// get the message
|
|
message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, i);
|
|
|
|
// check if it's time to resend it
|
|
if((now - message->lastSend) > GTI2_RESEND_TIME)
|
|
{
|
|
if(!gti2ResendMessage(connection, message))
|
|
return GT2False;
|
|
}
|
|
}
|
|
|
|
return GT2True;
|
|
}
|
|
|
|
static GT2Bool gti2CheckPendingAck(GT2Connection connection, gsi_time now)
|
|
{
|
|
// check for nothing pending
|
|
if(!connection->pendingAck)
|
|
return GT2True;
|
|
|
|
// check how long it has been pending
|
|
if((now - connection->pendingAckTime) > GTI2_PENDING_ACK_TIME)
|
|
{
|
|
if(!gti2SendAck(connection))
|
|
return GT2False;
|
|
}
|
|
|
|
return GT2True;
|
|
}
|
|
|
|
static GT2Bool gti2CheckKeepAlive(GT2Connection connection, gsi_time now)
|
|
{
|
|
if((now - connection->lastSend) > GTI2_KEEP_ALIVE_TIME)
|
|
{
|
|
if(!gti2SendKeepAlive(connection))
|
|
return GT2False;
|
|
}
|
|
|
|
return GT2True;
|
|
}
|
|
|
|
GT2Bool gti2ConnectionThink(GT2Connection connection, gsi_time now)
|
|
{
|
|
// check timeout
|
|
if(!gti2CheckTimeout(connection, now))
|
|
return GT2False;
|
|
|
|
// check keep alives
|
|
if(!gti2CheckKeepAlive(connection, now))
|
|
return GT2False;
|
|
|
|
// send retries
|
|
if(!gti2SendRetries(connection, now))
|
|
return GT2False;
|
|
|
|
// check the pending ack
|
|
if(!gti2CheckPendingAck(connection, now))
|
|
return GT2False;
|
|
|
|
return GT2True;
|
|
}
|
|
|
|
void gti2CloseConnection(GT2Connection connection, GT2Bool hard)
|
|
{
|
|
// check if it should be hard or soft closed
|
|
if(hard)
|
|
{
|
|
// check if it's already closed
|
|
if(connection->state >= GTI2Closed)
|
|
return;
|
|
|
|
// mark it as closed
|
|
gti2ConnectionClosed(connection);
|
|
|
|
// send a closed message
|
|
gti2SendClosed(connection);
|
|
|
|
// call the callback
|
|
gti2ClosedCallback(connection, GT2LocalClose);
|
|
|
|
// try and free it
|
|
gti2FreeSocketConnection(connection);
|
|
}
|
|
else
|
|
{
|
|
// mark it as closing
|
|
connection->state = GTI2Closing;
|
|
|
|
// send the close
|
|
gti2SendClose(connection);
|
|
}
|
|
}
|
|
|
|
void gti2ConnectionClosed(GT2Connection connection)
|
|
{
|
|
// check for already closed
|
|
if(connection->state == GTI2Closed)
|
|
return;
|
|
|
|
// mark the connection as closed
|
|
connection->state = GTI2Closed;
|
|
|
|
// remove it from the connected list
|
|
TableRemove(connection->socket->connections, &connection);
|
|
|
|
// add it to the closed list
|
|
ArrayAppend(connection->socket->closedConnections, &connection);
|
|
}
|
|
|
|
void gti2ConnectionCleanup(GT2Connection connection)
|
|
{
|
|
if(connection->initialMessage)
|
|
gsifree(connection->initialMessage);
|
|
|
|
if(connection->incomingBuffer.buffer)
|
|
gsifree(connection->incomingBuffer.buffer);
|
|
if(connection->outgoingBuffer.buffer)
|
|
gsifree(connection->outgoingBuffer.buffer);
|
|
|
|
if(connection->incomingBufferMessages)
|
|
ArrayFree(connection->incomingBufferMessages);
|
|
if(connection->outgoingBufferMessages)
|
|
ArrayFree(connection->outgoingBufferMessages);
|
|
|
|
if(connection->sendFilters)
|
|
ArrayFree(connection->sendFilters);
|
|
if(connection->receiveFilters)
|
|
ArrayFree(connection->receiveFilters);
|
|
|
|
gsifree(connection);
|
|
}
|