GPResult gpiSendBufferToPeer(GPConnection * connection, unsigned int ip, unsigned short port, GPIBuffer * outputBuffer, GPIBool *closed, GPIBool clipSentData) { GPIConnection *iconnection = (GPIConnection *)*connection; //GPIBool closed; unsigned int remaining; unsigned char * buffer; unsigned int pos; unsigned int len; unsigned int total = 0; GSUdpPeerState aPeerState; assert(outputBuffer != NULL); buffer = (unsigned char *)outputBuffer->buffer; len = (unsigned int)outputBuffer->len; pos = (unsigned int)outputBuffer->pos; remaining = (len - pos); // Check for nothing to send. ///////////////////////////// if(remaining == 0) return GP_NO_ERROR; // length of message remaining must be smaller than total buffer size minus gt2 reliable msg header size minus // in order to send the message in one shot. if ((int)remaining <= (gsUdpEngineGetPeerOutBufferFreeSpace(ip, port) - GS_UDP_RELIABLE_MSG_HEADER - GS_UDP_MSG_HEADER_LEN)) { gsUdpEngineSendMessage(ip, port, iconnection->mHeader, &buffer[pos], remaining, gsi_true); total = remaining; remaining = 0; } else { unsigned int freeSpace =0; unsigned int sendAmount = 0; do { freeSpace = (unsigned int)gsUdpEngineGetPeerOutBufferFreeSpace(ip, port); sendAmount = freeSpace - (GS_UDP_MSG_HEADER_LEN + GS_UDP_RELIABLE_MSG_HEADER); if (sendAmount <= (GS_UDP_MSG_HEADER_LEN + GS_UDP_RELIABLE_MSG_HEADER)) break; if (gsUdpEngineSendMessage(ip, port, iconnection->mHeader, &buffer[pos+total], sendAmount, gsi_true) == GS_UDP_SEND_FAILED) break; total += sendAmount; remaining -= sendAmount; }while (remaining); } if(clipSentData) { if (total > 0) { memmove(buffer, &buffer[total], remaining + 1); len -= total; } } else { pos += total; } // Set outputs. /////////////// outputBuffer->len = (int)len; outputBuffer->pos = (int)pos; gsUdpEngineGetPeerState(ip, port, &aPeerState); if (aPeerState == GS_UDP_PEER_CLOSED) *closed = GPITrue; else *closed = GPIFalse; 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; }
//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 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; }
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; }