Message *Message_Decode(char *data, size_t len, struct PendingResponses *pending) { assert(data != NULL && "NULL data pointer"); BNode *dict = NULL; Message *message = calloc(1, sizeof(Message)); check_mem(message); dict = BDecode(data, len); if (dict == NULL || dict->type != BDictionary) { BNode_Destroy(dict); message->type = MUnknown; message->errors |= MERROR_UNKNOWN_TYPE; return message; } char y = GetMessageType(dict); int rc = 0; switch(y) { case 'q': rc = DecodeQuery(message, dict); check(rc == 0, "DecodeQuery failed"); break; case 'r': rc = DecodeResponse(message, dict, pending); check(rc == 0, "DecodeResponse failed"); break; case 'e': rc = DecodeError(message, dict); check(rc == 0, "DecodeError failed"); break; default: message->errors |= MERROR_UNKNOWN_TYPE; break; } BNode_Destroy(dict); return message; error: BNode_Destroy(dict); return NULL; }
void HandleClient(ConnectionPeer clientPeer, ConnectionPeer serverPeer, std::mutex &outputMutex) { bool close = false; size_t messageLength = 0; while (!close) { while ((messageLength = MessageLength(clientPeer.peek())) == 0) std::this_thread::yield(); std::chrono::system_clock::time_point before = std::chrono::system_clock::now(); std::string message = clientPeer.read(messageLength); serverPeer.write(message); close = (DecodeQuery(message).size() == 0); outputMutex.lock(); std::cout << "S_LB " << std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::system_clock::now() - before).count() << '\n'; outputMutex.unlock(); if (!close) { while ((messageLength = MessageLength(serverPeer.peek())) == 0) std::this_thread::yield(); before = std::chrono::system_clock::now(); message = serverPeer.read(messageLength); clientPeer.write(message); outputMutex.lock(); std::cout << "S_LB " << std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::system_clock::now() - before).count() << '\n'; outputMutex.unlock(); } } clientPeer.close(); serverPeer.close(); }
/** This version of DecodeMessageData() can NOT extract a 'v' region since the original string has already been parsed outside the scope of this object. */ void DHTMessage::DecodeMessageData(BencodedDict &bDict) { _bDictForUser = &bDict; // if not a dictionary, it's not a valid DHT RPC if(bDict.GetType() != BENC_DICT) { _parseSuccessful = false; dhtMessageType = DHT_UNDEFINED_MESSAGE; return; } _parseSuccessful = true; // extract the components common to all DHT messages transactionID.b = (byte*)bDict.GetString("t", &transactionID.len); version.b = (byte*)bDict.GetString("v", &version.len); external_ip.b = (byte*)bDict.GetString("ip", &external_ip.len); read_only = bDict.GetInt("ro", 0) != 0; type = bDict.GetString("y", 1); if (!type) return; switch(*type) { case 'q': { dhtMessageType = DHT_QUERY; DecodeQuery(bDict); break; } case 'r': { // Just extract the reply dictionary. Specific elements can be // extracted further down the call chain once it is known what // specific query this is a reply to. replyDict = bDict.GetDict("r"); if(replyDict){ id = (byte*)replyDict->GetString("id", DHT_ID_SIZE); dhtMessageType = DHT_RESPONSE; sequenceNum = replyDict->GetInt("seq", 1); vBuf.len = region.second - region.first; vBuf.b = region.first; signature.b = (byte*)replyDict->GetString("sig", &signature.len); key.b = (byte*)replyDict->GetString("k", &key.len); } else { dhtMessageType = DHT_UNDEFINED_MESSAGE; } break; } case 'e': { dhtMessageType = DHT_ERROR; DecodeError(bDict); break; } default: dhtMessageType = DHT_UNDEFINED_MESSAGE; } }