1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define LOG_NDEBUG 0 18 #define LOG_TAG "ARTSPConnection" 19 #include <utils/Log.h> 20 21 #include "ARTSPConnection.h" 22 23 #include <media/stagefright/foundation/ABuffer.h> 24 #include <media/stagefright/foundation/ADebug.h> 25 #include <media/stagefright/foundation/AMessage.h> 26 #include <media/stagefright/foundation/base64.h> 27 #include <media/stagefright/MediaErrors.h> 28 #include <media/stagefright/Utils.h> 29 30 #include <arpa/inet.h> 31 #include <fcntl.h> 32 #include <netdb.h> 33 #include <openssl/md5.h> 34 #include <sys/socket.h> 35 36 #include "include/HTTPBase.h" 37 38 namespace android { 39 40 // static 41 const int64_t ARTSPConnection::kSelectTimeoutUs = 1000ll; 42 43 // static 44 const AString ARTSPConnection::sUserAgent = 45 AStringPrintf("User-Agent: %s\r\n", MakeUserAgent().c_str()); 46 47 ARTSPConnection::ARTSPConnection(bool uidValid, uid_t uid) 48 : mUIDValid(uidValid), 49 mUID(uid), 50 mState(DISCONNECTED), 51 mAuthType(NONE), 52 mSocket(-1), 53 mConnectionID(0), 54 mNextCSeq(0), 55 mReceiveResponseEventPending(false) { 56 } 57 58 ARTSPConnection::~ARTSPConnection() { 59 if (mSocket >= 0) { 60 ALOGE("Connection is still open, closing the socket."); 61 if (mUIDValid) { 62 HTTPBase::UnRegisterSocketUserTag(mSocket); 63 HTTPBase::UnRegisterSocketUserMark(mSocket); 64 } 65 close(mSocket); 66 mSocket = -1; 67 } 68 } 69 70 void ARTSPConnection::connect(const char *url, const sp<AMessage> &reply) { 71 sp<AMessage> msg = new AMessage(kWhatConnect, this); 72 msg->setString("url", url); 73 msg->setMessage("reply", reply); 74 msg->post(); 75 } 76 77 void ARTSPConnection::disconnect(const sp<AMessage> &reply) { 78 sp<AMessage> msg = new AMessage(kWhatDisconnect, this); 79 msg->setMessage("reply", reply); 80 msg->post(); 81 } 82 83 void ARTSPConnection::sendRequest( 84 const char *request, const sp<AMessage> &reply) { 85 sp<AMessage> msg = new AMessage(kWhatSendRequest, this); 86 msg->setString("request", request); 87 msg->setMessage("reply", reply); 88 msg->post(); 89 } 90 91 void ARTSPConnection::observeBinaryData(const sp<AMessage> &reply) { 92 sp<AMessage> msg = new AMessage(kWhatObserveBinaryData, this); 93 msg->setMessage("reply", reply); 94 msg->post(); 95 } 96 97 void ARTSPConnection::onMessageReceived(const sp<AMessage> &msg) { 98 switch (msg->what()) { 99 case kWhatConnect: 100 onConnect(msg); 101 break; 102 103 case kWhatDisconnect: 104 onDisconnect(msg); 105 break; 106 107 case kWhatCompleteConnection: 108 onCompleteConnection(msg); 109 break; 110 111 case kWhatSendRequest: 112 onSendRequest(msg); 113 break; 114 115 case kWhatReceiveResponse: 116 onReceiveResponse(); 117 break; 118 119 case kWhatObserveBinaryData: 120 { 121 CHECK(msg->findMessage("reply", &mObserveBinaryMessage)); 122 break; 123 } 124 125 default: 126 TRESPASS(); 127 break; 128 } 129 } 130 131 // static 132 bool ARTSPConnection::ParseURL( 133 const char *url, AString *host, unsigned *port, AString *path, 134 AString *user, AString *pass) { 135 host->clear(); 136 *port = 0; 137 path->clear(); 138 user->clear(); 139 pass->clear(); 140 141 if (strncasecmp("rtsp://", url, 7)) { 142 return false; 143 } 144 145 const char *slashPos = strchr(&url[7], '/'); 146 147 if (slashPos == NULL) { 148 host->setTo(&url[7]); 149 path->setTo("/"); 150 } else { 151 host->setTo(&url[7], slashPos - &url[7]); 152 path->setTo(slashPos); 153 } 154 155 ssize_t atPos = host->find("@"); 156 157 if (atPos >= 0) { 158 // Split of user:pass@ from hostname. 159 160 AString userPass(*host, 0, atPos); 161 host->erase(0, atPos + 1); 162 163 ssize_t colonPos = userPass.find(":"); 164 165 if (colonPos < 0) { 166 *user = userPass; 167 } else { 168 user->setTo(userPass, 0, colonPos); 169 pass->setTo(userPass, colonPos + 1, userPass.size() - colonPos - 1); 170 } 171 } 172 173 const char *colonPos = strchr(host->c_str(), ':'); 174 175 if (colonPos != NULL) { 176 unsigned long x; 177 if (!ParseSingleUnsignedLong(colonPos + 1, &x) || x >= 65536) { 178 return false; 179 } 180 181 *port = x; 182 183 size_t colonOffset = colonPos - host->c_str(); 184 size_t trailing = host->size() - colonOffset; 185 host->erase(colonOffset, trailing); 186 } else { 187 *port = 554; 188 } 189 190 return true; 191 } 192 193 static status_t MakeSocketBlocking(int s, bool blocking) { 194 // Make socket non-blocking. 195 int flags = fcntl(s, F_GETFL, 0); 196 197 if (flags == -1) { 198 return UNKNOWN_ERROR; 199 } 200 201 if (blocking) { 202 flags &= ~O_NONBLOCK; 203 } else { 204 flags |= O_NONBLOCK; 205 } 206 207 flags = fcntl(s, F_SETFL, flags); 208 209 return flags == -1 ? UNKNOWN_ERROR : OK; 210 } 211 212 void ARTSPConnection::onConnect(const sp<AMessage> &msg) { 213 ++mConnectionID; 214 215 if (mState != DISCONNECTED) { 216 if (mUIDValid) { 217 HTTPBase::UnRegisterSocketUserTag(mSocket); 218 HTTPBase::UnRegisterSocketUserMark(mSocket); 219 } 220 close(mSocket); 221 mSocket = -1; 222 223 flushPendingRequests(); 224 } 225 226 mState = CONNECTING; 227 228 AString url; 229 CHECK(msg->findString("url", &url)); 230 231 sp<AMessage> reply; 232 CHECK(msg->findMessage("reply", &reply)); 233 234 AString host, path; 235 unsigned port; 236 if (!ParseURL(url.c_str(), &host, &port, &path, &mUser, &mPass) 237 || (mUser.size() > 0 && mPass.size() == 0)) { 238 // If we have a user name but no password we have to give up 239 // right here, since we currently have no way of asking the user 240 // for this information. 241 242 ALOGE("Malformed rtsp url %s", uriDebugString(url).c_str()); 243 244 reply->setInt32("result", ERROR_MALFORMED); 245 reply->post(); 246 247 mState = DISCONNECTED; 248 return; 249 } 250 251 if (mUser.size() > 0) { 252 ALOGV("user = '%s', pass = '%s'", mUser.c_str(), mPass.c_str()); 253 } 254 255 struct hostent *ent = gethostbyname(host.c_str()); 256 if (ent == NULL) { 257 ALOGE("Unknown host %s", host.c_str()); 258 259 reply->setInt32("result", -ENOENT); 260 reply->post(); 261 262 mState = DISCONNECTED; 263 return; 264 } 265 266 mSocket = socket(AF_INET, SOCK_STREAM, 0); 267 268 if (mUIDValid) { 269 HTTPBase::RegisterSocketUserTag(mSocket, mUID, 270 (uint32_t)*(uint32_t*) "RTSP"); 271 HTTPBase::RegisterSocketUserMark(mSocket, mUID); 272 } 273 274 MakeSocketBlocking(mSocket, false); 275 276 struct sockaddr_in remote; 277 memset(remote.sin_zero, 0, sizeof(remote.sin_zero)); 278 remote.sin_family = AF_INET; 279 remote.sin_addr.s_addr = *(in_addr_t *)ent->h_addr; 280 remote.sin_port = htons(port); 281 282 int err = ::connect( 283 mSocket, (const struct sockaddr *)&remote, sizeof(remote)); 284 285 reply->setInt32("server-ip", ntohl(remote.sin_addr.s_addr)); 286 287 if (err < 0) { 288 if (errno == EINPROGRESS) { 289 sp<AMessage> msg = new AMessage(kWhatCompleteConnection, this); 290 msg->setMessage("reply", reply); 291 msg->setInt32("connection-id", mConnectionID); 292 msg->post(); 293 return; 294 } 295 296 reply->setInt32("result", -errno); 297 mState = DISCONNECTED; 298 299 if (mUIDValid) { 300 HTTPBase::UnRegisterSocketUserTag(mSocket); 301 HTTPBase::UnRegisterSocketUserMark(mSocket); 302 } 303 close(mSocket); 304 mSocket = -1; 305 } else { 306 reply->setInt32("result", OK); 307 mState = CONNECTED; 308 mNextCSeq = 1; 309 310 postReceiveReponseEvent(); 311 } 312 313 reply->post(); 314 } 315 316 void ARTSPConnection::performDisconnect() { 317 if (mUIDValid) { 318 HTTPBase::UnRegisterSocketUserTag(mSocket); 319 HTTPBase::UnRegisterSocketUserMark(mSocket); 320 } 321 close(mSocket); 322 mSocket = -1; 323 324 flushPendingRequests(); 325 326 mUser.clear(); 327 mPass.clear(); 328 mAuthType = NONE; 329 mNonce.clear(); 330 331 mState = DISCONNECTED; 332 } 333 334 void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) { 335 if (mState == CONNECTED || mState == CONNECTING) { 336 performDisconnect(); 337 } 338 339 sp<AMessage> reply; 340 CHECK(msg->findMessage("reply", &reply)); 341 342 reply->setInt32("result", OK); 343 344 reply->post(); 345 } 346 347 void ARTSPConnection::onCompleteConnection(const sp<AMessage> &msg) { 348 sp<AMessage> reply; 349 CHECK(msg->findMessage("reply", &reply)); 350 351 int32_t connectionID; 352 CHECK(msg->findInt32("connection-id", &connectionID)); 353 354 if ((connectionID != mConnectionID) || mState != CONNECTING) { 355 // While we were attempting to connect, the attempt was 356 // cancelled. 357 reply->setInt32("result", -ECONNABORTED); 358 reply->post(); 359 return; 360 } 361 362 struct timeval tv; 363 tv.tv_sec = 0; 364 tv.tv_usec = kSelectTimeoutUs; 365 366 fd_set ws; 367 FD_ZERO(&ws); 368 FD_SET(mSocket, &ws); 369 370 int res = select(mSocket + 1, NULL, &ws, NULL, &tv); 371 CHECK_GE(res, 0); 372 373 if (res == 0) { 374 // Timed out. Not yet connected. 375 376 msg->post(); 377 return; 378 } 379 380 int err; 381 socklen_t optionLen = sizeof(err); 382 CHECK_EQ(getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &err, &optionLen), 0); 383 CHECK_EQ(optionLen, (socklen_t)sizeof(err)); 384 385 if (err != 0) { 386 ALOGE("err = %d (%s)", err, strerror(err)); 387 388 reply->setInt32("result", -err); 389 390 mState = DISCONNECTED; 391 if (mUIDValid) { 392 HTTPBase::UnRegisterSocketUserTag(mSocket); 393 HTTPBase::UnRegisterSocketUserMark(mSocket); 394 } 395 close(mSocket); 396 mSocket = -1; 397 } else { 398 reply->setInt32("result", OK); 399 mState = CONNECTED; 400 mNextCSeq = 1; 401 402 postReceiveReponseEvent(); 403 } 404 405 reply->post(); 406 } 407 408 void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) { 409 sp<AMessage> reply; 410 CHECK(msg->findMessage("reply", &reply)); 411 412 if (mState != CONNECTED) { 413 reply->setInt32("result", -ENOTCONN); 414 reply->post(); 415 return; 416 } 417 418 AString request; 419 CHECK(msg->findString("request", &request)); 420 421 // Just in case we need to re-issue the request with proper authentication 422 // later, stash it away. 423 reply->setString("original-request", request.c_str(), request.size()); 424 425 addAuthentication(&request); 426 addUserAgent(&request); 427 428 // Find the boundary between headers and the body. 429 ssize_t i = request.find("\r\n\r\n"); 430 CHECK_GE(i, 0); 431 432 int32_t cseq = mNextCSeq++; 433 434 AString cseqHeader = "CSeq: "; 435 cseqHeader.append(cseq); 436 cseqHeader.append("\r\n"); 437 438 request.insert(cseqHeader, i + 2); 439 440 ALOGV("request: '%s'", request.c_str()); 441 442 size_t numBytesSent = 0; 443 while (numBytesSent < request.size()) { 444 ssize_t n = 445 send(mSocket, request.c_str() + numBytesSent, 446 request.size() - numBytesSent, 0); 447 448 if (n < 0 && errno == EINTR) { 449 continue; 450 } 451 452 if (n <= 0) { 453 performDisconnect(); 454 455 if (n == 0) { 456 // Server closed the connection. 457 ALOGE("Server unexpectedly closed the connection."); 458 459 reply->setInt32("result", ERROR_IO); 460 reply->post(); 461 } else { 462 ALOGE("Error sending rtsp request. (%s)", strerror(errno)); 463 reply->setInt32("result", -errno); 464 reply->post(); 465 } 466 467 return; 468 } 469 470 numBytesSent += (size_t)n; 471 } 472 473 mPendingRequests.add(cseq, reply); 474 } 475 476 void ARTSPConnection::onReceiveResponse() { 477 mReceiveResponseEventPending = false; 478 479 if (mState != CONNECTED) { 480 return; 481 } 482 483 struct timeval tv; 484 tv.tv_sec = 0; 485 tv.tv_usec = kSelectTimeoutUs; 486 487 fd_set rs; 488 FD_ZERO(&rs); 489 FD_SET(mSocket, &rs); 490 491 int res = select(mSocket + 1, &rs, NULL, NULL, &tv); 492 493 if (res == 1) { 494 MakeSocketBlocking(mSocket, true); 495 496 bool success = receiveRTSPReponse(); 497 498 MakeSocketBlocking(mSocket, false); 499 500 if (!success) { 501 // Something horrible, irreparable has happened. 502 flushPendingRequests(); 503 return; 504 } 505 } 506 507 postReceiveReponseEvent(); 508 } 509 510 void ARTSPConnection::flushPendingRequests() { 511 for (size_t i = 0; i < mPendingRequests.size(); ++i) { 512 sp<AMessage> reply = mPendingRequests.valueAt(i); 513 514 reply->setInt32("result", -ECONNABORTED); 515 reply->post(); 516 } 517 518 mPendingRequests.clear(); 519 } 520 521 void ARTSPConnection::postReceiveReponseEvent() { 522 if (mReceiveResponseEventPending) { 523 return; 524 } 525 526 sp<AMessage> msg = new AMessage(kWhatReceiveResponse, this); 527 msg->post(); 528 529 mReceiveResponseEventPending = true; 530 } 531 532 status_t ARTSPConnection::receive(void *data, size_t size) { 533 size_t offset = 0; 534 while (offset < size) { 535 ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0); 536 537 if (n < 0 && errno == EINTR) { 538 continue; 539 } 540 541 if (n <= 0) { 542 performDisconnect(); 543 544 if (n == 0) { 545 // Server closed the connection. 546 ALOGE("Server unexpectedly closed the connection."); 547 return ERROR_IO; 548 } else { 549 ALOGE("Error reading rtsp response. (%s)", strerror(errno)); 550 return -errno; 551 } 552 } 553 554 offset += (size_t)n; 555 } 556 557 return OK; 558 } 559 560 bool ARTSPConnection::receiveLine(AString *line) { 561 line->clear(); 562 563 bool sawCR = false; 564 for (;;) { 565 char c; 566 if (receive(&c, 1) != OK) { 567 return false; 568 } 569 570 if (sawCR && c == '\n') { 571 line->erase(line->size() - 1, 1); 572 return true; 573 } else if (c == '\n') { 574 // some reponse line ended with '\n', instead of '\r\n'. 575 return true; 576 } 577 578 line->append(&c, 1); 579 580 if (c == '$' && line->size() == 1) { 581 // Special-case for interleaved binary data. 582 return true; 583 } 584 585 sawCR = (c == '\r'); 586 } 587 } 588 589 sp<ABuffer> ARTSPConnection::receiveBinaryData() { 590 uint8_t x[3]; 591 if (receive(x, 3) != OK) { 592 return NULL; 593 } 594 595 sp<ABuffer> buffer = new ABuffer((x[1] << 8) | x[2]); 596 if (receive(buffer->data(), buffer->size()) != OK) { 597 return NULL; 598 } 599 600 buffer->meta()->setInt32("index", (int32_t)x[0]); 601 602 return buffer; 603 } 604 605 static bool IsRTSPVersion(const AString &s) { 606 return s == "RTSP/1.0"; 607 } 608 609 bool ARTSPConnection::receiveRTSPReponse() { 610 AString statusLine; 611 612 if (!receiveLine(&statusLine)) { 613 return false; 614 } 615 616 if (statusLine == "$") { 617 sp<ABuffer> buffer = receiveBinaryData(); 618 619 if (buffer == NULL) { 620 return false; 621 } 622 623 if (mObserveBinaryMessage != NULL) { 624 sp<AMessage> notify = mObserveBinaryMessage->dup(); 625 notify->setBuffer("buffer", buffer); 626 notify->post(); 627 } else { 628 ALOGW("received binary data, but no one cares."); 629 } 630 631 return true; 632 } 633 634 sp<ARTSPResponse> response = new ARTSPResponse; 635 response->mStatusLine = statusLine; 636 637 ALOGI("status: %s", response->mStatusLine.c_str()); 638 639 ssize_t space1 = response->mStatusLine.find(" "); 640 if (space1 < 0) { 641 return false; 642 } 643 ssize_t space2 = response->mStatusLine.find(" ", space1 + 1); 644 if (space2 < 0) { 645 return false; 646 } 647 648 bool isRequest = false; 649 650 if (!IsRTSPVersion(AString(response->mStatusLine, 0, space1))) { 651 CHECK(IsRTSPVersion( 652 AString( 653 response->mStatusLine, 654 space2 + 1, 655 response->mStatusLine.size() - space2 - 1))); 656 657 isRequest = true; 658 659 response->mStatusCode = 0; 660 } else { 661 AString statusCodeStr( 662 response->mStatusLine, space1 + 1, space2 - space1 - 1); 663 664 if (!ParseSingleUnsignedLong( 665 statusCodeStr.c_str(), &response->mStatusCode) 666 || response->mStatusCode < 100 || response->mStatusCode > 999) { 667 return false; 668 } 669 } 670 671 AString line; 672 ssize_t lastDictIndex = -1; 673 for (;;) { 674 if (!receiveLine(&line)) { 675 break; 676 } 677 678 if (line.empty()) { 679 break; 680 } 681 682 ALOGV("line: '%s'", line.c_str()); 683 684 if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') { 685 // Support for folded header values. 686 687 if (lastDictIndex < 0) { 688 // First line cannot be a continuation of the previous one. 689 return false; 690 } 691 692 AString &value = response->mHeaders.editValueAt(lastDictIndex); 693 value.append(line); 694 695 continue; 696 } 697 698 ssize_t colonPos = line.find(":"); 699 if (colonPos < 0) { 700 // Malformed header line. 701 return false; 702 } 703 704 AString key(line, 0, colonPos); 705 key.trim(); 706 key.tolower(); 707 708 line.erase(0, colonPos + 1); 709 710 lastDictIndex = response->mHeaders.add(key, line); 711 } 712 713 for (size_t i = 0; i < response->mHeaders.size(); ++i) { 714 response->mHeaders.editValueAt(i).trim(); 715 } 716 717 unsigned long contentLength = 0; 718 719 ssize_t i = response->mHeaders.indexOfKey("content-length"); 720 721 if (i >= 0) { 722 AString value = response->mHeaders.valueAt(i); 723 if (!ParseSingleUnsignedLong(value.c_str(), &contentLength)) { 724 return false; 725 } 726 } 727 728 if (contentLength > 0) { 729 response->mContent = new ABuffer(contentLength); 730 731 if (receive(response->mContent->data(), contentLength) != OK) { 732 return false; 733 } 734 } 735 736 if (response->mStatusCode == 401) { 737 if (mAuthType == NONE && mUser.size() > 0 738 && parseAuthMethod(response)) { 739 ssize_t i; 740 CHECK_EQ((status_t)OK, findPendingRequest(response, &i)); 741 CHECK_GE(i, 0); 742 743 sp<AMessage> reply = mPendingRequests.valueAt(i); 744 mPendingRequests.removeItemsAt(i); 745 746 AString request; 747 CHECK(reply->findString("original-request", &request)); 748 749 sp<AMessage> msg = new AMessage(kWhatSendRequest, this); 750 msg->setMessage("reply", reply); 751 msg->setString("request", request.c_str(), request.size()); 752 753 ALOGI("re-sending request with authentication headers..."); 754 onSendRequest(msg); 755 756 return true; 757 } 758 } 759 760 return isRequest 761 ? handleServerRequest(response) 762 : notifyResponseListener(response); 763 } 764 765 bool ARTSPConnection::handleServerRequest(const sp<ARTSPResponse> &request) { 766 // Implementation of server->client requests is optional for all methods 767 // but we do need to respond, even if it's just to say that we don't 768 // support the method. 769 770 ssize_t space1 = request->mStatusLine.find(" "); 771 CHECK_GE(space1, 0); 772 773 AString response; 774 response.append("RTSP/1.0 501 Not Implemented\r\n"); 775 776 ssize_t i = request->mHeaders.indexOfKey("cseq"); 777 778 if (i >= 0) { 779 AString value = request->mHeaders.valueAt(i); 780 781 unsigned long cseq; 782 if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) { 783 return false; 784 } 785 786 response.append("CSeq: "); 787 response.append(cseq); 788 response.append("\r\n"); 789 } 790 791 response.append("\r\n"); 792 793 size_t numBytesSent = 0; 794 while (numBytesSent < response.size()) { 795 ssize_t n = 796 send(mSocket, response.c_str() + numBytesSent, 797 response.size() - numBytesSent, 0); 798 799 if (n < 0 && errno == EINTR) { 800 continue; 801 } 802 803 if (n <= 0) { 804 if (n == 0) { 805 // Server closed the connection. 806 ALOGE("Server unexpectedly closed the connection."); 807 } else { 808 ALOGE("Error sending rtsp response (%s).", strerror(errno)); 809 } 810 811 performDisconnect(); 812 813 return false; 814 } 815 816 numBytesSent += (size_t)n; 817 } 818 819 return true; 820 } 821 822 // static 823 bool ARTSPConnection::ParseSingleUnsignedLong( 824 const char *from, unsigned long *x) { 825 char *end; 826 *x = strtoul(from, &end, 10); 827 828 if (end == from || *end != '\0') { 829 return false; 830 } 831 832 return true; 833 } 834 835 status_t ARTSPConnection::findPendingRequest( 836 const sp<ARTSPResponse> &response, ssize_t *index) const { 837 *index = 0; 838 839 ssize_t i = response->mHeaders.indexOfKey("cseq"); 840 841 if (i < 0) { 842 // This is an unsolicited server->client message. 843 *index = -1; 844 return OK; 845 } 846 847 AString value = response->mHeaders.valueAt(i); 848 849 unsigned long cseq; 850 if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) { 851 return ERROR_MALFORMED; 852 } 853 854 i = mPendingRequests.indexOfKey(cseq); 855 856 if (i < 0) { 857 return -ENOENT; 858 } 859 860 *index = i; 861 862 return OK; 863 } 864 865 bool ARTSPConnection::notifyResponseListener( 866 const sp<ARTSPResponse> &response) { 867 ssize_t i; 868 status_t err = findPendingRequest(response, &i); 869 870 if (err == OK && i < 0) { 871 // An unsolicited server response is not a problem. 872 return true; 873 } 874 875 if (err != OK) { 876 return false; 877 } 878 879 sp<AMessage> reply = mPendingRequests.valueAt(i); 880 mPendingRequests.removeItemsAt(i); 881 882 reply->setInt32("result", OK); 883 reply->setObject("response", response); 884 reply->post(); 885 886 return true; 887 } 888 889 bool ARTSPConnection::parseAuthMethod(const sp<ARTSPResponse> &response) { 890 ssize_t i = response->mHeaders.indexOfKey("www-authenticate"); 891 892 if (i < 0) { 893 return false; 894 } 895 896 AString value = response->mHeaders.valueAt(i); 897 898 if (!strncmp(value.c_str(), "Basic", 5)) { 899 mAuthType = BASIC; 900 } else { 901 902 CHECK(!strncmp(value.c_str(), "Digest", 6)); 903 mAuthType = DIGEST; 904 905 i = value.find("nonce="); 906 CHECK_GE(i, 0); 907 CHECK_EQ(value.c_str()[i + 6], '\"'); 908 ssize_t j = value.find("\"", i + 7); 909 CHECK_GE(j, 0); 910 911 mNonce.setTo(value, i + 7, j - i - 7); 912 } 913 914 return true; 915 } 916 917 static void H(const AString &s, AString *out) { 918 out->clear(); 919 920 MD5_CTX m; 921 MD5_Init(&m); 922 MD5_Update(&m, s.c_str(), s.size()); 923 924 uint8_t key[16]; 925 MD5_Final(key, &m); 926 927 for (size_t i = 0; i < 16; ++i) { 928 char nibble = key[i] >> 4; 929 if (nibble <= 9) { 930 nibble += '0'; 931 } else { 932 nibble += 'a' - 10; 933 } 934 out->append(&nibble, 1); 935 936 nibble = key[i] & 0x0f; 937 if (nibble <= 9) { 938 nibble += '0'; 939 } else { 940 nibble += 'a' - 10; 941 } 942 out->append(&nibble, 1); 943 } 944 } 945 946 static void GetMethodAndURL( 947 const AString &request, AString *method, AString *url) { 948 ssize_t space1 = request.find(" "); 949 CHECK_GE(space1, 0); 950 951 ssize_t space2 = request.find(" ", space1 + 1); 952 CHECK_GE(space2, 0); 953 954 method->setTo(request, 0, space1); 955 url->setTo(request, space1 + 1, space2 - space1); 956 } 957 958 void ARTSPConnection::addAuthentication(AString *request) { 959 if (mAuthType == NONE) { 960 return; 961 } 962 963 // Find the boundary between headers and the body. 964 ssize_t i = request->find("\r\n\r\n"); 965 CHECK_GE(i, 0); 966 967 if (mAuthType == BASIC) { 968 AString tmp; 969 tmp.append(mUser); 970 tmp.append(":"); 971 tmp.append(mPass); 972 973 AString out; 974 encodeBase64(tmp.c_str(), tmp.size(), &out); 975 976 AString fragment; 977 fragment.append("Authorization: Basic "); 978 fragment.append(out); 979 fragment.append("\r\n"); 980 981 request->insert(fragment, i + 2); 982 983 return; 984 } 985 986 CHECK_EQ((int)mAuthType, (int)DIGEST); 987 988 AString method, url; 989 GetMethodAndURL(*request, &method, &url); 990 991 AString A1; 992 A1.append(mUser); 993 A1.append(":"); 994 A1.append("Streaming Server"); 995 A1.append(":"); 996 A1.append(mPass); 997 998 AString A2; 999 A2.append(method); 1000 A2.append(":"); 1001 A2.append(url); 1002 1003 AString HA1, HA2; 1004 H(A1, &HA1); 1005 H(A2, &HA2); 1006 1007 AString tmp; 1008 tmp.append(HA1); 1009 tmp.append(":"); 1010 tmp.append(mNonce); 1011 tmp.append(":"); 1012 tmp.append(HA2); 1013 1014 AString digest; 1015 H(tmp, &digest); 1016 1017 AString fragment; 1018 fragment.append("Authorization: Digest "); 1019 fragment.append("nonce=\""); 1020 fragment.append(mNonce); 1021 fragment.append("\", "); 1022 fragment.append("username=\""); 1023 fragment.append(mUser); 1024 fragment.append("\", "); 1025 fragment.append("uri=\""); 1026 fragment.append(url); 1027 fragment.append("\", "); 1028 fragment.append("response=\""); 1029 fragment.append(digest); 1030 fragment.append("\""); 1031 fragment.append("\r\n"); 1032 1033 request->insert(fragment, i + 2); 1034 } 1035 1036 void ARTSPConnection::addUserAgent(AString *request) const { 1037 // Find the boundary between headers and the body. 1038 ssize_t i = request->find("\r\n\r\n"); 1039 CHECK_GE(i, 0); 1040 1041 request->insert(sUserAgent, i + 2); 1042 } 1043 1044 } // namespace android 1045