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