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