mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00
1308 lines
34 KiB
C
1308 lines
34 KiB
C
/*
|
|
gpiPeer.c
|
|
GameSpy Presence SDK
|
|
Dan "Mr. Pants" Schoenblum
|
|
|
|
Copyright 1999-2007 GameSpy Industries, Inc
|
|
|
|
devsupport@gamespy.com
|
|
|
|
***********************************************************************
|
|
Please see the GameSpy Presence SDK documentation for more information
|
|
**********************************************************************/
|
|
|
|
//INCLUDES
|
|
//////////
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "gpi.h"
|
|
|
|
//FUNCTIONS
|
|
///////////
|
|
static GPResult
|
|
gpiProcessPeerInitiatingConnection(
|
|
GPConnection * connection,
|
|
GPIPeer * peer
|
|
)
|
|
{
|
|
GPIConnection * iconnection = (GPIConnection*)*connection;
|
|
//int state;
|
|
char * str = NULL;
|
|
//int len;
|
|
GPIBool connClosed;
|
|
GPIProfile * pProfile;
|
|
GPResult result;
|
|
GSUdpPeerState aPeerState;
|
|
|
|
GS_ASSERT(peer);
|
|
if (!peer)
|
|
return GP_NETWORK_ERROR;
|
|
|
|
GS_ASSERT(peer->state != GPI_PEER_DISCONNECTED && peer->state != GPI_PEER_NOT_CONNECTED);
|
|
if (peer->state == GPI_PEER_DISCONNECTED || peer->state == GPI_PEER_NOT_CONNECTED)
|
|
return GP_NETWORK_ERROR;
|
|
// Check the state.
|
|
///////////////////
|
|
switch(peer->state)
|
|
{
|
|
case GPI_PEER_GETTING_SIG:
|
|
// Do nothing - we're waiting for getinfo to get the sig.
|
|
/////////////////////////////////////////////////////////
|
|
break;
|
|
|
|
case GPI_PEER_GOT_SIG:
|
|
{
|
|
// Start the connect.
|
|
/////////////////////
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_State, GSIDebugLevel_Verbose, "Got the peer signature for profileid: %d\n", peer->profile);
|
|
CHECK_RESULT(gpiPeerStartConnect(connection, peer));
|
|
|
|
break;
|
|
}
|
|
case GPI_PEER_CONNECTING:
|
|
{
|
|
// Check if the connect finished.
|
|
/////////////////////////////////
|
|
/*
|
|
CHECK_RESULT(gpiCheckSocketConnect(connection, peer->sock, &state));
|
|
if(state == GPI_DISCONNECTED)
|
|
{
|
|
Error(connection, GP_NETWORK_ERROR, "Error connecting to a peer.");
|
|
}
|
|
*/
|
|
|
|
gsUdpEngineGetPeerState(peer->ip, peer->port, &aPeerState);
|
|
|
|
if(aPeerState == GS_UDP_PEER_CONNECTED)
|
|
{
|
|
GPIPeer * pcurr;
|
|
GPIBool freePeerSig = GPITrue;
|
|
|
|
// Get the profile object.
|
|
//////////////////////////
|
|
if(!gpiGetProfile(connection, peer->profile, &pProfile))
|
|
Error(connection, GP_NETWORK_ERROR, "Error connecting to a peer.");
|
|
|
|
// Send the auth.
|
|
/////////////////
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\auth\\");
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\pid\\");
|
|
gpiAppendIntToBuffer(connection, &peer->outputBuffer, iconnection->profileid);
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\nick\\");
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, iconnection->nick);
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\sig\\");
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, pProfile->peerSig);
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\final\\");
|
|
|
|
// Are there any other peers still connecting?
|
|
//////////////////////////////////////////////
|
|
for(pcurr = iconnection->peerList ; pcurr != NULL ; pcurr = pcurr->pnext)
|
|
if((pcurr->profile == peer->profile) && (pcurr != peer))
|
|
if(pcurr->state <= GPI_PEER_CONNECTING)
|
|
freePeerSig = GPIFalse;
|
|
|
|
// freeclear it?
|
|
///////////
|
|
if(freePeerSig)
|
|
{
|
|
freeclear(pProfile->peerSig);
|
|
if(gpiCanFreeProfile(pProfile))
|
|
gpiRemoveProfile(connection, pProfile);
|
|
}
|
|
|
|
// Update the state.
|
|
////////////////////
|
|
peer->state = GPI_PEER_WAITING;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case GPI_PEER_WAITING:
|
|
{
|
|
// Check for a response.
|
|
////////////////////////
|
|
//CHECK_RESULT(gpiRecvToBuffer(connection, peer->sock, &peer->inputBuffer, &len, &connClosed, "PR"));
|
|
|
|
// Check for a final.
|
|
/////////////////////
|
|
if (peer->inputBuffer.buffer)
|
|
str = strstr(peer->inputBuffer.buffer, "\\final\\");
|
|
if(str != NULL)
|
|
{
|
|
str[0] = '\0';
|
|
str += 7;
|
|
|
|
// Was it rejected?
|
|
///////////////////
|
|
if(strncmp(peer->inputBuffer.buffer, "\\anack\\", 7) == 0)
|
|
{
|
|
// Rejected.
|
|
////////////
|
|
peer->nackCount++;
|
|
|
|
// Is this more than once?
|
|
//////////////////////////
|
|
if(peer->nackCount > 1)
|
|
{
|
|
// we shouldn't reach this case unless there is a problem with
|
|
// the server when getting a buddy's signature
|
|
|
|
// Give up already.
|
|
///////////////////
|
|
Error(connection, GP_NETWORK_ERROR, "Error getting buddy authorization.");
|
|
}
|
|
|
|
// Try getting the latest sig.
|
|
//////////////////////////////
|
|
CHECK_RESULT(gpiPeerGetSig(connection, peer));
|
|
}
|
|
else if(strncmp(peer->inputBuffer.buffer, "\\aack\\", 6) != 0)
|
|
{
|
|
// Unknown message.
|
|
///////////////////
|
|
Error(connection, GP_NETWORK_ERROR, "Error parsing buddy message.");
|
|
}
|
|
|
|
// The connection has been established.
|
|
///////////////////////////////////////
|
|
peer->state = GPI_PEER_CONNECTED;
|
|
peer->inputBuffer.len = 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
// code should not reach here.
|
|
default: break;
|
|
}
|
|
|
|
// Send stuff that needs to be sent.
|
|
////////////////////////////////////
|
|
if(peer->outputBuffer.len > 0)
|
|
{
|
|
//result = gpiSendFromBuffer(connection, peer->sock, &peer->outputBuffer, &connClosed, GPITrue, "PR");
|
|
result = gpiSendBufferToPeer(connection, peer->ip, peer->port, &peer->outputBuffer, &connClosed, GPITrue);
|
|
if(connClosed || (result != GP_NO_ERROR))
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
}
|
|
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
static GPResult
|
|
gpiProcessPeerAcceptingConnection(
|
|
GPConnection * connection,
|
|
GPIPeer * peer
|
|
)
|
|
{
|
|
GPIConnection * iconnection = (GPIConnection*)*connection;
|
|
GSUdpPeerState aPeerState;
|
|
char * str;
|
|
//int len;
|
|
GPIBool connClosed;
|
|
char intValue[16];
|
|
int pid;
|
|
char nick[GP_NICK_LEN];
|
|
char sig[33];
|
|
char sigCheck[33];
|
|
char buffer[256];
|
|
|
|
// Check the state.
|
|
///////////////////
|
|
GS_ASSERT(peer->state == GPI_PEER_WAITING);
|
|
if (peer->state != GPI_PEER_WAITING)
|
|
return GP_NETWORK_ERROR;
|
|
|
|
// Read any pending info.
|
|
/////////////////////////
|
|
//CHECK_RESULT(gpiRecvToBuffer(connection, peer->sock, &peer->inputBuffer, &len, &connClosed, "PR"));
|
|
gsUdpEngineGetPeerState(peer->ip, peer->port, &aPeerState);
|
|
|
|
// Check for a closed connection.
|
|
/////////////////////////////////
|
|
if(aPeerState == GS_UDP_PEER_CLOSED)
|
|
{
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
// Check for a final.
|
|
/////////////////////
|
|
str = strstr(peer->inputBuffer.buffer, "\\final\\");
|
|
if(str != NULL)
|
|
{
|
|
str[0] = '\0';
|
|
str += 7;
|
|
|
|
// Is it an auth?
|
|
/////////////////
|
|
if(strncmp(peer->inputBuffer.buffer, "\\auth\\", 6) == 0)
|
|
{
|
|
// Get the pid.
|
|
///////////////
|
|
if(!gpiValueForKey(peer->inputBuffer.buffer, "\\pid\\", intValue, sizeof(intValue)))
|
|
{
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
return GP_NO_ERROR;
|
|
}
|
|
pid = atoi(intValue);
|
|
|
|
// Get the nick.
|
|
////////////////
|
|
if(!gpiValueForKey(peer->inputBuffer.buffer, "\\nick\\", nick, sizeof(nick)))
|
|
{
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
// Get the sig.
|
|
///////////////
|
|
if(!gpiValueForKey(peer->inputBuffer.buffer, "\\sig\\", sig, sizeof(sig)))
|
|
{
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
// Compute what the sig should be.
|
|
//////////////////////////////////
|
|
sprintf(buffer, "%s%d%d",
|
|
iconnection->password,
|
|
iconnection->profileid,
|
|
pid);
|
|
MD5Digest((unsigned char *)buffer, strlen(buffer), sigCheck);
|
|
|
|
// Check the sig.
|
|
/////////////////
|
|
if(strcmp(sig, sigCheck) != 0)
|
|
{
|
|
// Bad sig.
|
|
///////////
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\anack\\");
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\final\\");
|
|
|
|
gpiSendBufferToPeer(connection, peer->ip, peer->port, &peer->outputBuffer, &connClosed, GPITrue);
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
// Send an ack.
|
|
///////////////
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\aack\\");
|
|
gpiAppendStringToBuffer(connection, &peer->outputBuffer, "\\final\\");
|
|
|
|
peer->state = GPI_PEER_CONNECTED;
|
|
peer->profile = (GPProfile)pid;
|
|
}
|
|
else
|
|
{
|
|
// Unrecognized command.
|
|
////////////////////////
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
// Update the buffer length.
|
|
////////////////////////////
|
|
peer->inputBuffer.len = 0;
|
|
}
|
|
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
GPResult
|
|
gpiPeerSendMessages(
|
|
GPConnection * connection,
|
|
GPIPeer * peer
|
|
)
|
|
{
|
|
GPIBool connClosed;
|
|
GPIMessage * message;
|
|
GPResult result;
|
|
|
|
GS_ASSERT(peer);
|
|
if (!peer)
|
|
return GP_NETWORK_ERROR;
|
|
// Only send messages if there's nothing waiting in the output buffer.
|
|
//////////////////////////////////////////////////////////////////////
|
|
if(peer->outputBuffer.len)
|
|
return GP_NO_ERROR;
|
|
|
|
// Send outgoing messages.
|
|
//////////////////////////
|
|
while(ArrayLength(peer->messages))
|
|
{
|
|
// Get the first message.
|
|
/////////////////////////
|
|
message = (GPIMessage *)ArrayNth(peer->messages, 0);
|
|
|
|
// Send as much as possible.
|
|
////////////////////////////
|
|
//result = gpiSendFromBuffer(connection, peer->sock, &message->buffer, &connClosed, GPIFalse, "PR");
|
|
result = gpiSendBufferToPeer(connection, peer->ip, peer->port, &message->buffer, &connClosed, GPIFalse);
|
|
if(connClosed || (result != GP_NO_ERROR))
|
|
{
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
// Did we not send it all?
|
|
//////////////////////////
|
|
if(message->buffer.pos != message->buffer.len)
|
|
break;
|
|
|
|
// Remove the message.
|
|
//////////////////////
|
|
ArrayDeleteAt(peer->messages, 0);
|
|
}
|
|
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
static GPResult
|
|
gpiProcessPeerConnected(
|
|
GPConnection * connection,
|
|
GPIPeer * peer
|
|
)
|
|
{
|
|
GPIConnection * iconnection = (GPIConnection*)*connection;
|
|
//int len;
|
|
GSUdpPeerState aPeerState;
|
|
GPIBool connClosed;
|
|
GPICallback callback;
|
|
char * buffer;
|
|
int type;
|
|
int messageLen;
|
|
GPResult result;
|
|
|
|
GS_ASSERT(peer);
|
|
if (!peer)
|
|
return GP_NETWORK_ERROR;
|
|
// Send stuff.
|
|
//////////////
|
|
if(peer->outputBuffer.len)
|
|
{
|
|
//result = gpiSendFromBuffer(connection, peer->sock, &peer->outputBuffer, &connClosed, GPITrue, "PR");
|
|
result = gpiSendBufferToPeer(connection, peer->ip, peer->port, &peer->outputBuffer, &connClosed, GPITrue);
|
|
if(connClosed || (result != GP_NO_ERROR))
|
|
{
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
return GP_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
// Send outgoing messages.
|
|
//////////////////////////
|
|
if(!peer->outputBuffer.len)
|
|
{
|
|
CHECK_RESULT(gpiPeerSendMessages(connection, peer));
|
|
if(peer->state == GPI_PEER_DISCONNECTED)
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
// Read messages.
|
|
/////////////////
|
|
/*
|
|
result = gpiRecvToBuffer(connection, peer->sock, &peer->inputBuffer, &len, &connClosed, "PR");
|
|
if(result != GP_NO_ERROR)
|
|
{
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
return GP_NO_ERROR;
|
|
}
|
|
*/
|
|
if(peer->inputBuffer.len > 0)
|
|
{
|
|
peer->timeout = (time(NULL) + GPI_PEER_TIMEOUT);
|
|
}
|
|
|
|
// Grab the message header.
|
|
///////////////////////////
|
|
do
|
|
{
|
|
// Read a message.
|
|
//////////////////
|
|
CHECK_RESULT(gpiReadMessageFromBuffer(connection, &peer->inputBuffer, &buffer, &type, &messageLen));
|
|
if(buffer != NULL)
|
|
{
|
|
// Got a message!
|
|
/////////////////
|
|
switch(type)
|
|
{
|
|
case GPI_BM_MESSAGE:
|
|
callback = iconnection->callbacks[GPI_RECV_BUDDY_MESSAGE];
|
|
if(callback.callback != NULL)
|
|
{
|
|
GPRecvBuddyMessageArg * arg;
|
|
|
|
arg = (GPRecvBuddyMessageArg *)gsimalloc(sizeof(GPRecvBuddyMessageArg));
|
|
if(arg == NULL)
|
|
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
|
|
arg->profile = peer->profile;
|
|
#ifndef GSI_UNICODE
|
|
arg->message = goastrdup(buffer);
|
|
#else
|
|
arg->message = UTF8ToUCS2StringAlloc(buffer);
|
|
#endif
|
|
arg->date = (unsigned int)time(NULL);
|
|
CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_MESSAGE));
|
|
}
|
|
break;
|
|
|
|
case GPI_BM_UTM:
|
|
callback = iconnection->callbacks[GPI_RECV_BUDDY_UTM];
|
|
if (callback.callback != NULL)
|
|
{
|
|
GPRecvBuddyUTMArg * arg;
|
|
|
|
arg = (GPRecvBuddyUTMArg *)gsimalloc(sizeof(GPRecvBuddyUTMArg));
|
|
if(arg == NULL)
|
|
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
|
|
arg->profile = peer->profile;
|
|
#ifndef GSI_UNICODE
|
|
arg->message = goastrdup(buffer);
|
|
#else
|
|
arg->message = UTF8ToUCS2StringAlloc(buffer);
|
|
#endif
|
|
arg->date = (unsigned int)time(NULL);
|
|
CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_MESSAGE));
|
|
}
|
|
break;
|
|
|
|
case GPI_BM_PING:
|
|
// Send back a pong.
|
|
////////////////////
|
|
gpiSendBuddyMessage(connection, peer->profile, GPI_BM_PONG, "1", 0, NULL);
|
|
|
|
break;
|
|
|
|
#ifndef NOFILE
|
|
case GPI_BM_PONG:
|
|
// Lets the transfers handle this.
|
|
//////////////////////////////////
|
|
gpiTransfersHandlePong(connection, peer->profile, peer);
|
|
break;
|
|
#endif
|
|
case GPI_BM_KEYS_REQUEST:
|
|
CHECK_RESULT(gpiBuddyHandleKeyRequest(connection, peer));
|
|
break;
|
|
case GPI_BM_KEYS_REPLY:
|
|
CHECK_RESULT(gpiBuddyHandleKeyReply(connection, peer, buffer));
|
|
// Let the keys request reply handler take care of this.
|
|
////////////////////////////////////////////////////////
|
|
break;
|
|
case GPI_BM_FILE_SEND_REQUEST:
|
|
case GPI_BM_FILE_SEND_REPLY:
|
|
case GPI_BM_FILE_BEGIN:
|
|
case GPI_BM_FILE_END:
|
|
case GPI_BM_FILE_DATA:
|
|
case GPI_BM_FILE_SKIP:
|
|
case GPI_BM_FILE_TRANSFER_THROTTLE:
|
|
case GPI_BM_FILE_TRANSFER_CANCEL:
|
|
case GPI_BM_FILE_TRANSFER_KEEPALIVE:
|
|
// Handle a transfer protocol message.
|
|
//////////////////////////////////////
|
|
gpiHandleTransferMessage(connection, peer, type, peer->inputBuffer.buffer, buffer, messageLen);
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Remove it from the buffer.
|
|
/////////////////////////////
|
|
gpiClipBufferToPosition(connection, &peer->inputBuffer);
|
|
}
|
|
}
|
|
while(buffer);
|
|
|
|
gsUdpEngineGetPeerState(peer->ip, peer->port, &aPeerState);
|
|
//if(connClosed)
|
|
if (aPeerState == GS_UDP_PEER_CLOSED)
|
|
peer->state = GPI_PEER_DISCONNECTED;
|
|
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
|
|
// Used to check for any timed out peer operations
|
|
// assumes peer is not NULL
|
|
// makes no assumption of the operation queue
|
|
void gpiCheckTimedOutPeerOperations(GPConnection * connection, GPIPeer *peer)
|
|
{
|
|
GPIPeerOp *anIterator = peer->peerOpQueue.first;
|
|
GS_ASSERT(peer);
|
|
if (!peer)
|
|
return;
|
|
|
|
while (anIterator && anIterator != peer->peerOpQueue.last)
|
|
{
|
|
if (anIterator->state != GPI_PEER_OP_STATE_FINISHED && current_time() > anIterator->timeout && anIterator->callback)
|
|
{
|
|
// currently only one type of peer operation exists
|
|
// when it's found, we need to provide the application with
|
|
// a result of no data
|
|
if (anIterator->type == GPI_BM_KEYS_REQUEST)
|
|
{
|
|
GPICallback callback;
|
|
GPGetBuddyStatusInfoKeysArg *arg = (GPGetBuddyStatusInfoKeysArg *)gsimalloc(sizeof(GPGetBuddyStatusInfoKeysArg));
|
|
callback.callback = anIterator->callback;
|
|
callback.param = anIterator->userData;
|
|
arg->keys = NULL;
|
|
arg->numKeys = 0;
|
|
arg->values = NULL;
|
|
arg->profile = peer->profile;
|
|
gpiAddCallback(connection, callback, arg, NULL, 0);
|
|
|
|
}
|
|
// The peer operation is removed regardless of type
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Notice, "Peer operation timed out");
|
|
gpiPeerRemoveOp(peer, anIterator);
|
|
}
|
|
anIterator = anIterator->next;
|
|
}
|
|
}
|
|
|
|
|
|
static GPResult
|
|
gpiProcessPeer(
|
|
GPConnection * connection,
|
|
GPIPeer * peer
|
|
)
|
|
{
|
|
GPResult result = GP_NO_ERROR;
|
|
|
|
// This state should never get out of initialization.
|
|
/////////////////////////////////////////////////////
|
|
GS_ASSERT(peer->state != GPI_PEER_NOT_CONNECTED);
|
|
if (peer->state == GPI_PEER_NOT_CONNECTED)
|
|
return GP_NETWORK_ERROR;
|
|
|
|
// If we're not connected yet.
|
|
//////////////////////////////
|
|
if(peer->state != GPI_PEER_CONNECTED)
|
|
{
|
|
if(peer->initiated)
|
|
result = gpiProcessPeerInitiatingConnection(connection, peer);
|
|
else
|
|
result = gpiProcessPeerAcceptingConnection(connection, peer);
|
|
}
|
|
|
|
// If we're connected.
|
|
//////////////////////
|
|
if((result == GP_NO_ERROR) && (peer->state == GPI_PEER_CONNECTED))
|
|
{
|
|
result = gpiProcessPeerConnected(connection, peer);
|
|
gpiCheckTimedOutPeerOperations(connection, peer);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void
|
|
gpiDestroyPeer(
|
|
GPConnection * connection,
|
|
GPIPeer * peer
|
|
)
|
|
{
|
|
#ifndef NOFILE
|
|
// Cleanup any transfers that use this peer.
|
|
////////////////////////////////////////////
|
|
gpiTransferPeerDestroyed(connection, peer);
|
|
#endif
|
|
|
|
//shutdown(peer->sock, 2);
|
|
//closesocket(peer->sock);
|
|
freeclear(peer->inputBuffer.buffer);
|
|
freeclear(peer->outputBuffer.buffer);
|
|
if(peer->messages)
|
|
{
|
|
ArrayFree(peer->messages);
|
|
peer->messages = NULL;
|
|
}
|
|
freeclear(peer);
|
|
|
|
GSI_UNUSED(connection);
|
|
}
|
|
|
|
void
|
|
gpiRemovePeer(
|
|
GPConnection * connection,
|
|
GPIPeer * peer
|
|
)
|
|
{
|
|
GPIPeer * pprev;
|
|
GPIConnection * iconnection = (GPIConnection*)*connection;
|
|
GPIMessage * message;
|
|
|
|
GS_ASSERT(peer != NULL);
|
|
if (peer == NULL)
|
|
return;
|
|
|
|
GS_ASSERT(iconnection->peerList);
|
|
if (iconnection->peerList == NULL)
|
|
return;
|
|
// Check if this is the first peer.
|
|
///////////////////////////////////
|
|
if(iconnection->peerList == peer)
|
|
{
|
|
iconnection->peerList = peer->pnext;
|
|
}
|
|
else
|
|
{
|
|
// Find the previous peer.
|
|
//////////////////////////
|
|
for(pprev = iconnection->peerList ; pprev->pnext != peer ; pprev = pprev->pnext)
|
|
{
|
|
if(pprev->pnext == NULL)
|
|
{
|
|
// Can't find this peer in the list!
|
|
////////////////////////////////////
|
|
assert(0);
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError,
|
|
"Tried to remove peer not in list.");
|
|
return;
|
|
}
|
|
}
|
|
pprev->pnext = peer->pnext;
|
|
}
|
|
|
|
// Check for pending messages.
|
|
//////////////////////////////
|
|
while(ArrayLength(peer->messages))
|
|
{
|
|
// Get the next message.
|
|
////////////////////////
|
|
message = (GPIMessage *)ArrayNth(peer->messages, 0);
|
|
|
|
// Don't forward protocol messages.
|
|
///////////////////////////////////
|
|
if(message->type < 100)
|
|
gpiSendServerBuddyMessage(connection, peer->profile, message->type, message->buffer.buffer + message->start);
|
|
|
|
// Remove the message.
|
|
//////////////////////
|
|
ArrayDeleteAt(peer->messages, 0);
|
|
}
|
|
|
|
gpiDestroyPeer(connection, peer);
|
|
}
|
|
|
|
GPResult gpiProcessPeers(GPConnection *connection)
|
|
{
|
|
GPIConnection * iconnection = (GPIConnection*)*connection;
|
|
GPIPeer * nextPeer;
|
|
GPIPeer * peer;
|
|
//SOCKET incoming;
|
|
GPResult result;
|
|
|
|
/*
|
|
// Check for incoming peer connections.
|
|
///////////////////////////////////////
|
|
if(iconnection->peerSocket != INVALID_SOCKET)
|
|
{
|
|
// Have to manually check if accept is possible since
|
|
// PS2 Insock only supports blocking sockets.
|
|
if (CanReceiveOnSocket(iconnection->peerSocket))
|
|
{
|
|
incoming = accept(iconnection->peerSocket, NULL, NULL);
|
|
if(incoming != INVALID_SOCKET)
|
|
{
|
|
// This is a new peer.
|
|
//////////////////////
|
|
peer = gpiAddPeer(connection, -1, GPIFalse);
|
|
if(peer)
|
|
{
|
|
peer->state = GPI_PEER_WAITING;
|
|
peer->sock = incoming;
|
|
SetSockBlocking(incoming, 0);
|
|
gpiSetPeerSocketSizes(peer->sock);
|
|
}
|
|
else
|
|
{
|
|
closesocket(incoming);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
gsUdpEngineThink();
|
|
// Got through the list of peers.
|
|
/////////////////////////////////
|
|
for(peer = iconnection->peerList ; peer != NULL ; peer = nextPeer)
|
|
{
|
|
// Store the next peer.
|
|
///////////////////////
|
|
nextPeer = peer->pnext;
|
|
if(peer->state == GPI_PEER_DISCONNECTED)
|
|
{
|
|
// Remove it.
|
|
/////////////
|
|
//gsDebug
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Notice, "Peer disconnected, pid: %d", peer->profile);
|
|
gpiRemovePeer(connection, peer);
|
|
}
|
|
else
|
|
{
|
|
// Process the peer.
|
|
////////////////////
|
|
result = gpiProcessPeer(connection, peer);
|
|
|
|
// Check for a disconnection or a timeout.
|
|
//////////////////////////////////////////
|
|
if((peer->state == GPI_PEER_DISCONNECTED) || (result != GP_NO_ERROR) || (time(NULL) > peer->timeout))
|
|
{
|
|
// Remove it.
|
|
/////////////
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Notice, "Peer disconnected, pid: %d", peer->profile);
|
|
gpiRemovePeer(connection, peer);
|
|
}
|
|
}
|
|
}
|
|
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
// NOTE: use this function when in a gp function
|
|
GPIPeer * gpiGetPeerByProfile(const GPConnection * connection,
|
|
int profileid)
|
|
{
|
|
GPIConnection * iconnection = (GPIConnection*)*connection;
|
|
GPIPeer * pcurr;
|
|
|
|
// Go through the list of peers.
|
|
////////////////////////////////
|
|
for(pcurr = iconnection->peerList ; pcurr != NULL ; pcurr = pcurr->pnext)
|
|
{
|
|
// Check for a match.
|
|
/////////////////////
|
|
if(pcurr->profile == profileid)
|
|
{
|
|
// Got it.
|
|
//////////
|
|
return pcurr;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// NOTE: use this function only when in a UDP layer callback
|
|
GPIPeer * gpiGetPeerByAddr(const GPConnection *connection,
|
|
unsigned int ip,
|
|
unsigned short port)
|
|
{
|
|
GPIConnection * iconnection = (GPIConnection*)*connection;
|
|
GPIPeer * pcurr;
|
|
|
|
GS_ASSERT(ip);
|
|
GS_ASSERT(port);
|
|
if (!ip && !port)
|
|
return NULL;
|
|
// Go through the list of peers.
|
|
////////////////////////////////
|
|
for(pcurr = iconnection->peerList ; pcurr != NULL ; pcurr = pcurr->pnext)
|
|
{
|
|
// Check for a match.
|
|
/////////////////////
|
|
if(pcurr->ip == ip && pcurr->port == port)
|
|
{
|
|
// Got it.
|
|
//////////
|
|
return pcurr;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
gsi_bool gpiIsPeerConnected(GPIPeer *peer)
|
|
{
|
|
GS_ASSERT(peer);
|
|
if (!peer)
|
|
return gsi_false;
|
|
|
|
if (peer && peer->state != GPI_PEER_CONNECTED)
|
|
return gsi_false;
|
|
|
|
return gsi_true;
|
|
}
|
|
|
|
static void gpiFreeMessage(void * elem)
|
|
{
|
|
GPIMessage * message = (GPIMessage *)elem;
|
|
|
|
freeclear(message->buffer.buffer);
|
|
}
|
|
|
|
GPIPeer *
|
|
gpiAddPeer(
|
|
GPConnection * connection,
|
|
int profileid,
|
|
GPIBool initiate
|
|
)
|
|
{
|
|
GPIPeer * peer;
|
|
GPIConnection * iconnection = (GPIConnection*)*connection;
|
|
|
|
// Create a new peer.
|
|
/////////////////////
|
|
peer = (GPIPeer *)gsimalloc(sizeof(GPIPeer));
|
|
if(peer == NULL)
|
|
return NULL;
|
|
memset(peer, 0, sizeof(GPIPeer));
|
|
peer->state = GPI_PEER_NOT_CONNECTED;
|
|
peer->initiated = initiate;
|
|
//peer->sock = INVALID_SOCKET;
|
|
peer->profile = profileid;
|
|
peer->timeout = (time(NULL) + GPI_PEER_TIMEOUT);
|
|
peer->pnext = iconnection->peerList;
|
|
peer->messages = ArrayNew(sizeof(GPIMessage), 0, gpiFreeMessage);
|
|
iconnection->peerList = peer;
|
|
peer->peerOpQueue.first = NULL;
|
|
peer->peerOpQueue.last = NULL;
|
|
peer->peerOpQueue.opList = NULL;
|
|
return peer;
|
|
}
|
|
|
|
GPResult
|
|
gpiPeerGetSig(
|
|
GPConnection * connection,
|
|
GPIPeer * peer
|
|
)
|
|
{
|
|
GPIOperation * operation;
|
|
|
|
// Start a get info operation to get the sig.
|
|
/////////////////////////////////////////////
|
|
CHECK_RESULT(gpiAddOperation(connection, GPI_GET_INFO, NULL, &operation, GP_NON_BLOCKING, NULL, NULL));
|
|
|
|
// Send the get info.
|
|
/////////////////////
|
|
CHECK_RESULT(gpiSendGetInfo(connection, peer->profile, operation->id));
|
|
|
|
// Set the state.
|
|
/////////////////
|
|
peer->state = GPI_PEER_GETTING_SIG;
|
|
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
GPResult
|
|
gpiPeerStartConnect(
|
|
GPConnection * connection,
|
|
GPIPeer * peer
|
|
)
|
|
{
|
|
//int rcode;
|
|
//struct sockaddr_in address;
|
|
GPIProfile * profile;
|
|
GPIConnection * iconnection = (GPIConnection*)*connection;
|
|
GSUdpErrorCode anError;
|
|
|
|
// Get the profile object.
|
|
//////////////////////////
|
|
if(!gpiGetProfile(connection, peer->profile, &profile))
|
|
Error(connection, GP_NETWORK_ERROR, "Error connecting to a peer.");
|
|
|
|
/*
|
|
// Create the socket.
|
|
/////////////////////
|
|
peer->sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if(peer->sock == INVALID_SOCKET)
|
|
CallbackError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error creating a socket.");
|
|
|
|
// Make it non-blocking.
|
|
////////////////////////
|
|
rcode = SetSockBlocking(peer->sock, 0);
|
|
if(rcode == 0)
|
|
CallbackError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error making a socket non-blocking.");
|
|
|
|
// Bind the socket.
|
|
///////////////////
|
|
|
|
// BD: PS2 Insock has bug with binding to port 0
|
|
// No sockets after the first will be able to bind
|
|
|
|
memset(&address, 0, sizeof(address));
|
|
address.sin_family = AF_INET;
|
|
rcode = bind(peer->sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in));
|
|
if (gsiSocketIsError(rcode))
|
|
CallbackError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error binding a socket.");
|
|
|
|
// Set the socket sizes.
|
|
////////////////////////
|
|
gpiSetPeerSocketSizes(peer->sock);
|
|
|
|
// Connect the socket.
|
|
//////////////////////
|
|
memset(&address, 0, sizeof(address));
|
|
address.sin_family = AF_INET;
|
|
address.sin_addr.s_addr = profile->buddyStatus->ip;
|
|
address.sin_port = (gsi_u16)profile->buddyStatus->port;
|
|
rcode = connect(peer->sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in));
|
|
if (gsiSocketIsError(rcode))
|
|
{
|
|
int error = GOAGetLastError(peer->sock);
|
|
if((error != WSAEWOULDBLOCK) && (error != WSAEINPROGRESS) && (error != WSAETIMEDOUT) )
|
|
{
|
|
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error connecting a socket.");
|
|
}
|
|
}
|
|
*/
|
|
|
|
if (profile->buddyStatusInfo)
|
|
{
|
|
GSUdpPeerState aPeerState;
|
|
gsUdpEngineGetPeerState(profile->buddyStatusInfo->buddyIp , profile->buddyStatusInfo->buddyPort, &aPeerState);
|
|
if (aPeerState != GS_UDP_PEER_CONNECTED || aPeerState != GS_UDP_PEER_CONNECTING)
|
|
{
|
|
anError = gsUdpEngineStartTalkingToPeer(profile->buddyStatusInfo->buddyIp , profile->buddyStatusInfo->buddyPort,
|
|
iconnection->mHeader, GPI_PEER_TIMEOUT);
|
|
if (anError != GS_UDP_ADDRESS_ALREADY_IN_USE)
|
|
CallbackError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error starting communication with a peer.");
|
|
}
|
|
peer->ip = profile->buddyStatusInfo->buddyIp;
|
|
peer->port = profile->buddyStatusInfo->buddyPort;
|
|
}
|
|
// We're waiting for the connect to complete.
|
|
/////////////////////////////////////////////
|
|
peer->state = GPI_PEER_CONNECTING;
|
|
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
GPResult
|
|
gpiPeerAddMessage(
|
|
GPConnection * connection,
|
|
GPIPeer * peer,
|
|
int type,
|
|
const char * message
|
|
)
|
|
{
|
|
GPIMessage gpiMessage;
|
|
int len;
|
|
|
|
GS_ASSERT(peer != NULL);
|
|
GS_ASSERT(message != NULL);
|
|
|
|
if (peer == NULL)
|
|
return GP_NETWORK_ERROR;
|
|
if (message == NULL)
|
|
return GP_NETWORK_ERROR;
|
|
|
|
// Get the length.
|
|
//////////////////
|
|
len = (int)strlen(message);
|
|
|
|
// Clear the message.
|
|
/////////////////////
|
|
memset(&gpiMessage, 0, sizeof(GPIMessage));
|
|
|
|
// Copy the type.
|
|
/////////////////
|
|
gpiMessage.type = type;
|
|
|
|
// Copy the header to the buffer.
|
|
/////////////////////////////////
|
|
CHECK_RESULT(gpiAppendStringToBuffer(connection, &gpiMessage.buffer, "\\m\\"));
|
|
CHECK_RESULT(gpiAppendIntToBuffer(connection, &gpiMessage.buffer, type));
|
|
CHECK_RESULT(gpiAppendStringToBuffer(connection, &gpiMessage.buffer, "\\len\\"));
|
|
CHECK_RESULT(gpiAppendIntToBuffer(connection, &gpiMessage.buffer, len));
|
|
CHECK_RESULT(gpiAppendStringToBuffer(connection, &gpiMessage.buffer, "\\msg\\\n"));
|
|
|
|
// Copy the message to the buffer.
|
|
//////////////////////////////////
|
|
gpiMessage.start = gpiMessage.buffer.len;
|
|
CHECK_RESULT(gpiAppendStringToBufferLen(connection, &gpiMessage.buffer, message, len));
|
|
CHECK_RESULT(gpiAppendCharToBuffer(connection, &gpiMessage.buffer, '\0'));
|
|
|
|
// Add it to the list.
|
|
//////////////////////
|
|
ArrayAppend(peer->messages, &gpiMessage);
|
|
|
|
// Reset the timeout.
|
|
/////////////////////
|
|
peer->timeout = (time(NULL) + GPI_PEER_TIMEOUT);
|
|
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
GPResult
|
|
gpiPeerStartTransferMessage(
|
|
GPConnection * connection,
|
|
GPIPeer * peer,
|
|
int type,
|
|
const struct GPITransferID_s * transferID
|
|
)
|
|
{
|
|
char buffer[64];
|
|
GPITransferID tid;
|
|
tid.count = transferID->count;
|
|
tid.profileid = transferID->profileid;
|
|
tid.time = transferID->time;
|
|
|
|
GS_ASSERT(transferID);
|
|
if (!transferID)
|
|
return GP_NETWORK_ERROR;
|
|
// Start the message.
|
|
/////////////////////
|
|
sprintf(buffer, "\\m\\%d\\xfer\\%d %u %u", type, tid.profileid, tid.count, tid.time);
|
|
|
|
return gpiSendOrBufferString(connection, peer, buffer);
|
|
}
|
|
|
|
GPResult
|
|
gpiPeerFinishTransferMessage(
|
|
GPConnection * connection,
|
|
GPIPeer * peer,
|
|
const char * message,
|
|
int len
|
|
)
|
|
{
|
|
char buffer[32];
|
|
GS_ASSERT(peer != NULL);
|
|
if (!peer)
|
|
return GP_NETWORK_ERROR;
|
|
|
|
// Check the message.
|
|
/////////////////////
|
|
if(!message)
|
|
message = "";
|
|
|
|
if(len == -1)
|
|
len = (int)strlen(message);
|
|
|
|
// Set the len and the message.
|
|
///////////////////////////////
|
|
sprintf(buffer, "\\len\\%d\\msg\\\n", len);
|
|
CHECK_RESULT(gpiSendOrBufferString(connection, peer, buffer));
|
|
|
|
// Copy the message to the buffer.
|
|
//////////////////////////////////
|
|
CHECK_RESULT(gpiSendOrBufferStringLenToPeer(connection, peer, message, len));
|
|
CHECK_RESULT(gpiSendOrBufferChar(connection, peer, '\0'));
|
|
|
|
// Reset the timeout.
|
|
/////////////////////
|
|
peer->timeout = (time(NULL) + GPI_PEER_TIMEOUT);
|
|
|
|
return GP_NO_ERROR;
|
|
}
|
|
|
|
void gpiPeerLeftCallback(unsigned int ip, unsigned short port, GSUdpCloseReason reason, void *userData)
|
|
{
|
|
|
|
GPConnection *connection = (GPConnection *)userData;
|
|
GPIPeer *aPeer;
|
|
IN_ADDR anAddr;
|
|
anAddr.s_addr = ip;
|
|
aPeer = gpiGetPeerByAddr(connection, ip, port);
|
|
//gpiRemovePeer(connection, aPeer);
|
|
if (aPeer)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Notice,
|
|
"Peer left: addr: %s:%d, profile: %d\n", inet_ntoa(anAddr), port, aPeer->profile);
|
|
aPeer->state = GPI_PEER_DISCONNECTED;
|
|
}
|
|
|
|
GSI_UNUSED(anAddr);
|
|
GSI_UNUSED(reason);
|
|
}
|
|
|
|
void gpiPeerMessageCallback(unsigned int ip, unsigned short port, unsigned char *message,
|
|
unsigned int messageLength, gsi_bool reliable, void *userData)
|
|
{
|
|
GPConnection *connection = (GPConnection *)userData;
|
|
GPIPeer *aPeer;
|
|
unsigned char * buff;
|
|
int writePos;
|
|
int size;
|
|
IN_ADDR anAddr;
|
|
anAddr.s_addr = ip;
|
|
aPeer = gpiGetPeerByAddr(connection, ip, port);
|
|
if (!aPeer)
|
|
{
|
|
aPeer = gpiAddPeer(connection, -1, GPIFalse);
|
|
if (aPeer)
|
|
{
|
|
aPeer->state = GPI_PEER_WAITING;
|
|
aPeer->ip = ip;
|
|
aPeer->port = port;
|
|
}
|
|
else
|
|
{
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Memory, GSIDebugLevel_HotError,
|
|
"gpiPeerMessageCallback: out of memory when allocating peer, addr: %s:%d", inet_ntoa(anAddr), port);
|
|
return;
|
|
}
|
|
}
|
|
|
|
buff = (unsigned char *)aPeer->inputBuffer.buffer;
|
|
writePos = aPeer->inputBuffer.len;
|
|
size = aPeer->inputBuffer.size;
|
|
|
|
// Check if the buffer needs to be resized.
|
|
///////////////////////////////////////////
|
|
if((int)messageLength > (size - writePos))
|
|
{
|
|
unsigned char *reallocedBuff;
|
|
size = (writePos + max(GPI_READ_SIZE,(int)messageLength));
|
|
reallocedBuff = (unsigned char *)gsirealloc(buff, (unsigned int)size + 1);
|
|
if(reallocedBuff == NULL)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Memory, GSIDebugLevel_HotError,
|
|
"gpiPeerMessageCallback: out of memory when reallocating buffer, addr: %s:%d", inet_ntoa(anAddr), port);
|
|
gsifree(buff);
|
|
gpiSetErrorString(connection, "Out of memory.");
|
|
gpiCallErrorCallback(connection, GP_MEMORY_ERROR, GP_NON_FATAL);
|
|
return;
|
|
}
|
|
else
|
|
buff = reallocedBuff;
|
|
}
|
|
|
|
memcpy(&buff[writePos], message, messageLength);
|
|
|
|
aPeer->inputBuffer.buffer = (char *)buff;
|
|
aPeer->inputBuffer.len += messageLength;
|
|
aPeer->inputBuffer.size = size;
|
|
buff[aPeer->inputBuffer.len] = '\0';
|
|
GSI_UNUSED(reliable);
|
|
GSI_UNUSED(anAddr);
|
|
}
|
|
|
|
void gpiPeerAcceptedCallback(unsigned int ip, unsigned short port,
|
|
GSUdpErrorCode error, gsi_bool rejected, void *userData)
|
|
{
|
|
GPConnection *connection = (GPConnection *)userData;
|
|
GPIPeer *aPeer;
|
|
IN_ADDR anAddr;
|
|
anAddr.s_addr = ip;
|
|
|
|
aPeer = gpiGetPeerByAddr(connection, ip, port);
|
|
if (!aPeer)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_HotError,
|
|
"Peer does not exist: ip-port: %s:%d\n", inet_ntoa(anAddr), port);
|
|
}
|
|
else
|
|
{
|
|
if (rejected)
|
|
{
|
|
aPeer->state = GPI_PEER_DISCONNECTED;
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Notice,
|
|
"Peer Connection rejected: ip-port: %s:%d\n", inet_ntoa(anAddr), port);
|
|
return;
|
|
}
|
|
}
|
|
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Notice,
|
|
"Peer Connection accepted: ip-port: %s:%d\n", inet_ntoa(anAddr), port);
|
|
|
|
GSI_UNUSED(userData);
|
|
GSI_UNUSED(rejected);
|
|
GSI_UNUSED(error);
|
|
GSI_UNUSED(anAddr);
|
|
}
|
|
void gpiPeerPingReplyCallback(unsigned int ip, unsigned short port, unsigned int latency, void *userData)
|
|
{
|
|
GSI_UNUSED(userData);
|
|
GSI_UNUSED(latency);
|
|
GSI_UNUSED(port);
|
|
GSI_UNUSED(ip);
|
|
}
|
|
|
|
// gpiPeerAddOp notes:
|
|
// Assumes non-null inputs!
|
|
// The queue should be empty when the first element is added.
|
|
// Any new element added will be added to the end of the queue.
|
|
void gpiPeerAddOp(GPIPeer *peer, GPIPeerOp *operation)
|
|
{
|
|
GS_ASSERT(peer);
|
|
GS_ASSERT(operation);
|
|
|
|
if (!peer || !operation)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_WarmError, "Peer operation not added");
|
|
return;
|
|
}
|
|
// Three cases can occur:
|
|
// The list is empty - set all pointers to the new node
|
|
// The list has only one element - set the first element's next to the new
|
|
// and set the last element to the new
|
|
// The list has more than one element - add the new element to the end of
|
|
// the queue
|
|
if (peer->peerOpQueue.opList == NULL)
|
|
{
|
|
peer->peerOpQueue.first = operation;
|
|
peer->peerOpQueue.last = operation;
|
|
peer->peerOpQueue.opList = operation;
|
|
}
|
|
else if (peer->peerOpQueue.first == peer->peerOpQueue.last)
|
|
{
|
|
peer->peerOpQueue.first->next = operation;
|
|
peer->peerOpQueue.last = operation;
|
|
}
|
|
else
|
|
{
|
|
peer->peerOpQueue.last->next = operation;
|
|
peer->peerOpQueue.last = operation;
|
|
}
|
|
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Notice, "Peer Operation Added");
|
|
}
|
|
|
|
// gpiPeerRemoveOp:
|
|
// Assumes the list is NOT NULL otherwise it returns.
|
|
// Assumes the operation being passed in is on the queue.
|
|
// Assumes non-null inputs!
|
|
// Completed or Timed out Operations are deleted from queue by finding
|
|
// the operation passed in. Removal of operations don't necessarily
|
|
// happen in order.
|
|
void gpiPeerRemoveOp(GPIPeer *peer, GPIPeerOp *operation)
|
|
{
|
|
GS_ASSERT(peer);
|
|
GS_ASSERT(operation);
|
|
if (!peer || !operation)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_WarmError, "Peer operation not removed");
|
|
return;
|
|
}
|
|
|
|
GS_ASSERT(peer->peerOpQueue.opList != NULL);
|
|
if (peer->peerOpQueue.opList == NULL)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_WarmError, "Peer operation not removed");
|
|
return;
|
|
}
|
|
|
|
if (peer->peerOpQueue.first == peer->peerOpQueue.last && peer->peerOpQueue.first == operation)
|
|
{
|
|
peer->peerOpQueue.opList = peer->peerOpQueue.first = peer->peerOpQueue.last = operation->next;
|
|
}
|
|
else if (peer->peerOpQueue.first == operation)
|
|
{
|
|
peer->peerOpQueue.first = peer->peerOpQueue.first->next;
|
|
peer->peerOpQueue.opList = peer->peerOpQueue.first;
|
|
}
|
|
else
|
|
{
|
|
GPIPeerOp *aPrevOp = NULL;
|
|
for(aPrevOp = peer->peerOpQueue.first ; aPrevOp->next != operation ; aPrevOp = aPrevOp->next)
|
|
{
|
|
if(aPrevOp->next == NULL)
|
|
{
|
|
// Can't find this peer in the list!
|
|
////////////////////////////////////
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_HotError,
|
|
"Tried to remove peer operation not in list.");
|
|
return;
|
|
}
|
|
}
|
|
aPrevOp->next = operation->next;
|
|
}
|
|
|
|
gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Misc, GSIDebugLevel_Notice, "Peer operation removed");
|
|
freeclear(operation);
|
|
}
|