Home | History | Annotate | Download | only in rtsp
      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 
     39 namespace android {
     40 
     41 // static
     42 const int64_t ARTSPConnection::kSelectTimeoutUs = 1000ll;
     43 
     44 ARTSPConnection::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 
     56 ARTSPConnection::~ARTSPConnection() {
     57     if (mSocket >= 0) {
     58         LOGE("Connection is still open, closing the socket.");
     59         if (mUIDValid) {
     60             HTTPBase::UnRegisterSocketUserTag(mSocket);
     61         }
     62         close(mSocket);
     63         mSocket = -1;
     64     }
     65 }
     66 
     67 void 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 
     74 void ARTSPConnection::disconnect(const sp<AMessage> &reply) {
     75     sp<AMessage> msg = new AMessage(kWhatDisconnect, id());
     76     msg->setMessage("reply", reply);
     77     msg->post();
     78 }
     79 
     80 void 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 
     88 void ARTSPConnection::observeBinaryData(const sp<AMessage> &reply) {
     89     sp<AMessage> msg = new AMessage(kWhatObserveBinaryData, id());
     90     msg->setMessage("reply", reply);
     91     msg->post();
     92 }
     93 
     94 void 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
    129 bool 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 
    190 static 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 
    209 void 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         LOGE("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         LOGV("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         LOGE("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 
    310 void 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 
    327 void 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 
    340 void 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         LOGE("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 
    400 void 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     LOGV("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                 LOGE("Server unexpectedly closed the connection.");
    450 
    451                 reply->setInt32("result", ERROR_IO);
    452                 reply->post();
    453             } else {
    454                 LOGE("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 
    468 void 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 
    503 void 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 
    514 void 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 
    525 status_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                 LOGE("Server unexpectedly closed the connection.");
    540                 return ERROR_IO;
    541             } else {
    542                 LOGE("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 
    553 bool 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 
    579 sp<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 
    595 static bool IsRTSPVersion(const AString &s) {
    596     return s == "RTSP/1.0";
    597 }
    598 
    599 bool 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             LOGW("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     LOGI("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         LOGV("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             LOGI("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 
    755 bool 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                 LOGE("Server unexpectedly closed the connection.");
    797             } else {
    798                 LOGE("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
    813 bool 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 
    825 status_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 
    854 bool 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 
    878 bool 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)
    912 static 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 
    942 static 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 
    954 void 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
   1035 void 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 
   1049 void 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