/* gpiUtility.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 #include #include #include #include "gpi.h" //DEFINES ///////// #define OUTPUT_MAX_COL 100 // Disable compiler warnings for issues that are unavoidable. ///////////////////////////////////////////////////////////// #if defined(_MSC_VER) // DevStudio // Level4, "conditional expression is constant". // Occurs with use of the MS provided macro FD_SET #pragma warning ( disable: 4127 ) #endif // _MSC_VER //FUNCTIONS /////////// void strzcpy( char * dest, const char * src, size_t len ) { assert(dest != NULL); assert(src != NULL); strncpy(dest, src, len); dest[len - 1] = '\0'; } GPIBool gpiCheckForError( GPConnection * connection, const char * input, GPIBool callErrorCallback ) { char buffer[16]; GPIConnection * iconnection = (GPIConnection*)*connection; if(strncmp(input, "\\error\\", 7) == 0) { // Get the err code. //////////////////// if(gpiValueForKey(input, "\\err\\", buffer, sizeof(buffer))) iconnection->errorCode = (GPErrorCode)atoi(buffer); // Get the error string. //////////////////////// if(!gpiValueForKey(input, "\\errmsg\\", iconnection->errorString, sizeof(iconnection->errorString))) iconnection->errorString[0] = '\0'; #ifdef GSI_UNICODE // Update the UNICODE version UTF8ToUCS2String(iconnection->errorString, iconnection->errorString_W); #endif // Call the error callback? /////////////////////////// if(callErrorCallback) { GPIBool fatal = (GPIBool)(strstr(input, "\\fatal\\") != NULL); gpiCallErrorCallback(connection, GP_SERVER_ERROR, fatal ? GP_FATAL : GP_NON_FATAL); } return GPITrue; } return GPIFalse; } GPIBool gpiValueForKeyWithIndex( const char * command, const char * key, int * index, char * value, int len ) { char delimiter; const char * start; int i; char c; // Check for NULL. ////////////////// assert(command != NULL); assert(key != NULL); assert(value != NULL); assert(len > 0); // Find which char is the delimiter. //////////////////////////////////// delimiter = key[0]; // Find the key - first navigate to the index ///////////////////////////////////////////// command += *index; start = strstr(command, key); if(start == NULL) return GPIFalse; // Get to the start of the value. ///////////////////////////////// start += strlen(key); // Copy in the value. ///////////////////// len--; for(i = 0 ; (i < len) && ((c = start[i]) != '\0') && (c != delimiter) ; i++) { value[i] = c; } value[i] = '\0'; // Copy back current end point for index //////////////////////////////////////// *index += ((start - command) + strlen(value)); return GPITrue; } GPIBool gpiValueForKey( const char * command, const char * key, char * value, int len ) { char delimiter; const char * start; int i; char c; // Check for NULL. ////////////////// assert(command != NULL); assert(key != NULL); assert(value != NULL); assert(len > 0); // Find which char is the delimiter. //////////////////////////////////// delimiter = key[0]; // Find the key. //////////////// start = strstr(command, key); if(start == NULL) return GPIFalse; // Get to the start of the value. ///////////////////////////////// start += strlen(key); // Copy in the value. ///////////////////// len--; for(i = 0 ; (i < len) && ((c = start[i]) != '\0') && (c != delimiter) ; i++) { value[i] = c; } value[i] = '\0'; return GPITrue; } char * gpiValueForKeyAlloc( const char * command, const char * key ) { char delimiter; const char * start; char c; char * value; int len; // Check for NULL. ////////////////// assert(command != NULL); assert(key != NULL); // Find which char is the delimiter. //////////////////////////////////// delimiter = key[0]; // Find the key. //////////////// start = strstr(command, key); if(start == NULL) return NULL; // Get to the start of the value. ///////////////////////////////// start += strlen(key); // Find the key length. /////////////////////// for(len = 0 ; ((c = start[len]) != '\0') && (c != delimiter) ; len++) { }; // Allocate the value. ////////////////////// value = (char *)gsimalloc((unsigned int)len + 1); if(!value) return NULL; // Copy in the value. ///////////////////// memcpy(value, start, (unsigned int)len); value[len] = '\0'; return value; } GPResult gpiCheckSocketConnect( GPConnection * connection, SOCKET sock, int * state ) { int aWriteFlag = 0; int aExceptFlag = 0; int aReturnCode = 0; // Check if the connect is completed. ///////////////////////////////////// aReturnCode = GSISocketSelect(sock, NULL, &aWriteFlag, &aExceptFlag); if ( gsiSocketIsError(aReturnCode)) { gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_HotError, "Error connecting\n"); CallbackFatalError(connection, GP_NETWORK_ERROR, GP_NETWORK, "There was an error checking for a completed connection."); } if (aReturnCode > 0) { // Check for a failed attempt. ////////////////////////////// if(aExceptFlag) { gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_HotError, "Connection rejected\n"); *state = GPI_DISCONNECTED; return GP_NO_ERROR; } // Check for a successful attempt. ////////////////////////////////// if(aWriteFlag) { gsDebugFormat(GSIDebugCat_GP, GSIDebugType_Network, GSIDebugLevel_Notice, "Connection accepted\n"); *state = GPI_CONNECTED; return GP_NO_ERROR; } } // Not connected yet. ///////////////////// *state = GPI_NOT_CONNECTED; return GP_NO_ERROR; } GPResult gpiReadKeyAndValue( GPConnection * connection, const char * buffer, int * index, char key[512], char value[512] ) { int c; int i; char * start; assert(buffer != NULL); assert(key != NULL); assert(value != NULL); buffer += *index; start = (char *)buffer; if(*buffer++ != '\\') CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Parse Error."); for(i = 0 ; (c = *buffer++) != '\\' ; i++) { if(c == '\0') CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Parse Error."); if(i == 511) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Parse Error."); *key++ = (char)c; } *key = '\0'; for(i = 0 ; ((c = *buffer++) != '\\') && (c != '\0') ; i++) { if(i == 511) CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Parse Error."); *value++ = (char)c; } *value = '\0'; *index += (buffer - start - 1); return GP_NO_ERROR; } void gpiSetError( GPConnection * connection, GPErrorCode errorCode, const char * errorString ) { GPIConnection * iconnection = (GPIConnection*)*connection; // Copy the string. /////////////////// strzcpy(iconnection->errorString, errorString, GP_ERROR_STRING_LEN); #ifdef GSI_UNICODE // Update the unicode version UTF8ToUCS2StringLen(iconnection->errorString, iconnection->errorString_W, GP_ERROR_STRING_LEN); #endif // Set the code. //////////////// iconnection->errorCode = errorCode; } void gpiSetErrorString( GPConnection * connection, const char * errorString ) { GPIConnection * iconnection = (GPIConnection*)*connection; // Copy the string. /////////////////// strzcpy(iconnection->errorString, errorString, GP_ERROR_STRING_LEN); #ifdef GSI_UNICODE // Update the unicode version UTF8ToUCS2StringLen(iconnection->errorString, iconnection->errorString_W, GP_ERROR_STRING_LEN); #endif } void gpiEncodeString( const char * unencodedString, char * encodedString ) { size_t i; const int useAlternateEncoding = 1; // Encrypt the password (xor with random values) char passwordxor[GP_PASSWORD_LEN]; size_t passwordlen = strlen(unencodedString); Util_RandSeed((unsigned long)GP_XOR_SEED); for (i=0; i < passwordlen; i++) { // XOR each character with the next rand char aRand = (char)Util_RandInt(0, 0xFF); passwordxor[i] = (char)(unencodedString[i] ^ aRand); } passwordxor[i] = '\0'; // Base 64 it (printable chars only) B64Encode(passwordxor, encodedString, (int)passwordlen, useAlternateEncoding); } // Re-enable previously disabled compiler warnings /////////////////////////////////////////////////// #if defined(_MSC_VER) #pragma warning ( default: 4127 ) #endif // _MSC_VER