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