• 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 <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 
ARTSPConnection(bool uidValid,uid_t uid)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 
~ARTSPConnection()56 ARTSPConnection::~ARTSPConnection() {
57     if (mSocket >= 0) {
58         ALOGE("Connection is still open, closing the socket.");
59         if (mUIDValid) {
60             HTTPBase::UnRegisterSocketUserTag(mSocket);
61         }
62         close(mSocket);
63         mSocket = -1;
64     }
65 }
66 
connect(const char * url,const sp<AMessage> & reply)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 
disconnect(const sp<AMessage> & reply)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 
sendRequest(const char * request,const sp<AMessage> & reply)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 
observeBinaryData(const sp<AMessage> & reply)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 
onMessageReceived(const sp<AMessage> & msg)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
ParseURL(const char * url,AString * host,unsigned * port,AString * path,AString * user,AString * pass)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 
MakeSocketBlocking(int s,bool blocking)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 
onConnect(const sp<AMessage> & msg)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         ALOGE("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         ALOGV("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         ALOGE("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 
performDisconnect()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 
onDisconnect(const sp<AMessage> & msg)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 
onCompleteConnection(const sp<AMessage> & msg)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         ALOGE("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 
onSendRequest(const sp<AMessage> & msg)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     ALOGV("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                 ALOGE("Server unexpectedly closed the connection.");
450 
451                 reply->setInt32("result", ERROR_IO);
452                 reply->post();
453             } else {
454                 ALOGE("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 
onReceiveResponse()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 
flushPendingRequests()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 
postReceiveReponseEvent()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 
receive(void * data,size_t size)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                 ALOGE("Server unexpectedly closed the connection.");
540                 return ERROR_IO;
541             } else {
542                 ALOGE("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 
receiveLine(AString * line)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 
receiveBinaryData()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 
IsRTSPVersion(const AString & s)595 static bool IsRTSPVersion(const AString &s) {
596     return s == "RTSP/1.0";
597 }
598 
receiveRTSPReponse()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->setBuffer("buffer", buffer);
616             notify->post();
617         } else {
618             ALOGW("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     ALOGI("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         ALOGV("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             ALOGI("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 
handleServerRequest(const sp<ARTSPResponse> & request)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                 ALOGE("Server unexpectedly closed the connection.");
797             } else {
798                 ALOGE("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
ParseSingleUnsignedLong(const char * from,unsigned long * x)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 
findPendingRequest(const sp<ARTSPResponse> & response,ssize_t * index) const825 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 
notifyResponseListener(const sp<ARTSPResponse> & response)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 
parseAuthMethod(const sp<ARTSPResponse> & response)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)
H(const AString & s,AString * out)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 
GetMethodAndURL(const AString & request,AString * method,AString * url)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 
addAuthentication(AString * request)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
MakeUserAgent(AString * userAgent)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 
addUserAgent(AString * request) const1049 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