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