bool ARTSPConnection::parseAuthMethod(const sp<ARTSPResponse> &response) { ssize_t i = response->mHeaders.indexOfKey("www-authenticate"); if (i < 0) { return false; } AString value = response->mHeaders.valueAt(i); if (!strncmp(value.c_str(), "Basic", 5)) { mAuthType = BASIC; } else { #if !defined(HAVE_ANDROID_OS) // We don't have access to the MD5 implementation on the simulator, // so we won't support digest authentication. return false; #endif CHECK(!strncmp(value.c_str(), "Digest", 6)); mAuthType = DIGEST; i = value.find("nonce="); CHECK_GE(i, 0); CHECK_EQ(value.c_str()[i + 6], '\"'); ssize_t j = value.find("\"", i + 7); CHECK_GE(j, 0); mNonce.setTo(value, i + 7, j - i - 7); } return true; }
bool ARTSPConnection::receiveRTSPRequest() { AString requestLine; LOGI(LOG_TAG,"start receiveLine ......\n"); if (!receiveLine(&requestLine)) { return false; } // LOGI(LOG_TAG,"receiveLine OK\n"); sp<AMessage> request = new AMessage(kWhatRequest,mhandlerID); request->setInt32("SessionID",mSessionID); LOGI(LOG_TAG,"request->setInt32 SessionID %d\n",mSessionID); LOGI(LOG_TAG,"request: %s\n", requestLine.c_str()); ssize_t space1 = requestLine.find(" ");//寻找空格 if (space1 < 0) { return false; } ssize_t space2 = requestLine.find(" ", space1 + 1); if (space2 < 0) { return false; } AString Method(requestLine.c_str(), space1); request->setString("Method",Method.c_str()); AString URI(requestLine,space1+1,space2-space1-1); request->setString("URI",URI.c_str()); AString line; for (;;) { if (!receiveLine(&line)) { break; } if (line.empty()) { break; } ssize_t colonPos = line.find(":"); if (colonPos < 0) { // Malformed header line. return false; } AString key(line, 0, colonPos); key.trim(); // key.tolower(); line.erase(0, colonPos + 1); line.trim(); LOGI(LOG_TAG,"line: %s:%s\n", key.c_str(),line.c_str()); request->setString(key.c_str(),line.c_str()); } LOGI(LOG_TAG,"Post the request to handler\n"); request->post();//将请求消息发送给uplayer 处理 return OK; }
static void GetMethodAndURL( const AString &request, AString *method, AString *url) { ssize_t space1 = request.find(" "); CHECK_GE(space1, 0); ssize_t space2 = request.find(" ", space1 + 1); CHECK_GE(space2, 0); method->setTo(request, 0, space1); url->setTo(request, space1 + 1, space2 - space1); }
// static status_t M3UParser::parseStreamInf( const AString &line, sp<AMessage> *meta) { ssize_t colonPos = line.find(":"); if (colonPos < 0) { return ERROR_MALFORMED; } size_t offset = colonPos + 1; while (offset < line.size()) { ssize_t end = line.find(",", offset); if (end < 0) { end = line.size(); } AString attr(line, offset, end - offset); attr.trim(); offset = end + 1; ssize_t equalPos = attr.find("="); if (equalPos < 0) { continue; } AString key(attr, 0, equalPos); key.trim(); AString val(attr, equalPos + 1, attr.size() - equalPos - 1); val.trim(); LOGV("key=%s value=%s", key.c_str(), val.c_str()); if (!strcasecmp("bandwidth", key.c_str())) { const char *s = val.c_str(); char *end; unsigned long x = strtoul(s, &end, 10); if (end == s || *end != '\0') { // malformed continue; } if (meta->get() == NULL) { *meta = new AMessage; } (*meta)->setInt32("bandwidth", x); } } return OK; }
static void GetMethodAndURL( const AString &request, AString *method, AString *url) { ssize_t space1 = request.find(" "); CHECK_GE(space1, 0); ssize_t space2 = request.find(" ", space1 + 1); CHECK_GE(space2, 0); method->setTo(request, 0, space1); #ifndef ANDROID_DEFAULT_CODE url->setTo(request, space1 + 1, space2 - space1 - 1); #else url->setTo(request, space1 + 1, space2 - space1); #endif // #ifndef ANDROID_DEFAULT_CODE }
bool ARTPSession::validateMediaFormat(size_t index, unsigned *port) const { AString format; mDesc->getFormat(index, &format); ssize_t i = format.find(" "); if (i < 0) { return false; } ++i; size_t j = i; while (isdigit(format.c_str()[j])) { ++j; } if (format.c_str()[j] != ' ') { return false; } AString portString(format, i, j - i); char *end; unsigned long x = strtoul(portString.c_str(), &end, 10); if (end == portString.c_str() || *end != '\0') { return false; } if (x == 0 || x > 65535) { return false; } *port = x; return true; }
void cBrewingRecipes::ReloadRecipes(void) { ClearRecipes(); LOGD("Loading brewing recipes..."); std::ifstream f(BREWING_RECIPE_FILE, std::ios::in); if (!f.good()) { LOG("Could not open the brewing recipes file \"%s\". No brewing recipes are available.", BREWING_RECIPE_FILE); return; } unsigned int LineNum = 0; AString ParsingLine; while (std::getline(f, ParsingLine)) { LineNum++; // Remove comments from the line: size_t FirstCommentSymbol = ParsingLine.find('#'); if (FirstCommentSymbol != AString::npos) { ParsingLine.erase(ParsingLine.begin() += static_cast<long>(FirstCommentSymbol), ParsingLine.end()); } if (ParsingLine.empty()) { continue; } AddRecipeFromLine(ParsingLine, LineNum); } // while (getline(ParsingLine)) LOG("Loaded " SIZE_T_FMT " brewing recipes", m_pState->Recipes.size()); }
bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2) { ssize_t pos = s.find(delimiter.c_str()); if (pos < 0) { return false; } *s1 = AString(s, 0, pos); *s2 = AString(s, pos + 1, s.size() - pos - 1); return true; }
// static status_t M3UParser::parseByteRange( const AString &line, uint64_t curOffset, uint64_t *length, uint64_t *offset) { ssize_t colonPos = line.find(":"); if (colonPos < 0) { return ERROR_MALFORMED; } ssize_t atPos = line.find("@", colonPos + 1); AString lenStr; if (atPos < 0) { lenStr = AString(line, colonPos + 1, line.size() - colonPos - 1); } else { lenStr = AString(line, colonPos + 1, atPos - colonPos - 1); } lenStr.trim(); const char *s = lenStr.c_str(); char *end; *length = strtoull(s, &end, 10); if (s == end || *end != '\0') { return ERROR_MALFORMED; } if (atPos >= 0) { AString offStr = AString(line, atPos + 1, line.size() - atPos - 1); offStr.trim(); const char *s = offStr.c_str(); *offset = strtoull(s, &end, 10); if (s == end || *end != '\0') { return ERROR_MALFORMED; } } else { *offset = curOffset; } return OK; }
void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) { sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); if (mState != CONNECTED) { reply->setInt32("result", -ENOTCONN); reply->post(); return; } AString request; CHECK(msg->findString("request", &request)); // Find the boundary between headers and the body. ssize_t i = request.find("\r\n\r\n"); CHECK_GE(i, 0); int32_t cseq = mNextCSeq++; AString cseqHeader = "CSeq: "; cseqHeader.append(cseq); cseqHeader.append("\r\n"); request.insert(cseqHeader, i + 2); LOGV("%s", request.c_str()); size_t numBytesSent = 0; while (numBytesSent < request.size()) { ssize_t n = send(mSocket, request.c_str() + numBytesSent, request.size() - numBytesSent, 0); if (n == 0) { // Server closed the connection. LOGE("Server unexpectedly closed the connection."); reply->setInt32("result", ERROR_IO); reply->post(); return; } else if (n < 0) { if (errno == EINTR) { continue; } LOGE("Error sending rtsp request."); reply->setInt32("result", -errno); reply->post(); return; } numBytesSent += (size_t)n; } mPendingRequests.add(cseq, reply); }
void cFurnaceRecipe::ReloadRecipes(void) { ClearRecipes(); LOGD("Loading furnace recipes..."); std::ifstream f(FURNACE_RECIPE_FILE, std::ios::in); if (!f.good()) { LOG("Could not open the furnace recipes file \"%s\". No furnace recipes are available.", FURNACE_RECIPE_FILE); return; } unsigned int LineNum = 0; AString ParsingLine; while (std::getline(f, ParsingLine)) { LineNum++; if (ParsingLine.empty()) { continue; } // Remove comments from the line: size_t FirstCommentSymbol = ParsingLine.find('#'); if ((FirstCommentSymbol != AString::npos) && (FirstCommentSymbol != 0)) { ParsingLine.erase(ParsingLine.begin() + static_cast<const long>(FirstCommentSymbol), ParsingLine.end()); } switch (ParsingLine[0]) { case '#': { // Comment break; } case '!': { AddFuelFromLine(ParsingLine, LineNum); break; } default: { AddRecipeFromLine(ParsingLine, LineNum); break; } } // switch (ParsingLine[0]) } // while (getline(ParsingLine)) LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size()); }
bool AXmlElement::isNameEquals(const AString& nameattr) const { size_t pos = nameattr.find('@'); if (AConstant::npos == pos) return m_Name.equals(nameattr); else { AString name; AString attr; nameattr.peek(name, 0, pos); nameattr.peek(attr, pos); return (m_Name.equals(name) && m_Attributes.exists(attr)); } }
/** 查找指定的文件 @Param 存储文件信息的列表 @Param 用于匹配文件名的字符 @Param 遍历时是否递归 @Param 是否遍历目录 */ void FZipFilePack::FindFiles( VFileInfoList& fileList,const AString& pattern, bool bRecurse,bool bDir ) { VFileInfoList::iterator itr; VFileInfoList::iterator end = m_FileInfos.end(); // 如果要查找的字符包含目录,则做一个全匹配 bool full_match = (pattern.find('/') != AString::npos || pattern.find('\\') != AString::npos ); // 获取关键字的目录 AString directory; if( full_match ) { size_t pos1 = pattern.rfind( '/' ); size_t pos2 = pattern.rfind( '\\' ); if( pos1 == AString::npos || ((pos2 != AString::npos) && pos1 < pos2) ) pos1 = pos2; if( pos1 != AString::npos ) directory = pattern.substr( 0,pos1+1 ); } // 遍历文件信息 for( itr=m_FileInfos.begin();itr!=end;itr++ ) { if( ((itr->nCompressedSize != (size_t)-1) || (itr->nCompressedSize == (size_t)-1 && bDir)) && (bRecurse || itr->sPath == directory) ) { if( AStringUtil::Match(full_match ? itr->sFileName : itr->sBaseName,pattern) ) fileList.push_back( *itr ); } } }
cPiece::cVerticalStrategyPtr CreateVerticalStrategyFromString(const AString & a_StrategyDesc, bool a_LogWarnings) { // Break apart the strategy class, the first parameter before the first pipe char: auto idxPipe = a_StrategyDesc.find('|'); if (idxPipe == AString::npos) { idxPipe = a_StrategyDesc.length(); } AString StrategyClass = a_StrategyDesc.substr(0, idxPipe); // Create a strategy class based on the class string: cPiece::cVerticalStrategyPtr Strategy; if (NoCaseCompare(StrategyClass, "Fixed") == 0) { Strategy = std::make_shared<cVerticalStrategyFixed>(); } else if (NoCaseCompare(StrategyClass, "Range") == 0) { Strategy = std::make_shared<cVerticalStrategyRange>(); } else if (NoCaseCompare(StrategyClass, "TerrainTop") == 0) { Strategy = std::make_shared<cVerticalStrategyTerrainTop>(); } else if (NoCaseCompare(StrategyClass, "TerrainOrOceanTop") == 0) { Strategy = std::make_shared<cVerticalStrategyTerrainOrOceanTop>(); } else { return nullptr; } // Initialize the strategy's parameters: AString Params; if (idxPipe < a_StrategyDesc.length()) { Params = a_StrategyDesc.substr(idxPipe + 1); } if (!Strategy->InitializeFromString(Params, a_LogWarnings)) { return nullptr; } return Strategy; }
void cCompositeChat::AddStyle(AString & a_Style, const AString & a_AddStyle) { if (a_AddStyle.empty()) { return; } if (a_AddStyle[0] == '@') { size_t idx = a_Style.find('@'); if ((idx != AString::npos) && (idx != a_Style.length())) { a_Style.erase(idx, 2); } a_Style.append(a_AddStyle); return; } a_Style.append(a_AddStyle); }
//liluchangyou void ARTSPConnection::onSendResponse(const sp<AMessage> &msg) { AString response; sp<AMessage> notify; CHECK(msg->findString("response", &response)); // Find the boundary between headers and the body. ssize_t i = response.find("\r\n\r\n"); CHECK_GE(i, 0); LOGI(LOG_TAG,"response:\n%s", response.c_str()); size_t numBytesSent = 0; while (numBytesSent < response.size()) { ssize_t n = send(mSocket, response.c_str() + numBytesSent, response.size() - numBytesSent, 0); if (n == 0) { // Client closed the connection. LOGE(LOG_TAG,"Client unexpectedly closed the connection."); mState = DISCONNECTED; notify = new AMessage(kwhatCloseSession,mhandlerID); notify->setInt32("result",-1); notify->setInt32("sessionID",mSessionID); notify->post(); return; } else if (n < 0) { if (errno == EINTR) { continue; } mState = DISCONNECTED; LOGE(LOG_TAG,"Error sending rtsp response."); notify = new AMessage(kwhatCloseSession,mhandlerID); notify->setInt32("result",errno ); notify->setInt32("sessionID",mSessionID); notify->post(); return; } numBytesSent += (size_t)n; } }
void cHTTPFormParser::OnPartHeader(const AString & a_Key, const AString & a_Value) { if (NoCaseCompare(a_Key, "Content-Disposition") == 0) { size_t len = a_Value.size(); size_t ParamsStart = AString::npos; for (size_t i = 0; i < len; ++i) { if (a_Value[i] > ' ') { if (strncmp(a_Value.c_str() + i, "form-data", 9) != 0) { // Content disposition is not "form-data", mark the whole form invalid m_IsValid = false; return; } ParamsStart = a_Value.find(';', i + 9); break; } } if (ParamsStart == AString::npos) { // There is data missing in the Content-Disposition field, mark the whole form invalid: m_IsValid = false; return; } // Parse the field name and optional filename from this header: cNameValueParser Parser(a_Value.data() + ParamsStart, a_Value.size() - ParamsStart); Parser.Finish(); m_CurrentPartName = Parser["name"]; if (!Parser.IsValid() || m_CurrentPartName.empty()) { // The required parameter "name" is missing, mark the whole form invalid: m_IsValid = false; return; } m_CurrentPartFileName = Parser["filename"]; } }
// static status_t M3UParser::parseMetaData( const AString &line, sp<AMessage> *meta, const char *key) { ssize_t colonPos = line.find(":"); if (colonPos < 0) { return ERROR_MALFORMED; } int32_t x; status_t err = ParseInt32(line.c_str() + colonPos + 1, &x); if (err != OK) { return err; } if (meta->get() == NULL) { *meta = new AMessage; } (*meta)->setInt32(key, x); return OK; }
// static status_t M3UParser::parseMetaDataDuration( const AString &line, sp<AMessage> *meta, const char *key) { ssize_t colonPos = line.find(":"); if (colonPos < 0) { return ERROR_MALFORMED; } double x; status_t err = ParseDouble(line.c_str() + colonPos + 1, &x); if (err != OK) { return err; } if (meta->get() == NULL) { *meta = new AMessage; } (*meta)->setInt64(key, (int64_t)(x * 1E6)); return OK; }
void cHTTPRequest::OnHeaderLine(const AString & a_Key, const AString & a_Value) { if ( (NoCaseCompare(a_Key, "Authorization") == 0) && (strncmp(a_Value.c_str(), "Basic ", 6) == 0) ) { AString UserPass = Base64Decode(a_Value.substr(6)); size_t idxCol = UserPass.find(':'); if (idxCol != AString::npos) { m_AuthUsername = UserPass.substr(0, idxCol); m_AuthPassword = UserPass.substr(idxCol + 1); m_HasAuth = true; } } if ((a_Key == "Connection") && (NoCaseCompare(a_Value, "keep-alive") == 0)) { m_AllowKeepAlive = true; } AddHeader(a_Key, a_Value); }
bool ARTSPConnection::receiveRTSPReponse() { AString statusLine; if (!receiveLine(&statusLine)) { return false; } if (statusLine == "$") { sp<ABuffer> buffer = receiveBinaryData(); if (buffer == NULL) { return false; } if (mObserveBinaryMessage != NULL) { sp<AMessage> notify = mObserveBinaryMessage->dup(); notify->setObject("buffer", buffer); notify->post(); } else { LOGW("received binary data, but no one cares."); } return true; } sp<ARTSPResponse> response = new ARTSPResponse; response->mStatusLine = statusLine; LOGI("status: %s", response->mStatusLine.c_str()); ssize_t space1 = response->mStatusLine.find(" "); if (space1 < 0) { return false; } ssize_t space2 = response->mStatusLine.find(" ", space1 + 1); if (space2 < 0) { return false; } AString statusCodeStr( response->mStatusLine, space1 + 1, space2 - space1 - 1); if (!ParseSingleUnsignedLong( statusCodeStr.c_str(), &response->mStatusCode) || response->mStatusCode < 100 || response->mStatusCode > 999) { return false; } AString line; for (;;) { if (!receiveLine(&line)) { break; } if (line.empty()) { break; } LOGV("line: %s", line.c_str()); ssize_t colonPos = line.find(":"); if (colonPos < 0) { // Malformed header line. return false; } AString key(line, 0, colonPos); key.trim(); key.tolower(); line.erase(0, colonPos + 1); line.trim(); response->mHeaders.add(key, line); } unsigned long contentLength = 0; ssize_t i = response->mHeaders.indexOfKey("content-length"); if (i >= 0) { AString value = response->mHeaders.valueAt(i); if (!ParseSingleUnsignedLong(value.c_str(), &contentLength)) { return false; } } if (contentLength > 0) { response->mContent = new ABuffer(contentLength); size_t numBytesRead = 0; while (numBytesRead < contentLength) { ssize_t n = recv( mSocket, response->mContent->data() + numBytesRead, contentLength - numBytesRead, 0); if (n == 0) { // Server closed the connection. TRESPASS(); } else if (n < 0) { if (errno == EINTR) { continue; } TRESPASS(); } numBytesRead += (size_t)n; } } if (response->mStatusCode == 401) { if (mAuthType == NONE && mUser.size() > 0 && parseAuthMethod(response)) { ssize_t i; CHECK_EQ((status_t)OK, findPendingRequest(response, &i)); CHECK_GE(i, 0); sp<AMessage> reply = mPendingRequests.valueAt(i); mPendingRequests.removeItemsAt(i); AString request; CHECK(reply->findString("original-request", &request)); sp<AMessage> msg = new AMessage(kWhatSendRequest, id()); msg->setMessage("reply", reply); msg->setString("request", request.c_str(), request.size()); LOGI("re-sending request with authentication headers..."); onSendRequest(msg); return true; } } return notifyResponseListener(response); }
void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID) { ASSERT(a_UUID.size() == 32); // Check if already present: { if (m_UUIDToProfile.find(a_UUID) != m_UUIDToProfile.end()) { return; } } // Create the request address: AString Address = m_UUIDToProfileAddress; ReplaceString(Address, "%UUID%", a_UUID); // Create the HTTP request: AString Request; Request += "GET " + Address + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding Request += "Host: " + m_UUIDToProfileServer + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; Request += "Content-Length: 0\r\n"; Request += "\r\n"; // Get the response from the server: AString Response; if (!SecureRequest(m_UUIDToProfileServer, Request, Response)) { return; } // Check the HTTP status line: const AString Prefix("HTTP/1.1 200 OK"); AString HexDump; if (Response.compare(0, Prefix.size(), Prefix)) { LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return; } // Erase the HTTP headers from the response: size_t idxHeadersEnd = Response.find("\r\n\r\n"); if (idxHeadersEnd == AString::npos) { LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return; } Response.erase(0, idxHeadersEnd + 4); // Parse the returned string into Json: Json::Reader reader; Json::Value root; if (!reader.parse(Response, root, false) || !root.isObject()) { LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return; } /* Example response: { "id": "b1caf24202a841a78055a079c460eee7", "name": "xoft", "properties": [ { "name": "textures", "value": "eyJ0aW1lc3RhbXAiOjE0MDcwNzAzMjEyNzEsInByb2ZpbGVJZCI6ImIxY2FmMjQyMDJhODQxYTc4MDU1YTA3OWM0NjBlZWU3IiwicHJvZmlsZU5hbWUiOiJ4b2Z0IiwiaXNQdWJsaWMiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9iNzc5YmFiZjVhNTg3Zjk0OGFkNjc0N2VhOTEyNzU0MjliNjg4Mjk1YWUzYzA3YmQwZTJmNWJmNGQwNTIifX19", "signature": "XCty+jGEF39hEPrPhYNnCX087kPaoCjYruzYI/DS4nkL5hbjnkSM5Rh15hnUyv/FHhC8OF5rif3D1tQjtMI19KSVaXoUFXpbJM8/+PB8GDgEbX8Fc3u9nYkzOcM/xfxdYsFAdFhLQMkvase/BZLSuPhdy9DdI+TCrO7xuSTZfYmmwVuWo3w5gCY+mSIAnqltnOzaOOTcly75xvO0WYpVk7nJdnR2tvSi0wfrQPDrIg/uzhX7p0SnDqijmBU4QaNez/TNKiFxy69dAzt0RSotlQzqkDbyVKhhv9a4eY8h3pXi4UMftKEj4FAKczxLImkukJXuOn5NN15/Q+le0rJVBC60/xjKIVzltEsMN6qjWD0lQjey7WEL+4pGhCVuWY5KzuZjFvgqszuJTFz7lo+bcHiceldJtea8/fa02eTRObZvdLxbWC9ZfFY0IhpOVKfcLdno/ddDMNMQMi5kMrJ8MZZ/PcW1w5n7MMGWPGCla1kOaC55AL0QYSMGRVEZqgU9wXI5M7sHGZKGM4mWxkbEJYBkpI/p3GyxWgV6v33ZWlsz65TqlNrR1gCLaoFCm7Sif8NqPBZUAONHYon0roXhin/DyEanS93WV6i6FC1Wisscjq2AcvnOlgTo/5nN/1QsMbjNumuMGo37sqjRqlXoPb8zEUbAhhztYuJjEfQ2Rd8=" } ] } */ // Store the returned result into caches: AString PlayerName = root.get("name", "").asString(); if (PlayerName.empty()) { // No valid playername, bail out return; } Json::Value Properties = root.get("properties", ""); Int64 Now = time(NULL); { cCSLock Lock(m_CSUUIDToProfile); m_UUIDToProfile[a_UUID] = sProfile(PlayerName, a_UUID, Properties, Now); } { cCSLock Lock(m_CSUUIDToName); m_UUIDToName[a_UUID] = sProfile(PlayerName, a_UUID, Properties, Now); } { cCSLock Lock(m_CSNameToUUID); m_NameToUUID[StrToLower(PlayerName)] = sProfile(PlayerName, a_UUID, Properties, Now); } }
void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) { // Create a list of names to query, by removing those that are already cached: AStringVector NamesToQuery; NamesToQuery.reserve(a_PlayerNames.size()); { cCSLock Lock(m_CSNameToUUID); for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) { if (m_NameToUUID.find(*itr) == m_NameToUUID.end()) { NamesToQuery.push_back(*itr); } } // for itr - a_PlayerNames[] } // Lock(m_CSNameToUUID) while (!NamesToQuery.empty()) { // Create the request body - a JSON containing up to MAX_PER_QUERY playernames: Json::Value root; int Count = 0; AStringVector::iterator itr = NamesToQuery.begin(), end = NamesToQuery.end(); for (; (itr != end) && (Count < MAX_PER_QUERY); ++itr, ++Count) { Json::Value req(*itr); root.append(req); } // for itr - a_PlayerNames[] NamesToQuery.erase(NamesToQuery.begin(), itr); Json::FastWriter Writer; AString RequestBody = Writer.write(root); // Create the HTTP request: AString Request; Request += "POST " + m_NameToUUIDAddress + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding Request += "Host: " + m_NameToUUIDServer + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; Request += "Content-Type: application/json\r\n"; Request += Printf("Content-Length: %u\r\n", (unsigned)RequestBody.length()); Request += "\r\n"; Request += RequestBody; // Get the response from the server: AString Response; if (!SecureRequest(m_NameToUUIDServer, Request, Response)) { continue; } // Check the HTTP status line: const AString Prefix("HTTP/1.1 200 OK"); AString HexDump; if (Response.compare(0, Prefix.size(), Prefix)) { LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } // Erase the HTTP headers from the response: size_t idxHeadersEnd = Response.find("\r\n\r\n"); if (idxHeadersEnd == AString::npos) { LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } Response.erase(0, idxHeadersEnd + 4); // Parse the returned string into Json: Json::Reader reader; if (!reader.parse(Response, root, false) || !root.isArray()) { LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } // Store the returned results into cache: size_t JsonCount = root.size(); Int64 Now = time(NULL); { cCSLock Lock(m_CSNameToUUID); for (size_t idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } m_NameToUUID[StrToLower(JsonName)] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } // cCSLock (m_CSNameToUUID) // Also cache the UUIDToName: { cCSLock Lock(m_CSUUIDToName); for (size_t idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } m_UUIDToName[JsonUUID] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } } // while (!NamesToQuery.empty()) }
// static status_t M3UParser::parseCipherInfo( const AString &line, sp<AMessage> *meta, const AString &baseURI) { ssize_t colonPos = line.find(":"); if (colonPos < 0) { return ERROR_MALFORMED; } size_t offset = colonPos + 1; while (offset < line.size()) { ssize_t end = FindNextUnquoted(line, ',', offset); if (end < 0) { end = line.size(); } AString attr(line, offset, end - offset); attr.trim(); offset = end + 1; ssize_t equalPos = attr.find("="); if (equalPos < 0) { continue; } AString key(attr, 0, equalPos); key.trim(); AString val(attr, equalPos + 1, attr.size() - equalPos - 1); val.trim(); LOGV("key=%s value=%s", key.c_str(), val.c_str()); key.tolower(); if (key == "method" || key == "uri" || key == "iv") { if (meta->get() == NULL) { *meta = new AMessage; } if (key == "uri") { if (val.size() >= 2 && val.c_str()[0] == '"' && val.c_str()[val.size() - 1] == '"') { // Remove surrounding quotes. AString tmp(val, 1, val.size() - 2); val = tmp; } AString absURI; if (MakeURL(baseURI.c_str(), val.c_str(), &absURI)) { val = absURI; } else { LOGE("failed to make absolute url for '%s'.", val.c_str()); } } key.insert(AString("cipher-"), 0); (*meta)->setString(key.c_str(), val.c_str(), val.size()); } } return OK; }
bool ASessionDescription::parse(const void *data, size_t size) { mTracks.clear(); mFormats.clear(); mTracks.push(Attribs()); mFormats.push(AString("[root]")); AString desc((const char *)data, size); size_t i = 0; for (;;) { ssize_t eolPos = desc.find("\n", i); if (eolPos < 0) { break; } AString line; if ((size_t)eolPos > i && desc.c_str()[eolPos - 1] == '\r') { // We accept both '\n' and '\r\n' line endings, if it's // the latter, strip the '\r' as well. line.setTo(desc, i, eolPos - i - 1); } else { line.setTo(desc, i, eolPos - i); } if (line.empty()) { i = eolPos + 1; continue; } if (line.size() < 2 || line.c_str()[1] != '=') { return false; } ALOGI("%s", line.c_str()); switch (line.c_str()[0]) { case 'v': { if (strcmp(line.c_str(), "v=0")) { return false; } break; } case 'a': case 'b': { AString key, value; ssize_t colonPos = line.find(":", 2); if (colonPos < 0) { key = line; } else { key.setTo(line, 0, colonPos); if (key == "a=fmtp" || key == "a=rtpmap" || key == "a=framesize") { ssize_t spacePos = line.find(" ", colonPos + 1); if (spacePos < 0) { return false; } key.setTo(line, 0, spacePos); colonPos = spacePos; } value.setTo(line, colonPos + 1, line.size() - colonPos - 1); } key.trim(); value.trim(); ALOGV("adding '%s' => '%s'", key.c_str(), value.c_str()); mTracks.editItemAt(mTracks.size() - 1).add(key, value); break; } case 'm': { ALOGV("new section '%s'", AString(line, 2, line.size() - 2).c_str()); mTracks.push(Attribs()); mFormats.push(AString(line, 2, line.size() - 2)); break; } default: { AString key, value; ssize_t equalPos = line.find("="); key = AString(line, 0, equalPos + 1); value = AString(line, equalPos + 1, line.size() - equalPos - 1); key.trim(); value.trim(); ALOGV("adding '%s' => '%s'", key.c_str(), value.c_str()); mTracks.editItemAt(mTracks.size() - 1).add(key, value); break; } } i = eolPos + 1; } return true; }
bool ARTSPConnection::receiveRTSPReponse() { AString statusLine; if (!receiveLine(&statusLine)) { return false; } if (statusLine == "$") { sp<ABuffer> buffer = receiveBinaryData(); if (buffer == NULL) { return false; } if (mObserveBinaryMessage != NULL) { sp<AMessage> notify = mObserveBinaryMessage->dup(); notify->setBuffer("buffer", buffer); notify->post(); } else { ALOGW("received binary data, but no one cares."); } return true; } sp<ARTSPResponse> response = new ARTSPResponse; response->mStatusLine = statusLine; ALOGI("status: %s", response->mStatusLine.c_str()); ssize_t space1 = response->mStatusLine.find(" "); if (space1 < 0) { return false; } ssize_t space2 = response->mStatusLine.find(" ", space1 + 1); if (space2 < 0) { return false; } bool isRequest = false; if (!IsRTSPVersion(AString(response->mStatusLine, 0, space1))) { CHECK(IsRTSPVersion( AString( response->mStatusLine, space2 + 1, response->mStatusLine.size() - space2 - 1))); isRequest = true; response->mStatusCode = 0; } else { AString statusCodeStr( response->mStatusLine, space1 + 1, space2 - space1 - 1); if (!ParseSingleUnsignedLong( statusCodeStr.c_str(), &response->mStatusCode) || response->mStatusCode < 100 || response->mStatusCode > 999) { return false; } } AString line; ssize_t lastDictIndex = -1; for (;;) { if (!receiveLine(&line)) { break; } if (line.empty()) { break; } ALOGV("line: '%s'", line.c_str()); if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') { // Support for folded header values. if (lastDictIndex < 0) { // First line cannot be a continuation of the previous one. return false; } AString &value = response->mHeaders.editValueAt(lastDictIndex); value.append(line); continue; } ssize_t colonPos = line.find(":"); if (colonPos < 0) { // Malformed header line. return false; } AString key(line, 0, colonPos); key.trim(); key.tolower(); line.erase(0, colonPos + 1); lastDictIndex = response->mHeaders.add(key, line); } for (size_t i = 0; i < response->mHeaders.size(); ++i) { response->mHeaders.editValueAt(i).trim(); } unsigned long contentLength = 0; ssize_t i = response->mHeaders.indexOfKey("content-length"); if (i >= 0) { AString value = response->mHeaders.valueAt(i); if (!ParseSingleUnsignedLong(value.c_str(), &contentLength)) { return false; } } if (contentLength > 0) { response->mContent = new ABuffer(contentLength); if (receive(response->mContent->data(), contentLength) != OK) { return false; } } if (response->mStatusCode == 401) { if (mAuthType == NONE && mUser.size() > 0 && parseAuthMethod(response)) { ssize_t i; CHECK_EQ((status_t)OK, findPendingRequest(response, &i)); CHECK_GE(i, 0); sp<AMessage> reply = mPendingRequests.valueAt(i); mPendingRequests.removeItemsAt(i); AString request; CHECK(reply->findString("original-request", &request)); sp<AMessage> msg = new AMessage(kWhatSendRequest, id()); msg->setMessage("reply", reply); msg->setString("request", request.c_str(), request.size()); ALOGI("re-sending request with authentication headers..."); onSendRequest(msg); return true; } } return isRequest ? handleServerRequest(response) : notifyResponseListener(response); }
void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) { sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); if (mState != CONNECTED) { reply->setInt32("result", -ENOTCONN); reply->post(); return; } AString request; CHECK(msg->findString("request", &request)); // Just in case we need to re-issue the request with proper authentication // later, stash it away. reply->setString("original-request", request.c_str(), request.size()); addAuthentication(&request); addUserAgent(&request); // Find the boundary between headers and the body. ssize_t i = request.find("\r\n\r\n"); CHECK_GE(i, 0); int32_t cseq = mNextCSeq++; AString cseqHeader = "CSeq: "; cseqHeader.append(cseq); cseqHeader.append("\r\n"); request.insert(cseqHeader, i + 2); ALOGV("request: '%s'", request.c_str()); size_t numBytesSent = 0; while (numBytesSent < request.size()) { ssize_t n = send(mSocket, request.c_str() + numBytesSent, request.size() - numBytesSent, 0); if (n < 0 && errno == EINTR) { continue; } if (n <= 0) { performDisconnect(); if (n == 0) { // Server closed the connection. ALOGE("Server unexpectedly closed the connection."); reply->setInt32("result", ERROR_IO); reply->post(); } else { ALOGE("Error sending rtsp request. (%s)", strerror(errno)); reply->setInt32("result", -errno); reply->post(); } return; } numBytesSent += (size_t)n; } mPendingRequests.add(cseq, reply); }
void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatStart: { sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); AString iface; CHECK(msg->findString("iface", &iface)); status_t err = OK; ssize_t colonPos = iface.find(":"); unsigned long port; if (colonPos >= 0) { const char *s = iface.c_str() + colonPos + 1; char *end; port = strtoul(s, &end, 10); if (end == s || *end != '\0' || port > 65535) { err = -EINVAL; } else { iface.erase(colonPos, iface.size() - colonPos); } } else { port = kWifiDisplayDefaultPort; } if (err == OK) { if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) { sp<AMessage> notify = new AMessage(kWhatRTSPNotify, this); err = mNetSession->createRTSPServer( mInterfaceAddr, port, notify, &mSessionID); } else { err = -EINVAL; } } mState = AWAITING_CLIENT_CONNECTION; sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatRTSPNotify: { int32_t reason; CHECK(msg->findInt32("reason", &reason)); switch (reason) { case ANetworkSession::kWhatError: { int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); int32_t err; CHECK(msg->findInt32("err", &err)); AString detail; CHECK(msg->findString("detail", &detail)); ALOGE("An error occurred in session %d (%d, '%s/%s').", sessionID, err, detail.c_str(), strerror(-err)); mNetSession->destroySession(sessionID); if (sessionID == mClientSessionID) { mClientSessionID = 0; mClient->onDisplayError( IRemoteDisplayClient::kDisplayErrorUnknown); } break; } case ANetworkSession::kWhatClientConnected: { int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); if (mClientSessionID > 0) { ALOGW("A client tried to connect, but we already " "have one."); mNetSession->destroySession(sessionID); break; } CHECK_EQ(mState, AWAITING_CLIENT_CONNECTION); CHECK(msg->findString("client-ip", &mClientInfo.mRemoteIP)); CHECK(msg->findString("server-ip", &mClientInfo.mLocalIP)); if (mClientInfo.mRemoteIP == mClientInfo.mLocalIP) { // Disallow connections from the local interface // for security reasons. mNetSession->destroySession(sessionID); break; } CHECK(msg->findInt32( "server-port", &mClientInfo.mLocalPort)); mClientInfo.mPlaybackSessionID = -1; mClientSessionID = sessionID; ALOGI("We now have a client (%d) connected.", sessionID); mState = AWAITING_CLIENT_SETUP; status_t err = sendM1(sessionID); CHECK_EQ(err, (status_t)OK); break; } case ANetworkSession::kWhatData: { status_t err = onReceiveClientData(msg); if (err != OK) { mClient->onDisplayError( IRemoteDisplayClient::kDisplayErrorUnknown); } #if 0 // testing only. char val[PROPERTY_VALUE_MAX]; if (property_get("media.wfd.trigger", val, NULL)) { if (!strcasecmp(val, "pause") && mState == PLAYING) { mState = PLAYING_TO_PAUSED; sendTrigger(mClientSessionID, TRIGGER_PAUSE); } else if (!strcasecmp(val, "play") && mState == PAUSED) { mState = PAUSED_TO_PLAYING; sendTrigger(mClientSessionID, TRIGGER_PLAY); } } #endif break; } case ANetworkSession::kWhatNetworkStall: { break; } default: TRESPASS(); } break; } case kWhatStop: { CHECK(msg->senderAwaitsResponse(&mStopReplyID)); CHECK_LT(mState, AWAITING_CLIENT_TEARDOWN); if (mState >= AWAITING_CLIENT_PLAY) { // We have a session, i.e. a previous SETUP succeeded. status_t err = sendTrigger( mClientSessionID, TRIGGER_TEARDOWN); if (err == OK) { mState = AWAITING_CLIENT_TEARDOWN; (new AMessage(kWhatTeardownTriggerTimedOut, this))->post( kTeardownTriggerTimeouSecs * 1000000ll); break; } // fall through. } finishStop(); break; } case kWhatPause: { sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); status_t err = OK; if (mState != PLAYING) { err = INVALID_OPERATION; } else { mState = PLAYING_TO_PAUSED; sendTrigger(mClientSessionID, TRIGGER_PAUSE); } sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatResume: { sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); status_t err = OK; if (mState != PAUSED) { err = INVALID_OPERATION; } else { mState = PAUSED_TO_PLAYING; sendTrigger(mClientSessionID, TRIGGER_PLAY); } sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatReapDeadClients: { mReaperPending = false; if (mClientSessionID == 0 || mClientInfo.mPlaybackSession == NULL) { break; } if (mClientInfo.mPlaybackSession->getLastLifesignUs() + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) { ALOGI("playback session timed out, reaping."); mNetSession->destroySession(mClientSessionID); mClientSessionID = 0; mClient->onDisplayError( IRemoteDisplayClient::kDisplayErrorUnknown); } else { scheduleReaper(); } break; } case kWhatPlaybackSessionNotify: { int32_t playbackSessionID; CHECK(msg->findInt32("playbackSessionID", &playbackSessionID)); int32_t what; CHECK(msg->findInt32("what", &what)); if (what == PlaybackSession::kWhatSessionDead) { ALOGI("playback session wants to quit."); mClient->onDisplayError( IRemoteDisplayClient::kDisplayErrorUnknown); } else if (what == PlaybackSession::kWhatSessionEstablished) { mPlaybackSessionEstablished = true; if (mClient != NULL) { if (!mSinkSupportsVideo) { mClient->onDisplayConnected( NULL, // SurfaceTexture 0, // width, 0, // height, mUsingHDCP ? IRemoteDisplayClient::kDisplayFlagSecure : 0, 0); } else { size_t width, height; CHECK(VideoFormats::GetConfiguration( mChosenVideoResolutionType, mChosenVideoResolutionIndex, &width, &height, NULL /* framesPerSecond */, NULL /* interlaced */)); mClient->onDisplayConnected( mClientInfo.mPlaybackSession ->getSurfaceTexture(), width, height, mUsingHDCP ? IRemoteDisplayClient::kDisplayFlagSecure : 0, playbackSessionID); } } finishPlay(); if (mState == ABOUT_TO_PLAY) { mState = PLAYING; } } else if (what == PlaybackSession::kWhatSessionDestroyed) { disconnectClient2(); } else { CHECK_EQ(what, PlaybackSession::kWhatBinaryData); int32_t channel; CHECK(msg->findInt32("channel", &channel)); sp<ABuffer> data; CHECK(msg->findBuffer("data", &data)); CHECK_LE(channel, 0xff); CHECK_LE(data->size(), 0xffffu); int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); char header[4]; header[0] = '$'; header[1] = channel; header[2] = data->size() >> 8; header[3] = data->size() & 0xff; mNetSession->sendRequest( sessionID, header, sizeof(header)); mNetSession->sendRequest( sessionID, data->data(), data->size()); } break; } case kWhatKeepAlive: { int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); if (mClientSessionID != sessionID) { // Obsolete event, client is already gone. break; } sendM16(sessionID); break; } case kWhatTeardownTriggerTimedOut: { if (mState == AWAITING_CLIENT_TEARDOWN) { ALOGI("TEARDOWN trigger timed out, forcing disconnection."); CHECK(mStopReplyID != NULL); finishStop(); break; } break; } case kWhatHDCPNotify: { int32_t msgCode, ext1, ext2; CHECK(msg->findInt32("msg", &msgCode)); CHECK(msg->findInt32("ext1", &ext1)); CHECK(msg->findInt32("ext2", &ext2)); ALOGI("Saw HDCP notification code %d, ext1 %d, ext2 %d", msgCode, ext1, ext2); switch (msgCode) { case HDCPModule::HDCP_INITIALIZATION_COMPLETE: { mHDCPInitializationComplete = true; if (mSetupTriggerDeferred) { mSetupTriggerDeferred = false; sendTrigger(mClientSessionID, TRIGGER_SETUP); } break; } case HDCPModule::HDCP_SHUTDOWN_COMPLETE: case HDCPModule::HDCP_SHUTDOWN_FAILED: { // Ugly hack to make sure that the call to // HDCPObserver::notify is completely handled before // we clear the HDCP instance and unload the shared // library :( (new AMessage(kWhatFinishStop2, this))->post(300000ll); break; } default: { ALOGE("HDCP failure, shutting down."); mClient->onDisplayError( IRemoteDisplayClient::kDisplayErrorUnknown); break; } } break; } case kWhatFinishStop2: { finishStop2(); break; } default: TRESPASS(); } }
bool ASessionDescription::parse(const void *data, size_t size) { mTracks.clear(); mFormats.clear(); mTracks.push(Attribs()); mFormats.push(AString("[root]")); AString desc((const char *)data, size); #ifndef ANDROID_DEFAULT_CODE int rtpmapNum = 0; bool unsupported = false; #endif // #ifndef ANDROID_DEFAULT_CODE size_t i = 0; for (;;) { #ifndef ANDROID_DEFAULT_CODE if (i >= desc.size()) { break; } #endif // #ifndef ANDROID_DEFAULT_CODE ssize_t eolPos = desc.find("\n", i); if (eolPos < 0) { #ifndef ANDROID_DEFAULT_CODE eolPos = desc.size(); #else break; #endif // #ifndef ANDROID_DEFAULT_CODE } AString line; if ((size_t)eolPos > i && desc.c_str()[eolPos - 1] == '\r') { // We accept both '\n' and '\r\n' line endings, if it's // the latter, strip the '\r' as well. line.setTo(desc, i, eolPos - i - 1); } else { line.setTo(desc, i, eolPos - i); } if (line.empty()) { i = eolPos + 1; continue; } if (line.size() < 2 || line.c_str()[1] != '=') { return false; } #ifndef ANDROID_DEFAULT_CODE if (unsupported && line.c_str()[0] != 'm') { LOGI("skip %s in unsupported media description", line.c_str()); i = eolPos + 1; continue; } else #endif // #ifndef ANDROID_DEFAULT_CODE LOGI("%s", line.c_str()); switch (line.c_str()[0]) { case 'v': { if (strcmp(line.c_str(), "v=0")) { return false; } break; } case 'a': case 'b': { AString key, value; ssize_t colonPos = line.find(":", 2); if (colonPos < 0) { key = line; } else { key.setTo(line, 0, colonPos); if (key == "a=fmtp" || key == "a=rtpmap" || key == "a=framesize") { ssize_t spacePos = line.find(" ", colonPos + 1); if (spacePos < 0) { return false; } #ifndef ANDROID_DEFAULT_CODE if (key == "a=rtpmap") { if (rtpmapNum > 0) { mTracks.pop(); mFormats.pop(); unsupported = true; LOGW("ASessionDescription: multiple rtpmap" " for one media is not supported yet"); break; } else { rtpmapNum++; } } #endif // #ifndef ANDROID_DEFAULT_CODE key.setTo(line, 0, spacePos); colonPos = spacePos; } value.setTo(line, colonPos + 1, line.size() - colonPos - 1); } key.trim(); value.trim(); LOGV("adding '%s' => '%s'", key.c_str(), value.c_str()); mTracks.editItemAt(mTracks.size() - 1).add(key, value); break; } case 'm': { LOGV("new section '%s'", AString(line, 2, line.size() - 2).c_str()); #ifndef ANDROID_DEFAULT_CODE rtpmapNum = 0; unsupported = false; #endif // #ifndef ANDROID_DEFAULT_CODE mTracks.push(Attribs()); mFormats.push(AString(line, 2, line.size() - 2)); break; } default: { AString key, value; ssize_t equalPos = line.find("="); key = AString(line, 0, equalPos + 1); value = AString(line, equalPos + 1, line.size() - equalPos - 1); key.trim(); value.trim(); LOGV("adding '%s' => '%s'", key.c_str(), value.c_str()); mTracks.editItemAt(mTracks.size() - 1).add(key, value); break; } } i = eolPos + 1; } return true; }
bool ARTSPConnection::receiveRTSPReponse() { AString statusLine; if (!receiveLine(&statusLine)) { return false; } if (statusLine == "$") { sp<ABuffer> buffer = receiveBinaryData(); if (buffer == NULL) { return false; } if (mObserveBinaryMessage != NULL) { sp<AMessage> notify = mObserveBinaryMessage->dup(); notify->setObject("buffer", buffer); notify->post(); } else { LOGW("received binary data, but no one cares."); } return true; } sp<ARTSPResponse> response = new ARTSPResponse; response->mStatusLine = statusLine; LOGI("status: %s", response->mStatusLine.c_str()); ssize_t space1 = response->mStatusLine.find(" "); if (space1 < 0) { return false; } ssize_t space2 = response->mStatusLine.find(" ", space1 + 1); if (space2 < 0) { return false; } AString statusCodeStr( response->mStatusLine, space1 + 1, space2 - space1 - 1); if (!ParseSingleUnsignedLong( statusCodeStr.c_str(), &response->mStatusCode) || response->mStatusCode < 100 || response->mStatusCode > 999) { return false; } AString line; for (;;) { if (!receiveLine(&line)) { break; } if (line.empty()) { break; } LOGV("line: %s", line.c_str()); ssize_t colonPos = line.find(":"); if (colonPos < 0) { // Malformed header line. return false; } AString key(line, 0, colonPos); key.trim(); key.tolower(); line.erase(0, colonPos + 1); line.trim(); response->mHeaders.add(key, line); } unsigned long contentLength = 0; ssize_t i = response->mHeaders.indexOfKey("content-length"); if (i >= 0) { AString value = response->mHeaders.valueAt(i); if (!ParseSingleUnsignedLong(value.c_str(), &contentLength)) { return false; } } if (contentLength > 0) { response->mContent = new ABuffer(contentLength); size_t numBytesRead = 0; while (numBytesRead < contentLength) { ssize_t n = recv( mSocket, response->mContent->data() + numBytesRead, contentLength - numBytesRead, 0); if (n == 0) { // Server closed the connection. TRESPASS(); } else if (n < 0) { if (errno == EINTR) { continue; } TRESPASS(); } numBytesRead += (size_t)n; } } return notifyResponseListener(response); }