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