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