unsigned int httpParseResponseHdr(WspHttpParms_t *parmPtr, const char *rspHeader) { unsigned int rc = SML_ERR_OK; XPTDEBUG((" httpParseResponseHdr(%lx, %s)\n", (unsigned long) parmPtr, rspHeader)); rc = initializeResponseParms(parmPtr, rspHeader); if (rc != SML_ERR_OK) return rc; rc = validateResponse(parmPtr); return rc; } /* End httpParseResponseHdr */
void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_params) { try { LLSD printable_params = login_params; //if(printable_params.has("params") // && printable_params["params"].has("passwd")) //{ // printable_params["params"]["passwd"] = "*******"; //} LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self) << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL; // Arriving in SRVRequest state LLEventStream replyPump("SRVreply", true); // Should be an array of one or more uri strings. LLSD rewrittenURIs; { LLEventTimeout filter(replyPump); sendProgressEvent("offline", "srvrequest"); // Request SRV record. LL_DEBUGS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL; // *NOTE:Mani - Completely arbitrary default timeout value for SRV request. F32 seconds_to_timeout = 5.0f; if(login_params.has("cfg_srv_timeout")) { seconds_to_timeout = login_params["cfg_srv_timeout"].asReal(); } // If the SRV request times out (e.g. EXT-3934), simulate response: an // array containing our original URI. LLSD fakeResponse(LLSD::emptyArray()); fakeResponse.append(uri); filter.eventAfter(seconds_to_timeout, fakeResponse); std::string srv_pump_name = "LLAres"; if(login_params.has("cfg_srv_pump")) { srv_pump_name = login_params["cfg_srv_pump"].asString(); } // Make request LLSD request; request["op"] = "rewriteURI"; request["uri"] = uri; request["reply"] = replyPump.getName(); rewrittenURIs = postAndWait(self, request, srv_pump_name, filter); } // we no longer need the filter LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); // EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used // to share them -- but the EXT-3934 fix made it possible for an abandoned // SRV response to arrive just as we were expecting the XMLRPC response. LLEventStream loginReplyPump("loginreply", true); // Loop through the rewrittenURIs, counting attempts along the way. // Because of possible redirect responses, we may make more than one // attempt per rewrittenURIs entry. LLSD::Integer attempts = 0; for (LLSD::array_const_iterator urit(rewrittenURIs.beginArray()), urend(rewrittenURIs.endArray()); urit != urend; ++urit) { LLSD request(login_params); request["reply"] = loginReplyPump.getName(); request["uri"] = *urit; std::string status; // Loop back to here if login attempt redirects to a different // request["uri"] for (;;) { ++attempts; LLSD progress_data; progress_data["attempt"] = attempts; progress_data["request"] = request; if(progress_data["request"].has("params") && progress_data["request"]["params"].has("passwd")) { progress_data["request"]["params"]["passwd"] = "*******"; } sendProgressEvent("offline", "authenticating", progress_data); // We expect zero or more "Downloading" status events, followed by // exactly one event with some other status. Use postAndWait() the // first time, because -- at least in unit-test land -- it's // possible for the reply to arrive before the post() call // returns. Subsequent responses, of course, must be awaited // without posting again. for (mAuthResponse = validateResponse(loginReplyPump.getName(), postAndWait(self, request, xmlrpcPump, loginReplyPump, "reply")); mAuthResponse["status"].asString() == "Downloading"; mAuthResponse = validateResponse(loginReplyPump.getName(), waitForEventOn(self, loginReplyPump))) { // Still Downloading -- send progress update. sendProgressEvent("offline", "downloading"); } LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL; status = mAuthResponse["status"].asString(); // Okay, we've received our final status event for this // request. Unless we got a redirect response, break the retry // loop for the current rewrittenURIs entry. if (!(status == "Complete" && mAuthResponse["responses"]["login"].asString() == "indeterminate")) { break; } sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]); // Here the login service at the current URI is redirecting us // to some other URI ("indeterminate" -- why not "redirect"?). // The response should contain another uri to try, with its // own auth method. request["uri"] = mAuthResponse["responses"]["next_url"].asString(); request["method"] = mAuthResponse["responses"]["next_method"].asString(); } // loop back to try the redirected URI // Here we're done with redirects for the current rewrittenURIs // entry. if (status == "Complete") { // StatusComplete does not imply auth success. Check the // actual outcome of the request. We've already handled the // "indeterminate" case in the loop above. if (mAuthResponse["responses"]["login"].asString() == "true") { sendProgressEvent("online", "connect", mAuthResponse["responses"]); } else { sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]); } return; // Done! } // If we don't recognize status at all, trouble if (! (status == "CURLError" || status == "XMLRPCError" || status == "OtherError")) { LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: " << mAuthResponse << LL_ENDL; return; } // Here status IS one of the errors tested above. } // Retry if there are any more rewrittenURIs. // Here we got through all the rewrittenURIs without succeeding. Tell // caller this didn't work out so well. Of course, the only failure data // we can reasonably show are from the last of the rewrittenURIs. // *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an // llsd with no "responses" node. To make the output from an incomplete login symmetrical // to success, add a data/message and data/reason fields. LLSD error_response; error_response["reason"] = mAuthResponse["status"]; error_response["errorcode"] = mAuthResponse["errorcode"]; error_response["message"] = mAuthResponse["error"]; if(mAuthResponse.has("certificate")) { error_response["certificate"] = mAuthResponse["certificate"]; } sendProgressEvent("offline", "fail.login", error_response); } catch (...) { llerrs << "login exception caught" << llendl; } }
int CommsHandler::process(uint8_t *responseBuffer, uint16_t responseBufferLen) { if (commsPtr == NULL) { errno = errorCommsNotSet; return false; } bool validResponse = false; errno = errorNoError; commsPtr->poll(); switch (state) { case stateWaitingForMessages: if (!stack.isEmpty()) { messageLen = stack.read(messageBuffer, messageBufferLen); if (messageLen) { bytesSent = 0; state = statePowerUp; if (commsBlockSize) { // Append null characters to fill a complete block // const uint8_t xrfBlockSize = 12; uint8_t remainder = messageLen % commsBlockSize; if (remainder) { uint16_t newLen = messageLen + (commsBlockSize - remainder); if (newLen <= messageBufferLen) { memset(messageBuffer + messageLen, 0, commsBlockSize - remainder); messageLen = newLen; } } } } } break; case statePowerUp: if (commsPtr->powerOn()) state = sendingData; break; case sendingData: // Send each byte individually. At present // HardwareSerial.write() waits until the buffer has room but // in future it might return immediately with a return value of // zero. if (bytesSent == 0 && verbosity) AWPacket::printPacket(messageBuffer, messageLen, console); if (bytesSent == 0) commsPtr->messageStart(); { size_t bytesToSend = commsPtr->messageWriteSize(); if (bytesToSend == 0) bytesToSend = messageLen; bytesSent += commsPtr->write(messageBuffer + bytesSent, bytesToSend); } if (bytesSent == messageLen) { commsPtr->messageEnd(); responseLen = 0; responseTimeout.start(responseTimeout_ms, AsyncDelay::MILLIS); responsePacketLen = 65535; // Use maximum value until we know state = stateWaitingForResponse; } break; case stateWaitingForResponse: if (responseTimeout.isExpired()) { Serial.println("Message timeout"); errno = errorResponseTimeout; ++ messagesWithoutAck; uint8_t maxMessagesNoAck = eeprom_read_byte((uint8_t*)EEPROM_MAX_MESSAGES_NO_ACK); if (maxMessagesNoAck && messagesWithoutAck >= maxMessagesNoAck) { Serial.println("Reboot due to timeout"); // DEBUG delay(1000); xboot_reset(); //wdt_enable(WDTO_1S); //while (1) // ; } // Put message back into queue if retries not exceeded AWPacket failedPacket(messageBuffer, messageLen); if (failedPacket.getRetries() < maxRetries) { failedPacket.incrementRetries(); // Update the signature for new retries failedPacket.setKey(key, keyLen); failedPacket.putSignature(messageBuffer, messageBufferLen); messageLen = 0; stack.write(messageBuffer, AWPacket::getPacketLength(messageBuffer)); } else { Serial.print("Too many retries: "); AWPacket::printPacket(messageBuffer, messageBufferLen, Serial); } state = stateTimedOut; break; } commsPtr->checkForResponse(); if (int avail = commsPtr->available()) { if (responseLen >= responseBufferLen) { errno = errorBufferTooSmall; messageLen = 0; state = stateWaitingForMessages; break; } for (int i = avail; i; --i) { uint8_t b = commsPtr->read(); responseBuffer[responseLen++] = b; } if (validateResponse(responseBuffer, responseLen)) { // The response in the buffer is valid, but is it a response // to our last message? uint32_t messageSeconds, responseSeconds; uint16_t messageFraction, responseFraction; AWPacket::getTimestamp(messageBuffer, messageSeconds, messageFraction); AWPacket::getTimestamp(responseBuffer, responseSeconds, responseFraction); if ((AWPacket::getSiteId(responseBuffer) == AWPacket::getSiteId(messageBuffer)) && (messageSeconds == responseSeconds) && (messageFraction == responseFraction) && (AWPacket::getSequenceId(responseBuffer) == AWPacket::getSequenceId(messageBuffer)) && (AWPacket::getRetries(responseBuffer) == AWPacket::getRetries(messageBuffer))) { // Valid response found validResponse = true; messageLen = 0; state = stateWaitingForMessages; } else { // Need another response Serial.println("######################"); Serial.println("Packet valid but incorrect response"); AWPacket::printPacket(responseBuffer, responseLen, Serial); Serial.println("######################"); responseLen = 0; responsePacketLen = 65535; // Use maximum value until we know } } } break; case stateTimedOut: // Stuck here until a new message is added break; } return validResponse; }