char *readStreamUpToTagAndGetToken( InputStream *inInputStream, char *inTag, int inMaxCharsToRead, int inTokenNumber ) { // read the string char *readString = readStreamUpToTag( inInputStream, inTag, inMaxCharsToRead ); if( readString == NULL ) { return NULL; } SimpleVector<char *> *readTokens = tokenizeString( readString ); delete [] readString; // second token should be their key char *selectedToken = NULL; int numTokens = readTokens->size(); if( numTokens > inTokenNumber ) { selectedToken = stringDuplicate( *( readTokens->getElement( inTokenNumber ) ) ); } else { char *message = autoSprintf( "Looking for token %d, but only %d tokens available\n", inTokenNumber, numTokens ); AppLog::error( "readStreamUpToTagAndGetToken", message ); } for( int i=0; i<numTokens; i++ ) { delete [] *( readTokens->getElement( i ) ); } delete readTokens; // will be NULL if not enough tokens read return selectedToken; }
void ChannelReceivingThread::run () { AppLog::detail (mLoggerName, "Starting up."); char correctMessageReceived = true; // first, receive the incoming host list // read up to the first occurrence of "EndHostList", allowing 10,000 // characters char *readListBuffer = readStreamUpToTag (mInputStream, "EndHostList", 10000); if (readListBuffer != NULL) { AppLog::trace (mLoggerName, readListBuffer); // tokenize it SimpleVector < char *>*tokenVector; if(settings->getAcceptSeedNodes()) { tokenVector = tokenizeString (readListBuffer); } else { AppLog::detail(mLoggerName, "Host List received is ignored for user settings"); tokenVector= new SimpleVector<char *>(); } delete[]readListBuffer; int numTokens = tokenVector->size (); // count should be second token, so skip first two int i; for (i = 2; i < numTokens - 1; i += 2) { char *addressString = *(tokenVector->getElement (i)); char *portString = *(tokenVector->getElement (i + 1)); int port; int numRead = sscanf (portString, "%d", &port); if (numRead == 1) { HostAddress *address = new HostAddress (stringDuplicate (addressString), port); mHostCatcher->addHost (address); delete address; } } for (i = 0; i < numTokens; i++) { delete[] * (tokenVector->getElement (i)); } delete tokenVector; } else { AppLog::error (mLoggerName, "Failed to receive host list."); correctMessageReceived = false; } // check for an accpeted connection status char connectionAccepted = false; if (correctMessageReceived) { correctMessageReceived = false; // next, receive the connection status char *readStatusBuffer = readStreamUpToTag (mInputStream, "EndConnectionStatus", 1000); if (readStatusBuffer != NULL) { AppLog::trace (mLoggerName, readStatusBuffer); // tokenize it SimpleVector < char *>*tokenVector = tokenizeString (readStatusBuffer); delete[]readStatusBuffer; int numTokens = tokenVector->size (); if (numTokens > 2) { // second token is status char *status = *(tokenVector->getElement (1)); if (strcmp (status, "Accepted") == 0) { connectionAccepted = true; correctMessageReceived = true; // we are actually connected now AppLog::info (mLoggerName, "Connection accepted by remote host."); // log it, if needed int logConnectionsFlag = settings->getLogConnectionsSetting(); if (logConnectionsFlag == 1) { FILE *connectionLogFILE = fopen ("connectionHistory.log", "a"); if (connectionLogFILE != NULL) { fprintf (connectionLogFILE, "%s : %d\n", mRemoteAddress, mRemotePort); fclose (connectionLogFILE); } } } else if (strcmp (status, "Rejected") == 0) { connectionAccepted = false; correctMessageReceived = true; AppLog::info (mLoggerName, "Connection rejected by remote host."); } } for (int i = 0; i < numTokens; i++) { delete[] * (tokenVector->getElement (i)); } delete tokenVector; } if (!correctMessageReceived) { AppLog::error (mLoggerName, "Failed to receive connection status."); } } // now read a series of MUTE messages mLock->lock (); char stopped = mStopSignal; mLock->unlock (); int badMessageReceived=0; while (!stopped && badMessageReceived<3 && connectionAccepted) { // read a message correctMessageReceived = false; // read up to the first occurrence of "Body:" char *readCharBuffer = readStreamUpToTag (mInputStream, "Body:", 5000); if (readCharBuffer != NULL) { const char *posBody=strstr("Body:",readCharBuffer); int lenHeader; if(posBody) lenHeader = posBody-readCharBuffer+5; else lenHeader = strlen(readCharBuffer); TotBytesReceived += lenHeader; mLimiter->bytesTransmitted (lenHeader); // buffer ends with "Body:" plus terminating character AppLog::detail (mLoggerName, "Got header"); AppLog::trace (mLoggerName, readCharBuffer); // tokenize it SimpleVector < char *>*tokenVector = tokenizeString (readCharBuffer); char *messageID = NULL; char *fromAddress = NULL; char *toAddress = NULL; char *flags = NULL; int utilityCounter = 0; int payloadLength = -1; char *dataPayload = NULL; int numTokens = tokenVector->size (); int i; for (i = 0; i < numTokens - 1; i++) { char *currentToken = *(tokenVector->getElement (i)); char *nextToken = *(tokenVector->getElement (i + 1)); if (strcmp (currentToken, "UniqueID:") == 0) { messageID = stringDuplicate (nextToken); } else if (strcmp (currentToken, "From:") == 0) { fromAddress = stringDuplicate (nextToken); } else if (strcmp (currentToken, "To:") == 0) { toAddress = stringDuplicate (nextToken); } else if (strcmp (currentToken, "Flags:") == 0) { flags = stringDuplicate (nextToken); } else if (strcmp (currentToken, "UtilityCounter:") == 0) { sscanf (nextToken, "%d", &utilityCounter); } else if (strcmp (currentToken, "Length:") == 0) { sscanf (nextToken, "%d", &payloadLength); } } // destroy vector for (i = 0; i < numTokens; i++) { delete[] * (tokenVector->getElement (i)); } delete tokenVector; if (messageID != NULL && fromAddress != NULL && toAddress != NULL && flags != NULL && payloadLength > 0) { // all header items read correctly // make sure payload not too big if (payloadLength <= 32768) { dataPayload = new char[payloadLength + 1]; int numRead = mInputStream->read ((unsigned char *) dataPayload, payloadLength); TotBytesReceived += numRead; // terminate payload string if (numRead > 0 && numRead <= payloadLength) { dataPayload[numRead] = '\0'; } else { dataPayload[payloadLength] = '\0'; } if (numRead == payloadLength) { // we've already traced the header AppLog::trace (mLoggerName, dataPayload); correctMessageReceived = true; TotMessagesReceived ++; if (strcmp (toAddress, "ALL") == 0) TotMessagesToAll++; // message formatted correctly, // so process it // obey the limit // we will block here if message rate is too high mLimiter->bytesTransmitted (numRead); // process the message //printf( "Registering received ID %s\n", messageID ); char fresh = mMessageIDTracker->checkIfIDFresh (messageID); if (fresh) { AppLog::detail (mLoggerName, "Message fresh."); } else { AppLog::detail (mLoggerName, "Message stale."); } // only do work of processing flags for fresh // messages // we might drop a fresh message based on flags char ignoreUC = false; char dropMessage = false; if (fresh) { char *newFlags = processFlags (messageID, fromAddress, flags, &ignoreUC, &dropMessage, mLoggerName); delete[]flags; flags = newFlags; if (dropMessage) { AppLog::detail (mLoggerName, "Dropping message based on flags."); } } // ignore messages that are not fresh // or that should be dropped according to flags. if (fresh && !dropMessage) { if (strstr (flags, "FRESH_ROUTE") != NULL) { // clear the routing information in both // directions mOutboundChannelManager-> clearRoutingInformation (fromAddress); mOutboundChannelManager-> clearRoutingInformation (toAddress); } // add new back-routing information mOutboundChannelManager-> addRoutingInformation (fromAddress, mOutboundChannel); int generatedUtility = 0; char receivedLocally; if (strstr (flags, "DROP_TTL") != NULL) { // don't locally-process DROP_TTL messages receivedLocally = false; } else { receivedLocally = mReceiver->messageReceived (fromAddress, toAddress, dataPayload, &generatedUtility); } if (receivedLocally) { AppLog::detail (mLoggerName, "Message consumed locally."); } // check this even if ignoring UCs if (utilityCounter < -mMaxUtilityCounter) { // correct negative utility counters utilityCounter = -mMaxUtilityCounter + mRandSource->getRandomBoundedInt (0, 6); } // we might generate utility for any message // type, either routed or broadcast (ALL), // that we do not consume locally if (!ignoreUC) { // add in our weighted, generated utility utilityCounter += mUtilityAlpha * generatedUtility; } // if we didn't consume message locally // or if message is a broadcast if (!receivedLocally || strcmp (toAddress, "ALL") == 0) { if (strcmp (toAddress, "ALL") == 0) { if (!ignoreUC) { // for ALL messages, also add in // the weighted (beta) branching // factor at this node and the // (gamma) constant factor int numNeighbors = mOutboundChannelManager-> getConnectionCount (); // we won't send to the neighbor that // sent the message to us int branchFactor = numNeighbors - 1; int deltaUtility = mUtilityBeta * branchFactor + mUtilityGamma + mRandSource->getRandomBoundedInt (-6, 0); if (deltaUtility < 1) deltaUtility = 1; utilityCounter += deltaUtility; } } if (!ignoreUC && utilityCounter > mMaxUtilityCounter) { // we have pushed the UC over the top // switch the message into DROP_CHAIN // mode to start the drop tail // the OutboundChannelManager will handle // the chaining and the side DROP_TTL // trees when it sees the DROP_CHAIN flag char *tempFlags = muteAddFlag (flags, "DROP_CHAIN"); delete[]flags; flags = tempFlags; AppLog::detail (mLoggerName, "Message switched into DROP_CHAIN " " mode because its" " utility is too high."); // if we switch a message into DROP_CHAIN // mode, we should pass it to the // OutboundChannelManager even if // the number of neighbors that we send // DROP_CHAIN messages to is 0. // In these cases, we will be sending // DROP_TTL messages to all neighbors. // We must do this because we have // already processed the message above // before we decide to change it into // DROP_CHAIN mode. If we simply // drop it at this point, our neighbors // could tell that we didn't send out // any DROP_TTL message (and therefore // that we weren't passing the DROP_CHAIN // message on to any neighbors). They // could be sure the results they see // are coming from us. } if (!dropMessage) { // route it // this manager will pay attention // to flags when routing. mOutboundChannelManager-> routeMessage (messageID, fromAddress, toAddress, flags, utilityCounter, dataPayload, mOutboundChannel); AppLog::detail (mLoggerName, "Message routed onward."); } } } } else { AppLog::error (mLoggerName, "Failed to read message data payload"); } } else { AppLog::error (mLoggerName, "Failed to read message payload too long"); } } else { if (messageID == NULL ) AppLog::error (mLoggerName, "No Message ID"); else if ( fromAddress == NULL ) AppLog::error (mLoggerName, "No From Address"); else if ( toAddress == NULL ) AppLog::error (mLoggerName, "No To Address"); else if ( flags == NULL ) AppLog::error (mLoggerName, "No Flags"); else AppLog::error (mLoggerName, "Payload length negative"); } // clean up, whether correct message was received or not if (messageID != NULL) { delete[]messageID; } if (fromAddress != NULL) { delete[]fromAddress; } if (toAddress != NULL) { delete[]toAddress; } if (flags != NULL) { delete[]flags; } if (dataPayload != NULL) { delete[]dataPayload; } delete[]readCharBuffer; } if (correctMessageReceived) { // AppLog::detail (mLoggerName, "Correct message received"); badMessageReceived=0; } else { AppLog::warning (mLoggerName, "Bad message received"); badMessageReceived++; } mLock->lock (); stopped = mStopSignal; mLock->unlock (); } // TODO // however we got here, we should perhaps remove the host from the catcher // (rejected our connection, broke the connection, sent a bad message, // dropped too many messages) // or immediately retry connect if it was a good host.... // HostAddress *remoteHost = new HostAddress (stringDuplicate (mRemoteAddress), // mRemotePort); // mHostCatcher->noteHostBad (remoteHost); // delete remoteHost; // let channel manager know that channel has been broken mOutboundChannelManager->channelBroken (mOutboundChannel); // cast to true type ConnectionMaintainer *maintainer = (ConnectionMaintainer *) mConnectionMaintainer; maintainer->connectionBroken (); // destroy the socket using the manager SocketManager::destroySocket (mSocket); mLock->lock (); mFinished = true; mLock->unlock (); }