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