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