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