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
333 mState = DISCONNECTED;
334 }
335
onDisconnect(const sp<AMessage> & msg)336 void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) {
337 if (mState == CONNECTED || mState == CONNECTING) {
338 performDisconnect();
339 }
340
341 sp<AMessage> reply;
342 CHECK(msg->findMessage("reply", &reply));
343
344 reply->setInt32("result", OK);
345
346 reply->post();
347 }
348
onCompleteConnection(const sp<AMessage> & msg)349 void ARTSPConnection::onCompleteConnection(const sp<AMessage> &msg) {
350 sp<AMessage> reply;
351 CHECK(msg->findMessage("reply", &reply));
352
353 int32_t connectionID;
354 CHECK(msg->findInt32("connection-id", &connectionID));
355
356 if ((connectionID != mConnectionID) || mState != CONNECTING) {
357 // While we were attempting to connect, the attempt was
358 // cancelled.
359 reply->setInt32("result", -ECONNABORTED);
360 reply->post();
361 return;
362 }
363
364 struct timeval tv;
365 tv.tv_sec = 0;
366 tv.tv_usec = kSelectTimeoutUs;
367
368 fd_set ws;
369 FD_ZERO(&ws);
370 FD_SET(mSocket, &ws);
371
372 int res = select(mSocket + 1, NULL, &ws, NULL, &tv);
373 CHECK_GE(res, 0);
374
375 if (res == 0) {
376 // Timed out. Not yet connected.
377
378 msg->post();
379 return;
380 }
381
382 int err;
383 socklen_t optionLen = sizeof(err);
384 CHECK_EQ(getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &err, &optionLen), 0);
385 CHECK_EQ(optionLen, (socklen_t)sizeof(err));
386
387 if (err != 0) {
388 ALOGE("err = %d (%s)", err, strerror(err));
389
390 reply->setInt32("result", -err);
391
392 mState = DISCONNECTED;
393 if (mUIDValid) {
394 NetworkUtils::UnRegisterSocketUserTag(mSocket);
395 NetworkUtils::UnRegisterSocketUserMark(mSocket);
396 }
397 close(mSocket);
398 mSocket = -1;
399 } else {
400 reply->setInt32("result", OK);
401 mState = CONNECTED;
402 mNextCSeq = 1;
403
404 postReceiveReponseEvent();
405 }
406
407 reply->post();
408 }
409
onSendRequest(const sp<AMessage> & msg)410 void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) {
411 sp<AMessage> reply;
412 CHECK(msg->findMessage("reply", &reply));
413
414 if (mState != CONNECTED) {
415 reply->setInt32("result", -ENOTCONN);
416 reply->post();
417 return;
418 }
419
420 AString request;
421 CHECK(msg->findString("request", &request));
422
423 // Just in case we need to re-issue the request with proper authentication
424 // later, stash it away.
425 reply->setString("original-request", request.c_str(), request.size());
426
427 addAuthentication(&request);
428 addUserAgent(&request);
429
430 // Find the boundary between headers and the body.
431 ssize_t i = request.find("\r\n\r\n");
432 CHECK_GE(i, 0);
433
434 int32_t cseq = mNextCSeq++;
435
436 AString cseqHeader = "CSeq: ";
437 cseqHeader.append(cseq);
438 cseqHeader.append("\r\n");
439
440 request.insert(cseqHeader, i + 2);
441
442 ALOGV("request: '%s'", request.c_str());
443
444 size_t numBytesSent = 0;
445 while (numBytesSent < request.size()) {
446 ssize_t n =
447 send(mSocket, request.c_str() + numBytesSent,
448 request.size() - numBytesSent, 0);
449
450 if (n < 0 && errno == EINTR) {
451 continue;
452 }
453
454 if (n <= 0) {
455 performDisconnect();
456
457 if (n == 0) {
458 // Server closed the connection.
459 ALOGE("Server unexpectedly closed the connection.");
460
461 reply->setInt32("result", ERROR_IO);
462 reply->post();
463 } else {
464 ALOGE("Error sending rtsp request. (%s)", strerror(errno));
465 reply->setInt32("result", -errno);
466 reply->post();
467 }
468
469 return;
470 }
471
472 numBytesSent += (size_t)n;
473 }
474
475 mPendingRequests.add(cseq, reply);
476 }
477
onReceiveResponse()478 void ARTSPConnection::onReceiveResponse() {
479 mReceiveResponseEventPending = false;
480
481 if (mState != CONNECTED) {
482 return;
483 }
484
485 struct timeval tv;
486 tv.tv_sec = 0;
487 tv.tv_usec = kSelectTimeoutUs;
488
489 fd_set rs;
490 FD_ZERO(&rs);
491 FD_SET(mSocket, &rs);
492
493 int res = select(mSocket + 1, &rs, NULL, NULL, &tv);
494
495 if (res == 1) {
496 MakeSocketBlocking(mSocket, true);
497
498 bool success = receiveRTSPReponse();
499
500 MakeSocketBlocking(mSocket, false);
501
502 if (!success) {
503 // Something horrible, irreparable has happened.
504 flushPendingRequests();
505 return;
506 }
507 }
508
509 postReceiveReponseEvent();
510 }
511
flushPendingRequests()512 void ARTSPConnection::flushPendingRequests() {
513 for (size_t i = 0; i < mPendingRequests.size(); ++i) {
514 sp<AMessage> reply = mPendingRequests.valueAt(i);
515
516 reply->setInt32("result", -ECONNABORTED);
517 reply->post();
518 }
519
520 mPendingRequests.clear();
521 }
522
postReceiveReponseEvent()523 void ARTSPConnection::postReceiveReponseEvent() {
524 if (mReceiveResponseEventPending) {
525 return;
526 }
527
528 sp<AMessage> msg = new AMessage(kWhatReceiveResponse, this);
529 msg->post();
530
531 mReceiveResponseEventPending = true;
532 }
533
receive(void * data,size_t size)534 status_t ARTSPConnection::receive(void *data, size_t size) {
535 size_t offset = 0;
536 while (offset < size) {
537 ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0);
538
539 if (n < 0 && errno == EINTR) {
540 continue;
541 }
542
543 if (n <= 0) {
544 performDisconnect();
545
546 if (n == 0) {
547 // Server closed the connection.
548 ALOGE("Server unexpectedly closed the connection.");
549 return ERROR_IO;
550 } else {
551 ALOGE("Error reading rtsp response. (%s)", strerror(errno));
552 return -errno;
553 }
554 }
555
556 offset += (size_t)n;
557 }
558
559 return OK;
560 }
561
receiveLine(AString * line)562 bool ARTSPConnection::receiveLine(AString *line) {
563 line->clear();
564
565 bool sawCR = false;
566 for (;;) {
567 char c;
568 if (receive(&c, 1) != OK) {
569 return false;
570 }
571
572 if (sawCR && c == '\n') {
573 line->erase(line->size() - 1, 1);
574 return true;
575 } else if (c == '\n') {
576 // some reponse line ended with '\n', instead of '\r\n'.
577 return true;
578 }
579
580 line->append(&c, 1);
581
582 if (c == '$' && line->size() == 1) {
583 // Special-case for interleaved binary data.
584 return true;
585 }
586
587 sawCR = (c == '\r');
588 }
589 }
590
receiveBinaryData()591 sp<ABuffer> ARTSPConnection::receiveBinaryData() {
592 uint8_t x[3];
593 if (receive(x, 3) != OK) {
594 return NULL;
595 }
596
597 sp<ABuffer> buffer = new ABuffer((x[1] << 8) | x[2]);
598 if (receive(buffer->data(), buffer->size()) != OK) {
599 return NULL;
600 }
601
602 buffer->meta()->setInt32("index", (int32_t)x[0]);
603
604 return buffer;
605 }
606
IsRTSPVersion(const AString & s)607 static bool IsRTSPVersion(const AString &s) {
608 return s == "RTSP/1.0";
609 }
610
receiveRTSPReponse()611 bool ARTSPConnection::receiveRTSPReponse() {
612 AString statusLine;
613
614 if (!receiveLine(&statusLine)) {
615 return false;
616 }
617
618 if (statusLine == "$") {
619 sp<ABuffer> buffer = receiveBinaryData();
620
621 if (buffer == NULL) {
622 return false;
623 }
624
625 if (mObserveBinaryMessage != NULL) {
626 sp<AMessage> notify = mObserveBinaryMessage->dup();
627 notify->setBuffer("buffer", buffer);
628 notify->post();
629 } else {
630 ALOGW("received binary data, but no one cares.");
631 }
632
633 return true;
634 }
635
636 sp<ARTSPResponse> response = new ARTSPResponse;
637 response->mStatusLine = statusLine;
638
639 ALOGI("status: %s", response->mStatusLine.c_str());
640
641 ssize_t space1 = response->mStatusLine.find(" ");
642 if (space1 < 0) {
643 return false;
644 }
645 ssize_t space2 = response->mStatusLine.find(" ", space1 + 1);
646 if (space2 < 0) {
647 return false;
648 }
649
650 bool isRequest = false;
651
652 if (!IsRTSPVersion(AString(response->mStatusLine, 0, space1))) {
653 CHECK(IsRTSPVersion(
654 AString(
655 response->mStatusLine,
656 space2 + 1,
657 response->mStatusLine.size() - space2 - 1)));
658
659 isRequest = true;
660
661 response->mStatusCode = 0;
662 } else {
663 AString statusCodeStr(
664 response->mStatusLine, space1 + 1, space2 - space1 - 1);
665
666 if (!ParseSingleUnsignedLong(
667 statusCodeStr.c_str(), &response->mStatusCode)
668 || response->mStatusCode < 100 || response->mStatusCode > 999) {
669 return false;
670 }
671 }
672
673 AString line;
674 ssize_t lastDictIndex = -1;
675 for (;;) {
676 if (!receiveLine(&line)) {
677 break;
678 }
679
680 if (line.empty()) {
681 break;
682 }
683
684 ALOGV("line: '%s'", line.c_str());
685
686 if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') {
687 // Support for folded header values.
688
689 if (lastDictIndex < 0) {
690 // First line cannot be a continuation of the previous one.
691 return false;
692 }
693
694 AString &value = response->mHeaders.editValueAt(lastDictIndex);
695 value.append(line);
696
697 continue;
698 }
699
700 ssize_t colonPos = line.find(":");
701 if (colonPos < 0) {
702 // Malformed header line.
703 return false;
704 }
705
706 AString key(line, 0, colonPos);
707 key.trim();
708 key.tolower();
709
710 line.erase(0, colonPos + 1);
711
712 lastDictIndex = response->mHeaders.add(key, line);
713 }
714
715 for (size_t i = 0; i < response->mHeaders.size(); ++i) {
716 response->mHeaders.editValueAt(i).trim();
717 }
718
719 unsigned long contentLength = 0;
720
721 ssize_t i = response->mHeaders.indexOfKey("content-length");
722
723 if (i >= 0) {
724 AString value = response->mHeaders.valueAt(i);
725 if (!ParseSingleUnsignedLong(value.c_str(), &contentLength)) {
726 return false;
727 }
728 }
729
730 if (contentLength > 0) {
731 response->mContent = new ABuffer(contentLength);
732
733 if (receive(response->mContent->data(), contentLength) != OK) {
734 return false;
735 }
736 }
737
738 if (response->mStatusCode == 401) {
739 if (mAuthType == NONE && mUser.size() > 0
740 && parseAuthMethod(response)) {
741 ssize_t i;
742 CHECK_EQ((status_t)OK, findPendingRequest(response, &i));
743 CHECK_GE(i, 0);
744
745 sp<AMessage> reply = mPendingRequests.valueAt(i);
746 mPendingRequests.removeItemsAt(i);
747
748 AString request;
749 CHECK(reply->findString("original-request", &request));
750
751 sp<AMessage> msg = new AMessage(kWhatSendRequest, this);
752 msg->setMessage("reply", reply);
753 msg->setString("request", request.c_str(), request.size());
754
755 ALOGI("re-sending request with authentication headers...");
756 onSendRequest(msg);
757
758 return true;
759 }
760 }
761
762 return isRequest
763 ? handleServerRequest(response)
764 : notifyResponseListener(response);
765 }
766
handleServerRequest(const sp<ARTSPResponse> & request)767 bool ARTSPConnection::handleServerRequest(const sp<ARTSPResponse> &request) {
768 // Implementation of server->client requests is optional for all methods
769 // but we do need to respond, even if it's just to say that we don't
770 // support the method.
771
772 ssize_t space1 = request->mStatusLine.find(" ");
773 CHECK_GE(space1, 0);
774
775 AString response;
776 response.append("RTSP/1.0 501 Not Implemented\r\n");
777
778 ssize_t i = request->mHeaders.indexOfKey("cseq");
779
780 if (i >= 0) {
781 AString value = request->mHeaders.valueAt(i);
782
783 unsigned long cseq;
784 if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) {
785 return false;
786 }
787
788 response.append("CSeq: ");
789 response.append(cseq);
790 response.append("\r\n");
791 }
792
793 response.append("\r\n");
794
795 size_t numBytesSent = 0;
796 while (numBytesSent < response.size()) {
797 ssize_t n =
798 send(mSocket, response.c_str() + numBytesSent,
799 response.size() - numBytesSent, 0);
800
801 if (n < 0 && errno == EINTR) {
802 continue;
803 }
804
805 if (n <= 0) {
806 if (n == 0) {
807 // Server closed the connection.
808 ALOGE("Server unexpectedly closed the connection.");
809 } else {
810 ALOGE("Error sending rtsp response (%s).", strerror(errno));
811 }
812
813 performDisconnect();
814
815 return false;
816 }
817
818 numBytesSent += (size_t)n;
819 }
820
821 return true;
822 }
823
824 // static
ParseSingleUnsignedLong(const char * from,unsigned long * x)825 bool ARTSPConnection::ParseSingleUnsignedLong(
826 const char *from, unsigned long *x) {
827 char *end;
828 *x = strtoul(from, &end, 10);
829
830 if (end == from || *end != '\0') {
831 return false;
832 }
833
834 return true;
835 }
836
findPendingRequest(const sp<ARTSPResponse> & response,ssize_t * index) const837 status_t ARTSPConnection::findPendingRequest(
838 const sp<ARTSPResponse> &response, ssize_t *index) const {
839 *index = 0;
840
841 ssize_t i = response->mHeaders.indexOfKey("cseq");
842
843 if (i < 0) {
844 // This is an unsolicited server->client message.
845 *index = -1;
846 return OK;
847 }
848
849 AString value = response->mHeaders.valueAt(i);
850
851 unsigned long cseq;
852 if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) {
853 return ERROR_MALFORMED;
854 }
855
856 i = mPendingRequests.indexOfKey(cseq);
857
858 if (i < 0) {
859 return -ENOENT;
860 }
861
862 *index = i;
863
864 return OK;
865 }
866
notifyResponseListener(const sp<ARTSPResponse> & response)867 bool ARTSPConnection::notifyResponseListener(
868 const sp<ARTSPResponse> &response) {
869 ssize_t i;
870 status_t err = findPendingRequest(response, &i);
871
872 if (err == OK && i < 0) {
873 // An unsolicited server response is not a problem.
874 return true;
875 }
876
877 if (err != OK) {
878 return false;
879 }
880
881 sp<AMessage> reply = mPendingRequests.valueAt(i);
882 mPendingRequests.removeItemsAt(i);
883
884 reply->setInt32("result", OK);
885 reply->setObject("response", response);
886 reply->post();
887
888 return true;
889 }
890
parseAuthMethod(const sp<ARTSPResponse> & response)891 bool ARTSPConnection::parseAuthMethod(const sp<ARTSPResponse> &response) {
892 ssize_t i = response->mHeaders.indexOfKey("www-authenticate");
893
894 if (i < 0) {
895 return false;
896 }
897
898 AString value = response->mHeaders.valueAt(i);
899
900 if (!strncmp(value.c_str(), "Basic", 5)) {
901 mAuthType = BASIC;
902 } else {
903
904 CHECK(!strncmp(value.c_str(), "Digest", 6));
905 mAuthType = DIGEST;
906
907 i = value.find("nonce=");
908 CHECK_GE(i, 0);
909 CHECK_EQ(value.c_str()[i + 6], '\"');
910 ssize_t j = value.find("\"", i + 7);
911 CHECK_GE(j, 0);
912
913 mNonce.setTo(value, i + 7, j - i - 7);
914 }
915
916 return true;
917 }
918
H(const AString & s,AString * out)919 static void H(const AString &s, AString *out) {
920 out->clear();
921
922 MD5_CTX m;
923 MD5_Init(&m);
924 MD5_Update(&m, s.c_str(), s.size());
925
926 uint8_t key[16];
927 MD5_Final(key, &m);
928
929 for (size_t i = 0; i < 16; ++i) {
930 char nibble = key[i] >> 4;
931 if (nibble <= 9) {
932 nibble += '0';
933 } else {
934 nibble += 'a' - 10;
935 }
936 out->append(&nibble, 1);
937
938 nibble = key[i] & 0x0f;
939 if (nibble <= 9) {
940 nibble += '0';
941 } else {
942 nibble += 'a' - 10;
943 }
944 out->append(&nibble, 1);
945 }
946 }
947
GetMethodAndURL(const AString & request,AString * method,AString * url)948 static void GetMethodAndURL(
949 const AString &request, AString *method, AString *url) {
950 ssize_t space1 = request.find(" ");
951 CHECK_GE(space1, 0);
952
953 ssize_t space2 = request.find(" ", space1 + 1);
954 CHECK_GE(space2, 0);
955
956 method->setTo(request, 0, space1);
957 url->setTo(request, space1 + 1, space2 - space1 - 1);
958 }
959
addAuthentication(AString * request)960 void ARTSPConnection::addAuthentication(AString *request) {
961 if (mAuthType == NONE) {
962 return;
963 }
964
965 // Find the boundary between headers and the body.
966 ssize_t i = request->find("\r\n\r\n");
967 CHECK_GE(i, 0);
968
969 if (mAuthType == BASIC) {
970 AString tmp;
971 tmp.append(mUser);
972 tmp.append(":");
973 tmp.append(mPass);
974
975 AString out;
976 encodeBase64(tmp.c_str(), tmp.size(), &out);
977
978 AString fragment;
979 fragment.append("Authorization: Basic ");
980 fragment.append(out);
981 fragment.append("\r\n");
982
983 request->insert(fragment, i + 2);
984
985 return;
986 }
987
988 CHECK_EQ((int)mAuthType, (int)DIGEST);
989
990 AString method, url;
991 GetMethodAndURL(*request, &method, &url);
992
993 AString A1;
994 A1.append(mUser);
995 A1.append(":");
996 A1.append("Streaming Server");
997 A1.append(":");
998 A1.append(mPass);
999
1000 AString A2;
1001 A2.append(method);
1002 A2.append(":");
1003 A2.append(url);
1004
1005 AString HA1, HA2;
1006 H(A1, &HA1);
1007 H(A2, &HA2);
1008
1009 AString tmp;
1010 tmp.append(HA1);
1011 tmp.append(":");
1012 tmp.append(mNonce);
1013 tmp.append(":");
1014 tmp.append(HA2);
1015
1016 AString digest;
1017 H(tmp, &digest);
1018
1019 AString fragment;
1020 fragment.append("Authorization: Digest ");
1021 fragment.append("nonce=\"");
1022 fragment.append(mNonce);
1023 fragment.append("\", ");
1024 fragment.append("username=\"");
1025 fragment.append(mUser);
1026 fragment.append("\", ");
1027 fragment.append("uri=\"");
1028 fragment.append(url);
1029 fragment.append("\", ");
1030 fragment.append("response=\"");
1031 fragment.append(digest);
1032 fragment.append("\"");
1033 fragment.append("\r\n");
1034
1035 request->insert(fragment, i + 2);
1036 }
1037
addUserAgent(AString * request) const1038 void ARTSPConnection::addUserAgent(AString *request) const {
1039 // Find the boundary between headers and the body.
1040 ssize_t i = request->find("\r\n\r\n");
1041 CHECK_GE(i, 0);
1042
1043 request->insert(sUserAgent, i + 2);
1044 }
1045
1046 } // namespace android
1047