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