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