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