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 "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 StringPrintf("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, id()); 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, id()); 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, id()); 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, id()); 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", 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, id()); 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 CHECK_GE(res, 0); 493 494 if (res == 1) { 495 MakeSocketBlocking(mSocket, true); 496 497 bool success = receiveRTSPReponse(); 498 499 MakeSocketBlocking(mSocket, false); 500 501 if (!success) { 502 // Something horrible, irreparable has happened. 503 flushPendingRequests(); 504 return; 505 } 506 } 507 508 postReceiveReponseEvent(); 509 } 510 511 void ARTSPConnection::flushPendingRequests() { 512 for (size_t i = 0; i < mPendingRequests.size(); ++i) { 513 sp<AMessage> reply = mPendingRequests.valueAt(i); 514 515 reply->setInt32("result", -ECONNABORTED); 516 reply->post(); 517 } 518 519 mPendingRequests.clear(); 520 } 521 522 void ARTSPConnection::postReceiveReponseEvent() { 523 if (mReceiveResponseEventPending) { 524 return; 525 } 526 527 sp<AMessage> msg = new AMessage(kWhatReceiveResponse, id()); 528 msg->post(); 529 530 mReceiveResponseEventPending = true; 531 } 532 533 status_t ARTSPConnection::receive(void *data, size_t size) { 534 size_t offset = 0; 535 while (offset < size) { 536 ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0); 537 538 if (n < 0 && errno == EINTR) { 539 continue; 540 } 541 542 if (n <= 0) { 543 performDisconnect(); 544 545 if (n == 0) { 546 // Server closed the connection. 547 ALOGE("Server unexpectedly closed the connection."); 548 return ERROR_IO; 549 } else { 550 ALOGE("Error reading rtsp response. (%s)", strerror(errno)); 551 return -errno; 552 } 553 } 554 555 offset += (size_t)n; 556 } 557 558 return OK; 559 } 560 561 bool ARTSPConnection::receiveLine(AString *line) { 562 line->clear(); 563 564 bool sawCR = false; 565 for (;;) { 566 char c; 567 if (receive(&c, 1) != OK) { 568 return false; 569 } 570 571 if (sawCR && c == '\n') { 572 line->erase(line->size() - 1, 1); 573 return true; 574 } else if (c == '\n') { 575 // some reponse line ended with '\n', instead of '\r\n'. 576 return true; 577 } 578 579 line->append(&c, 1); 580 581 if (c == '$' && line->size() == 1) { 582 // Special-case for interleaved binary data. 583 return true; 584 } 585 586 sawCR = (c == '\r'); 587 } 588 } 589 590 sp<ABuffer> ARTSPConnection::receiveBinaryData() { 591 uint8_t x[3]; 592 if (receive(x, 3) != OK) { 593 return NULL; 594 } 595 596 sp<ABuffer> buffer = new ABuffer((x[1] << 8) | x[2]); 597 if (receive(buffer->data(), buffer->size()) != OK) { 598 return NULL; 599 } 600 601 buffer->meta()->setInt32("index", (int32_t)x[0]); 602 603 return buffer; 604 } 605 606 static bool IsRTSPVersion(const AString &s) { 607 return s == "RTSP/1.0"; 608 } 609 610 bool ARTSPConnection::receiveRTSPReponse() { 611 AString statusLine; 612 613 if (!receiveLine(&statusLine)) { 614 return false; 615 } 616 617 if (statusLine == "$") { 618 sp<ABuffer> buffer = receiveBinaryData(); 619 620 if (buffer == NULL) { 621 return false; 622 } 623 624 if (mObserveBinaryMessage != NULL) { 625 sp<AMessage> notify = mObserveBinaryMessage->dup(); 626 notify->setBuffer("buffer", buffer); 627 notify->post(); 628 } else { 629 ALOGW("received binary data, but no one cares."); 630 } 631 632 return true; 633 } 634 635 sp<ARTSPResponse> response = new ARTSPResponse; 636 response->mStatusLine = statusLine; 637 638 ALOGI("status: %s", response->mStatusLine.c_str()); 639 640 ssize_t space1 = response->mStatusLine.find(" "); 641 if (space1 < 0) { 642 return false; 643 } 644 ssize_t space2 = response->mStatusLine.find(" ", space1 + 1); 645 if (space2 < 0) { 646 return false; 647 } 648 649 bool isRequest = false; 650 651 if (!IsRTSPVersion(AString(response->mStatusLine, 0, space1))) { 652 CHECK(IsRTSPVersion( 653 AString( 654 response->mStatusLine, 655 space2 + 1, 656 response->mStatusLine.size() - space2 - 1))); 657 658 isRequest = true; 659 660 response->mStatusCode = 0; 661 } else { 662 AString statusCodeStr( 663 response->mStatusLine, space1 + 1, space2 - space1 - 1); 664 665 if (!ParseSingleUnsignedLong( 666 statusCodeStr.c_str(), &response->mStatusCode) 667 || response->mStatusCode < 100 || response->mStatusCode > 999) { 668 return false; 669 } 670 } 671 672 AString line; 673 ssize_t lastDictIndex = -1; 674 for (;;) { 675 if (!receiveLine(&line)) { 676 break; 677 } 678 679 if (line.empty()) { 680 break; 681 } 682 683 ALOGV("line: '%s'", line.c_str()); 684 685 if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') { 686 // Support for folded header values. 687 688 if (lastDictIndex < 0) { 689 // First line cannot be a continuation of the previous one. 690 return false; 691 } 692 693 AString &value = response->mHeaders.editValueAt(lastDictIndex); 694 value.append(line); 695 696 continue; 697 } 698 699 ssize_t colonPos = line.find(":"); 700 if (colonPos < 0) { 701 // Malformed header line. 702 return false; 703 } 704 705 AString key(line, 0, colonPos); 706 key.trim(); 707 key.tolower(); 708 709 line.erase(0, colonPos + 1); 710 711 lastDictIndex = response->mHeaders.add(key, line); 712 } 713 714 for (size_t i = 0; i < response->mHeaders.size(); ++i) { 715 response->mHeaders.editValueAt(i).trim(); 716 } 717 718 unsigned long contentLength = 0; 719 720 ssize_t i = response->mHeaders.indexOfKey("content-length"); 721 722 if (i >= 0) { 723 AString value = response->mHeaders.valueAt(i); 724 if (!ParseSingleUnsignedLong(value.c_str(), &contentLength)) { 725 return false; 726 } 727 } 728 729 if (contentLength > 0) { 730 response->mContent = new ABuffer(contentLength); 731 732 if (receive(response->mContent->data(), contentLength) != OK) { 733 return false; 734 } 735 } 736 737 if (response->mStatusCode == 401) { 738 if (mAuthType == NONE && mUser.size() > 0 739 && parseAuthMethod(response)) { 740 ssize_t i; 741 CHECK_EQ((status_t)OK, findPendingRequest(response, &i)); 742 CHECK_GE(i, 0); 743 744 sp<AMessage> reply = mPendingRequests.valueAt(i); 745 mPendingRequests.removeItemsAt(i); 746 747 AString request; 748 CHECK(reply->findString("original-request", &request)); 749 750 sp<AMessage> msg = new AMessage(kWhatSendRequest, id()); 751 msg->setMessage("reply", reply); 752 msg->setString("request", request.c_str(), request.size()); 753 754 ALOGI("re-sending request with authentication headers..."); 755 onSendRequest(msg); 756 757 return true; 758 } 759 } 760 761 return isRequest 762 ? handleServerRequest(response) 763 : notifyResponseListener(response); 764 } 765 766 bool ARTSPConnection::handleServerRequest(const sp<ARTSPResponse> &request) { 767 // Implementation of server->client requests is optional for all methods 768 // but we do need to respond, even if it's just to say that we don't 769 // support the method. 770 771 ssize_t space1 = request->mStatusLine.find(" "); 772 CHECK_GE(space1, 0); 773 774 AString response; 775 response.append("RTSP/1.0 501 Not Implemented\r\n"); 776 777 ssize_t i = request->mHeaders.indexOfKey("cseq"); 778 779 if (i >= 0) { 780 AString value = request->mHeaders.valueAt(i); 781 782 unsigned long cseq; 783 if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) { 784 return false; 785 } 786 787 response.append("CSeq: "); 788 response.append(cseq); 789 response.append("\r\n"); 790 } 791 792 response.append("\r\n"); 793 794 size_t numBytesSent = 0; 795 while (numBytesSent < response.size()) { 796 ssize_t n = 797 send(mSocket, response.c_str() + numBytesSent, 798 response.size() - numBytesSent, 0); 799 800 if (n < 0 && errno == EINTR) { 801 continue; 802 } 803 804 if (n <= 0) { 805 if (n == 0) { 806 // Server closed the connection. 807 ALOGE("Server unexpectedly closed the connection."); 808 } else { 809 ALOGE("Error sending rtsp response (%s).", strerror(errno)); 810 } 811 812 performDisconnect(); 813 814 return false; 815 } 816 817 numBytesSent += (size_t)n; 818 } 819 820 return true; 821 } 822 823 // static 824 bool ARTSPConnection::ParseSingleUnsignedLong( 825 const char *from, unsigned long *x) { 826 char *end; 827 *x = strtoul(from, &end, 10); 828 829 if (end == from || *end != '\0') { 830 return false; 831 } 832 833 return true; 834 } 835 836 status_t ARTSPConnection::findPendingRequest( 837 const sp<ARTSPResponse> &response, ssize_t *index) const { 838 *index = 0; 839 840 ssize_t i = response->mHeaders.indexOfKey("cseq"); 841 842 if (i < 0) { 843 // This is an unsolicited server->client message. 844 *index = -1; 845 return OK; 846 } 847 848 AString value = response->mHeaders.valueAt(i); 849 850 unsigned long cseq; 851 if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) { 852 return ERROR_MALFORMED; 853 } 854 855 i = mPendingRequests.indexOfKey(cseq); 856 857 if (i < 0) { 858 return -ENOENT; 859 } 860 861 *index = i; 862 863 return OK; 864 } 865 866 bool ARTSPConnection::notifyResponseListener( 867 const sp<ARTSPResponse> &response) { 868 ssize_t i; 869 status_t err = findPendingRequest(response, &i); 870 871 if (err == OK && i < 0) { 872 // An unsolicited server response is not a problem. 873 return true; 874 } 875 876 if (err != OK) { 877 return false; 878 } 879 880 sp<AMessage> reply = mPendingRequests.valueAt(i); 881 mPendingRequests.removeItemsAt(i); 882 883 reply->setInt32("result", OK); 884 reply->setObject("response", response); 885 reply->post(); 886 887 return true; 888 } 889 890 bool ARTSPConnection::parseAuthMethod(const sp<ARTSPResponse> &response) { 891 ssize_t i = response->mHeaders.indexOfKey("www-authenticate"); 892 893 if (i < 0) { 894 return false; 895 } 896 897 AString value = response->mHeaders.valueAt(i); 898 899 if (!strncmp(value.c_str(), "Basic", 5)) { 900 mAuthType = BASIC; 901 } else { 902 #if !defined(HAVE_ANDROID_OS) 903 // We don't have access to the MD5 implementation on the simulator, 904 // so we won't support digest authentication. 905 return false; 906 #endif 907 908 CHECK(!strncmp(value.c_str(), "Digest", 6)); 909 mAuthType = DIGEST; 910 911 i = value.find("nonce="); 912 CHECK_GE(i, 0); 913 CHECK_EQ(value.c_str()[i + 6], '\"'); 914 ssize_t j = value.find("\"", i + 7); 915 CHECK_GE(j, 0); 916 917 mNonce.setTo(value, i + 7, j - i - 7); 918 } 919 920 return true; 921 } 922 923 #if defined(HAVE_ANDROID_OS) 924 static void H(const AString &s, AString *out) { 925 out->clear(); 926 927 MD5_CTX m; 928 MD5_Init(&m); 929 MD5_Update(&m, s.c_str(), s.size()); 930 931 uint8_t key[16]; 932 MD5_Final(key, &m); 933 934 for (size_t i = 0; i < 16; ++i) { 935 char nibble = key[i] >> 4; 936 if (nibble <= 9) { 937 nibble += '0'; 938 } else { 939 nibble += 'a' - 10; 940 } 941 out->append(&nibble, 1); 942 943 nibble = key[i] & 0x0f; 944 if (nibble <= 9) { 945 nibble += '0'; 946 } else { 947 nibble += 'a' - 10; 948 } 949 out->append(&nibble, 1); 950 } 951 } 952 #endif 953 954 static void GetMethodAndURL( 955 const AString &request, AString *method, AString *url) { 956 ssize_t space1 = request.find(" "); 957 CHECK_GE(space1, 0); 958 959 ssize_t space2 = request.find(" ", space1 + 1); 960 CHECK_GE(space2, 0); 961 962 method->setTo(request, 0, space1); 963 url->setTo(request, space1 + 1, space2 - space1); 964 } 965 966 void ARTSPConnection::addAuthentication(AString *request) { 967 if (mAuthType == NONE) { 968 return; 969 } 970 971 // Find the boundary between headers and the body. 972 ssize_t i = request->find("\r\n\r\n"); 973 CHECK_GE(i, 0); 974 975 if (mAuthType == BASIC) { 976 AString tmp; 977 tmp.append(mUser); 978 tmp.append(":"); 979 tmp.append(mPass); 980 981 AString out; 982 encodeBase64(tmp.c_str(), tmp.size(), &out); 983 984 AString fragment; 985 fragment.append("Authorization: Basic "); 986 fragment.append(out); 987 fragment.append("\r\n"); 988 989 request->insert(fragment, i + 2); 990 991 return; 992 } 993 994 #if defined(HAVE_ANDROID_OS) 995 CHECK_EQ((int)mAuthType, (int)DIGEST); 996 997 AString method, url; 998 GetMethodAndURL(*request, &method, &url); 999 1000 AString A1; 1001 A1.append(mUser); 1002 A1.append(":"); 1003 A1.append("Streaming Server"); 1004 A1.append(":"); 1005 A1.append(mPass); 1006 1007 AString A2; 1008 A2.append(method); 1009 A2.append(":"); 1010 A2.append(url); 1011 1012 AString HA1, HA2; 1013 H(A1, &HA1); 1014 H(A2, &HA2); 1015 1016 AString tmp; 1017 tmp.append(HA1); 1018 tmp.append(":"); 1019 tmp.append(mNonce); 1020 tmp.append(":"); 1021 tmp.append(HA2); 1022 1023 AString digest; 1024 H(tmp, &digest); 1025 1026 AString fragment; 1027 fragment.append("Authorization: Digest "); 1028 fragment.append("nonce=\""); 1029 fragment.append(mNonce); 1030 fragment.append("\", "); 1031 fragment.append("username=\""); 1032 fragment.append(mUser); 1033 fragment.append("\", "); 1034 fragment.append("uri=\""); 1035 fragment.append(url); 1036 fragment.append("\", "); 1037 fragment.append("response=\""); 1038 fragment.append(digest); 1039 fragment.append("\""); 1040 fragment.append("\r\n"); 1041 1042 request->insert(fragment, i + 2); 1043 #endif 1044 } 1045 1046 void ARTSPConnection::addUserAgent(AString *request) const { 1047 // Find the boundary between headers and the body. 1048 ssize_t i = request->find("\r\n\r\n"); 1049 CHECK_GE(i, 0); 1050 1051 request->insert(sUserAgent, i + 2); 1052 } 1053 1054 } // namespace android 1055