void BoshTransport::onConnectReply (Error result, const HttpResponsePtr & response, const ResultCallback & callback) { if (mState != Connecting) { Log (LogError) << LOGID << "Strange state " << toString (mState) << std::endl; return; } if (result) { return failConnect (result, callback, "error on http connect"); } if (!(response->resultCode == 200)) return failConnect (error::ConnectionError, callback, String ("bad http result=" + toString (response->resultCode)).c_str()); mAuthenticated = response->authenticated; BoshNodeParser parser; Error e = parser.parse(response->data->const_c_array(), response->data->size()); if (e) { return failConnect (e, callback, "parse"); } mSid = parser.attribute("sid"); if (mSid.empty()){ return failConnect (error::BadProtocol, callback, "parse"); } String wait = parser.attribute("wait"); if (wait.empty()){ Log (LogWarning) << LOGID << "Server did not respond with wait attribute!" << std::endl; // workaround. wait is mandatory, but at least the local Prosody instance does not send it // http://code.google.com/p/lxmppd/issues/detail?id=219 mLongPollTimeoutMs = 60000; } else { try { mLongPollTimeoutMs = boost::lexical_cast<int> (wait) * 1000; } catch (boost::bad_lexical_cast & e){ return failConnect (error::BadProtocol, callback, "bad wait response"); } } String type = parser.attribute ("type"); if (!type.empty()) { // error or terminate return failConnect (error::CouldNotConnectHost, callback, String ("opponent sent type=" + type).c_str()); } mState = Connected; String content = parser.content(); if (!content.empty()){ mInputBuffer.append(content.c_str(), content.length()); Log (LogInfo) << LOGID << "Server sent " << content.length() << " bytes on session create response" << std::endl; } mRidRecv++; // cannot receive first message out of order. asyncNotify (callback, NoError); // initial pending request continueWorking (); if (mChanged) { xcall (mChanged); } }
void BoshTransport::onRequestReply (Error result, const HttpResponsePtr & response, int64_t rid, const ResultCallback & originalCallback) { Log (LogInfo) << LOGID << "Reply of RID " << rid << ":" << toString (result) << " (" << (response ? response->resultCode : 0) << ")" << std::endl; if (mState != Connected && mState != Closing){ if (mState != Unconnected) Log (LogWarning) << LOGID << "Strange state" << std::endl; return; } if (mAuthenticated && !response->authenticated){ Log (LogWarning) << LOGID << "Lost authentication status" << std::endl; return failRequest (error::AuthError, rid, "Lost authentication", originalCallback); } if (result || response->resultCode != 200) { // Recovering from errors if (result) Log (LogWarning) << LOGID << "Got HTTP error " << toString (result) << std::endl; else if (response->resultCode != 200) Log (LogWarning) << LOGID << "Got bad HTTP result code " << response->resultCode << std::endl; mErrorCount++; mSumErrorCount++; if (mErrorCount > mMaxErrorCount) { return failRequest (result, rid, "To many HTTP errors", originalCallback); } // Try it again sf::ByteArrayPtr data = mOpenRids[rid]; assert (data); Log (LogInfo) << LOGID << "Try to recover (ErrCnt=" << mErrorCount << " SucCnt=" << mSuccessCount << ")" << std::endl; return executeRequest (data, mLongPollTimeoutMs, abind (dMemFun (this, &BoshTransport::onRequestReply), rid, originalCallback)); } mSuccessCount++; if (mErrorCount > 0) mErrorCount--; // so we can recover from errors BoshNodeParser parser; Error e = parser.parse(response->data->const_c_array(), response->data->size()); if (e) { return failRequest (e, rid, "Parse error", originalCallback); } mOpenRids.erase(rid); mOpenRidCount--; mInWaitingRids[rid] = sf::createByteArrayPtr (parser.content()); if (!parser.attribute ("type").empty()){ // server sent terminate or something failRequest (error::Eof, rid, String ("Server sent type=" ) + parser.attribute ("type"), originalCallback); } else { notifyAsync (originalCallback, NoError); } insertWaitingInputData (); /// some braking sf::xcallTimed(dMemFun (this, &BoshTransport::continueWorking), sf::futureInMs(mReconnectWaitMs)); if (mChanged) xcall (mChanged); }
int testNodeBuildAndParse () { BoshNodeBuilder builder; builder.addAttribute("hello", "world"); builder.addAttribute("and", "anotherone"); builder.addContent (sf::createByteArrayPtr ("<bla>Hi dude</bla>")); builder.addContent (sf::createByteArrayPtr ("<bli></bli>")); String s = builder.toString(); printf ("Serialized code: %s\n", s.c_str()); BoshNodeParser parser; Error e = parser.parse(s); tcheck1(!e); tcheck1(parser.attribute("hello") == "world"); tcheck1(parser.attribute("and") == "anotherone"); String back = parser.content(); XMLChunk chunk = xml::parseDocument(back.c_str(), back.length()); tcheck1 (chunk.getChild("bla").text() == "Hi dude"); tcheck1 (chunk.getHasChild("bli")); return 0; }