blob: 12cca134de1801b42ef4b272bb796703f9cb9929 [file] [log] [blame]
Andreas Huber7a747b82010-06-07 15:19:40 -07001/*
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
Andreas Huber6e3fa442010-09-21 13:13:15 -070017//#define LOG_NDEBUG 0
18#define LOG_TAG "ARTSPConnection"
19#include <utils/Log.h>
20
Andreas Huber7a747b82010-06-07 15:19:40 -070021#include "ARTSPConnection.h"
22
Andreas Huberb0e73812011-03-29 13:34:28 -070023#include <cutils/properties.h>
24
Andreas Huber7a747b82010-06-07 15:19:40 -070025#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/foundation/AMessage.h>
Andreas Hubera0b442e2010-10-20 15:00:34 -070028#include <media/stagefright/foundation/base64.h>
Andreas Huber0416da72010-08-26 11:17:32 -070029#include <media/stagefright/MediaErrors.h>
Andreas Huber7a747b82010-06-07 15:19:40 -070030
31#include <arpa/inet.h>
32#include <fcntl.h>
33#include <netdb.h>
Andreas Hubera0b442e2010-10-20 15:00:34 -070034#include <openssl/md5.h>
Andreas Huber7a747b82010-06-07 15:19:40 -070035#include <sys/socket.h>
36
Andreas Huberc3119332011-07-13 15:45:01 -070037#include "HTTPBase.h"
Andreas Huber603d7392011-06-30 15:47:02 -070038
Andreas Huber7a747b82010-06-07 15:19:40 -070039namespace android {
40
41// static
42const int64_t ARTSPConnection::kSelectTimeoutUs = 1000ll;
43
Andreas Huber603d7392011-06-30 15:47:02 -070044ARTSPConnection::ARTSPConnection(bool uidValid, uid_t uid)
45 : mUIDValid(uidValid),
46 mUID(uid),
47 mState(DISCONNECTED),
Andreas Hubera0b442e2010-10-20 15:00:34 -070048 mAuthType(NONE),
Andreas Huber7a747b82010-06-07 15:19:40 -070049 mSocket(-1),
50 mConnectionID(0),
51 mNextCSeq(0),
52 mReceiveResponseEventPending(false) {
Andreas Huberb0e73812011-03-29 13:34:28 -070053 MakeUserAgent(&mUserAgent);
Andreas Huber7a747b82010-06-07 15:19:40 -070054}
55
56ARTSPConnection::~ARTSPConnection() {
57 if (mSocket >= 0) {
Andreas Huber6e3fa442010-09-21 13:13:15 -070058 LOGE("Connection is still open, closing the socket.");
Ashish Sharmad5a20d82011-07-07 17:57:05 -070059 if (mUIDValid) {
60 HTTPBase::UnRegisterSocketUserTag(mSocket);
61 }
Andreas Huber7a747b82010-06-07 15:19:40 -070062 close(mSocket);
63 mSocket = -1;
64 }
65}
66
67void ARTSPConnection::connect(const char *url, const sp<AMessage> &reply) {
68 sp<AMessage> msg = new AMessage(kWhatConnect, id());
69 msg->setString("url", url);
70 msg->setMessage("reply", reply);
71 msg->post();
72}
73
74void ARTSPConnection::disconnect(const sp<AMessage> &reply) {
75 sp<AMessage> msg = new AMessage(kWhatDisconnect, id());
76 msg->setMessage("reply", reply);
77 msg->post();
78}
79
80void ARTSPConnection::sendRequest(
81 const char *request, const sp<AMessage> &reply) {
82 sp<AMessage> msg = new AMessage(kWhatSendRequest, id());
83 msg->setString("request", request);
84 msg->setMessage("reply", reply);
85 msg->post();
86}
87
Andreas Huber0416da72010-08-26 11:17:32 -070088void ARTSPConnection::observeBinaryData(const sp<AMessage> &reply) {
89 sp<AMessage> msg = new AMessage(kWhatObserveBinaryData, id());
90 msg->setMessage("reply", reply);
91 msg->post();
92}
93
Andreas Huber7a747b82010-06-07 15:19:40 -070094void ARTSPConnection::onMessageReceived(const sp<AMessage> &msg) {
95 switch (msg->what()) {
96 case kWhatConnect:
97 onConnect(msg);
98 break;
99
100 case kWhatDisconnect:
101 onDisconnect(msg);
102 break;
103
104 case kWhatCompleteConnection:
105 onCompleteConnection(msg);
106 break;
107
108 case kWhatSendRequest:
109 onSendRequest(msg);
110 break;
111
112 case kWhatReceiveResponse:
113 onReceiveResponse();
114 break;
115
Andreas Huber0416da72010-08-26 11:17:32 -0700116 case kWhatObserveBinaryData:
117 {
118 CHECK(msg->findMessage("reply", &mObserveBinaryMessage));
119 break;
120 }
121
Andreas Huber7a747b82010-06-07 15:19:40 -0700122 default:
123 TRESPASS();
124 break;
125 }
126}
127
128// static
129bool ARTSPConnection::ParseURL(
Andreas Hubera0b442e2010-10-20 15:00:34 -0700130 const char *url, AString *host, unsigned *port, AString *path,
131 AString *user, AString *pass) {
Andreas Huber7a747b82010-06-07 15:19:40 -0700132 host->clear();
133 *port = 0;
134 path->clear();
Andreas Hubera0b442e2010-10-20 15:00:34 -0700135 user->clear();
136 pass->clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700137
138 if (strncasecmp("rtsp://", url, 7)) {
139 return false;
140 }
141
142 const char *slashPos = strchr(&url[7], '/');
143
144 if (slashPos == NULL) {
145 host->setTo(&url[7]);
146 path->setTo("/");
147 } else {
148 host->setTo(&url[7], slashPos - &url[7]);
149 path->setTo(slashPos);
150 }
151
Andreas Hubera0b442e2010-10-20 15:00:34 -0700152 ssize_t atPos = host->find("@");
153
154 if (atPos >= 0) {
155 // Split of user:pass@ from hostname.
156
157 AString userPass(*host, 0, atPos);
158 host->erase(0, atPos + 1);
159
160 ssize_t colonPos = userPass.find(":");
161
162 if (colonPos < 0) {
163 *user = userPass;
164 } else {
165 user->setTo(userPass, 0, colonPos);
166 pass->setTo(userPass, colonPos + 1, userPass.size() - colonPos - 1);
167 }
168 }
169
Mike Lockwood5a23f8c2010-07-15 14:58:25 -0400170 const char *colonPos = strchr(host->c_str(), ':');
Andreas Huber7a747b82010-06-07 15:19:40 -0700171
172 if (colonPos != NULL) {
173 unsigned long x;
174 if (!ParseSingleUnsignedLong(colonPos + 1, &x) || x >= 65536) {
175 return false;
176 }
177
178 *port = x;
179
180 size_t colonOffset = colonPos - host->c_str();
181 size_t trailing = host->size() - colonOffset;
182 host->erase(colonOffset, trailing);
183 } else {
184 *port = 554;
185 }
186
187 return true;
188}
189
Andreas Huber58c94bf2011-11-10 14:48:20 -0800190static status_t MakeSocketBlocking(int s, bool blocking) {
Andreas Huberaf063a62010-08-18 10:17:18 -0700191 // Make socket non-blocking.
192 int flags = fcntl(s, F_GETFL, 0);
Andreas Huber58c94bf2011-11-10 14:48:20 -0800193
194 if (flags == -1) {
195 return UNKNOWN_ERROR;
196 }
Andreas Huberaf063a62010-08-18 10:17:18 -0700197
198 if (blocking) {
199 flags &= ~O_NONBLOCK;
200 } else {
201 flags |= O_NONBLOCK;
202 }
203
Andreas Huber58c94bf2011-11-10 14:48:20 -0800204 flags = fcntl(s, F_SETFL, flags);
205
206 return flags == -1 ? UNKNOWN_ERROR : OK;
Andreas Huberaf063a62010-08-18 10:17:18 -0700207}
208
Andreas Huber7a747b82010-06-07 15:19:40 -0700209void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
210 ++mConnectionID;
211
212 if (mState != DISCONNECTED) {
Ashish Sharmad5a20d82011-07-07 17:57:05 -0700213 if (mUIDValid) {
214 HTTPBase::UnRegisterSocketUserTag(mSocket);
215 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700216 close(mSocket);
217 mSocket = -1;
218
219 flushPendingRequests();
220 }
221
222 mState = CONNECTING;
223
Andreas Huber7a747b82010-06-07 15:19:40 -0700224 AString url;
225 CHECK(msg->findString("url", &url));
226
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700227 sp<AMessage> reply;
228 CHECK(msg->findMessage("reply", &reply));
229
Andreas Huber7a747b82010-06-07 15:19:40 -0700230 AString host, path;
231 unsigned port;
Andreas Hubera0b442e2010-10-20 15:00:34 -0700232 if (!ParseURL(url.c_str(), &host, &port, &path, &mUser, &mPass)
233 || (mUser.size() > 0 && mPass.size() == 0)) {
234 // If we have a user name but no password we have to give up
235 // right here, since we currently have no way of asking the user
236 // for this information.
237
Andreas Huber6e3fa442010-09-21 13:13:15 -0700238 LOGE("Malformed rtsp url %s", url.c_str());
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700239
240 reply->setInt32("result", ERROR_MALFORMED);
241 reply->post();
242
243 mState = DISCONNECTED;
244 return;
245 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700246
Andreas Hubera0b442e2010-10-20 15:00:34 -0700247 if (mUser.size() > 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100248 ALOGV("user = '%s', pass = '%s'", mUser.c_str(), mPass.c_str());
Andreas Hubera0b442e2010-10-20 15:00:34 -0700249 }
250
Andreas Huber7a747b82010-06-07 15:19:40 -0700251 struct hostent *ent = gethostbyname(host.c_str());
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700252 if (ent == NULL) {
Andreas Huber6e3fa442010-09-21 13:13:15 -0700253 LOGE("Unknown host %s", host.c_str());
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700254
255 reply->setInt32("result", -ENOENT);
256 reply->post();
257
258 mState = DISCONNECTED;
259 return;
260 }
261
262 mSocket = socket(AF_INET, SOCK_STREAM, 0);
263
Andreas Huber603d7392011-06-30 15:47:02 -0700264 if (mUIDValid) {
Ashish Sharmad5a20d82011-07-07 17:57:05 -0700265 HTTPBase::RegisterSocketUserTag(mSocket, mUID,
266 (uint32_t)*(uint32_t*) "RTSP");
Andreas Huber603d7392011-06-30 15:47:02 -0700267 }
268
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700269 MakeSocketBlocking(mSocket, false);
Andreas Huber7a747b82010-06-07 15:19:40 -0700270
271 struct sockaddr_in remote;
272 memset(remote.sin_zero, 0, sizeof(remote.sin_zero));
273 remote.sin_family = AF_INET;
274 remote.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
275 remote.sin_port = htons(port);
276
277 int err = ::connect(
278 mSocket, (const struct sockaddr *)&remote, sizeof(remote));
279
Andreas Huber7a747b82010-06-07 15:19:40 -0700280 reply->setInt32("server-ip", ntohl(remote.sin_addr.s_addr));
281
282 if (err < 0) {
283 if (errno == EINPROGRESS) {
284 sp<AMessage> msg = new AMessage(kWhatCompleteConnection, id());
285 msg->setMessage("reply", reply);
286 msg->setInt32("connection-id", mConnectionID);
287 msg->post();
288 return;
289 }
290
291 reply->setInt32("result", -errno);
292 mState = DISCONNECTED;
293
Ashish Sharmad5a20d82011-07-07 17:57:05 -0700294 if (mUIDValid) {
295 HTTPBase::UnRegisterSocketUserTag(mSocket);
296 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700297 close(mSocket);
298 mSocket = -1;
299 } else {
300 reply->setInt32("result", OK);
301 mState = CONNECTED;
302 mNextCSeq = 1;
303
304 postReceiveReponseEvent();
305 }
306
307 reply->post();
308}
309
Andreas Huber58c94bf2011-11-10 14:48:20 -0800310void ARTSPConnection::performDisconnect() {
311 if (mUIDValid) {
312 HTTPBase::UnRegisterSocketUserTag(mSocket);
313 }
314 close(mSocket);
315 mSocket = -1;
316
317 flushPendingRequests();
318
319 mUser.clear();
320 mPass.clear();
321 mAuthType = NONE;
322 mNonce.clear();
323
324 mState = DISCONNECTED;
325}
326
Andreas Huber7a747b82010-06-07 15:19:40 -0700327void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) {
328 if (mState == CONNECTED || mState == CONNECTING) {
Andreas Huber58c94bf2011-11-10 14:48:20 -0800329 performDisconnect();
Andreas Huberaf063a62010-08-18 10:17:18 -0700330 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700331
332 sp<AMessage> reply;
333 CHECK(msg->findMessage("reply", &reply));
334
335 reply->setInt32("result", OK);
Andreas Hubera0b442e2010-10-20 15:00:34 -0700336
Andreas Huber7a747b82010-06-07 15:19:40 -0700337 reply->post();
338}
339
340void ARTSPConnection::onCompleteConnection(const sp<AMessage> &msg) {
341 sp<AMessage> reply;
342 CHECK(msg->findMessage("reply", &reply));
343
344 int32_t connectionID;
345 CHECK(msg->findInt32("connection-id", &connectionID));
346
347 if ((connectionID != mConnectionID) || mState != CONNECTING) {
348 // While we were attempting to connect, the attempt was
349 // cancelled.
350 reply->setInt32("result", -ECONNABORTED);
351 reply->post();
352 return;
353 }
354
355 struct timeval tv;
356 tv.tv_sec = 0;
357 tv.tv_usec = kSelectTimeoutUs;
358
359 fd_set ws;
360 FD_ZERO(&ws);
361 FD_SET(mSocket, &ws);
362
363 int res = select(mSocket + 1, NULL, &ws, NULL, &tv);
364 CHECK_GE(res, 0);
365
366 if (res == 0) {
367 // Timed out. Not yet connected.
368
369 msg->post();
370 return;
371 }
372
373 int err;
374 socklen_t optionLen = sizeof(err);
375 CHECK_EQ(getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &err, &optionLen), 0);
376 CHECK_EQ(optionLen, (socklen_t)sizeof(err));
377
378 if (err != 0) {
Andreas Huber6e3fa442010-09-21 13:13:15 -0700379 LOGE("err = %d (%s)", err, strerror(err));
Andreas Huber7a747b82010-06-07 15:19:40 -0700380
381 reply->setInt32("result", -err);
382
383 mState = DISCONNECTED;
Ashish Sharmad5a20d82011-07-07 17:57:05 -0700384 if (mUIDValid) {
385 HTTPBase::UnRegisterSocketUserTag(mSocket);
386 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700387 close(mSocket);
388 mSocket = -1;
389 } else {
390 reply->setInt32("result", OK);
391 mState = CONNECTED;
392 mNextCSeq = 1;
393
394 postReceiveReponseEvent();
395 }
396
397 reply->post();
398}
399
400void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) {
401 sp<AMessage> reply;
402 CHECK(msg->findMessage("reply", &reply));
403
404 if (mState != CONNECTED) {
405 reply->setInt32("result", -ENOTCONN);
406 reply->post();
407 return;
408 }
409
410 AString request;
411 CHECK(msg->findString("request", &request));
412
Andreas Hubera0b442e2010-10-20 15:00:34 -0700413 // Just in case we need to re-issue the request with proper authentication
414 // later, stash it away.
415 reply->setString("original-request", request.c_str(), request.size());
416
417 addAuthentication(&request);
Andreas Huberb0e73812011-03-29 13:34:28 -0700418 addUserAgent(&request);
Andreas Hubera0b442e2010-10-20 15:00:34 -0700419
Andreas Huber7a747b82010-06-07 15:19:40 -0700420 // Find the boundary between headers and the body.
421 ssize_t i = request.find("\r\n\r\n");
422 CHECK_GE(i, 0);
423
424 int32_t cseq = mNextCSeq++;
425
426 AString cseqHeader = "CSeq: ";
427 cseqHeader.append(cseq);
428 cseqHeader.append("\r\n");
429
430 request.insert(cseqHeader, i + 2);
431
Steve Block71f2cf12011-10-20 11:56:00 +0100432 ALOGV("request: '%s'", request.c_str());
Andreas Huber7a747b82010-06-07 15:19:40 -0700433
434 size_t numBytesSent = 0;
435 while (numBytesSent < request.size()) {
436 ssize_t n =
437 send(mSocket, request.c_str() + numBytesSent,
438 request.size() - numBytesSent, 0);
439
Andreas Huber58c94bf2011-11-10 14:48:20 -0800440 if (n < 0 && errno == EINTR) {
441 continue;
442 }
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700443
Andreas Huber58c94bf2011-11-10 14:48:20 -0800444 if (n <= 0) {
445 performDisconnect();
446
447 if (n == 0) {
448 // Server closed the connection.
449 LOGE("Server unexpectedly closed the connection.");
450
451 reply->setInt32("result", ERROR_IO);
452 reply->post();
453 } else {
454 LOGE("Error sending rtsp request. (%s)", strerror(errno));
455 reply->setInt32("result", -errno);
456 reply->post();
Andreas Huber7a747b82010-06-07 15:19:40 -0700457 }
458
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700459 return;
Andreas Huber7a747b82010-06-07 15:19:40 -0700460 }
461
462 numBytesSent += (size_t)n;
463 }
464
465 mPendingRequests.add(cseq, reply);
466}
467
468void ARTSPConnection::onReceiveResponse() {
469 mReceiveResponseEventPending = false;
470
471 if (mState != CONNECTED) {
472 return;
473 }
474
475 struct timeval tv;
476 tv.tv_sec = 0;
477 tv.tv_usec = kSelectTimeoutUs;
478
479 fd_set rs;
480 FD_ZERO(&rs);
481 FD_SET(mSocket, &rs);
482
483 int res = select(mSocket + 1, &rs, NULL, NULL, &tv);
484 CHECK_GE(res, 0);
485
486 if (res == 1) {
Andreas Huberaf063a62010-08-18 10:17:18 -0700487 MakeSocketBlocking(mSocket, true);
488
489 bool success = receiveRTSPReponse();
490
491 MakeSocketBlocking(mSocket, false);
492
493 if (!success) {
Andreas Huber7a747b82010-06-07 15:19:40 -0700494 // Something horrible, irreparable has happened.
495 flushPendingRequests();
496 return;
497 }
498 }
499
500 postReceiveReponseEvent();
501}
502
503void ARTSPConnection::flushPendingRequests() {
504 for (size_t i = 0; i < mPendingRequests.size(); ++i) {
505 sp<AMessage> reply = mPendingRequests.valueAt(i);
506
507 reply->setInt32("result", -ECONNABORTED);
508 reply->post();
509 }
510
511 mPendingRequests.clear();
512}
513
514void ARTSPConnection::postReceiveReponseEvent() {
515 if (mReceiveResponseEventPending) {
516 return;
517 }
518
519 sp<AMessage> msg = new AMessage(kWhatReceiveResponse, id());
520 msg->post();
521
522 mReceiveResponseEventPending = true;
523}
524
Andreas Huber0416da72010-08-26 11:17:32 -0700525status_t ARTSPConnection::receive(void *data, size_t size) {
526 size_t offset = 0;
527 while (offset < size) {
528 ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0);
Andreas Huber7a747b82010-06-07 15:19:40 -0700529
Andreas Huber58c94bf2011-11-10 14:48:20 -0800530 if (n < 0 && errno == EINTR) {
531 continue;
532 }
533
534 if (n <= 0) {
535 performDisconnect();
536
537 if (n == 0) {
538 // Server closed the connection.
539 LOGE("Server unexpectedly closed the connection.");
540 return ERROR_IO;
541 } else {
542 LOGE("Error reading rtsp response. (%s)", strerror(errno));
543 return -errno;
544 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700545 }
546
Andreas Huber0416da72010-08-26 11:17:32 -0700547 offset += (size_t)n;
548 }
549
550 return OK;
551}
552
553bool ARTSPConnection::receiveLine(AString *line) {
554 line->clear();
555
556 bool sawCR = false;
557 for (;;) {
558 char c;
559 if (receive(&c, 1) != OK) {
560 return false;
561 }
562
Andreas Huber7a747b82010-06-07 15:19:40 -0700563 if (sawCR && c == '\n') {
564 line->erase(line->size() - 1, 1);
565 return true;
566 }
567
568 line->append(&c, 1);
569
Andreas Huber0416da72010-08-26 11:17:32 -0700570 if (c == '$' && line->size() == 1) {
571 // Special-case for interleaved binary data.
572 return true;
573 }
574
Andreas Huber7a747b82010-06-07 15:19:40 -0700575 sawCR = (c == '\r');
576 }
577}
578
Andreas Huber0416da72010-08-26 11:17:32 -0700579sp<ABuffer> ARTSPConnection::receiveBinaryData() {
580 uint8_t x[3];
581 if (receive(x, 3) != OK) {
582 return NULL;
583 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700584
Andreas Huber0416da72010-08-26 11:17:32 -0700585 sp<ABuffer> buffer = new ABuffer((x[1] << 8) | x[2]);
586 if (receive(buffer->data(), buffer->size()) != OK) {
587 return NULL;
588 }
589
590 buffer->meta()->setInt32("index", (int32_t)x[0]);
591
592 return buffer;
593}
594
Andreas Hubere0666162011-02-16 13:20:02 -0800595static bool IsRTSPVersion(const AString &s) {
596 return s == "RTSP/1.0";
597}
598
Andreas Huber0416da72010-08-26 11:17:32 -0700599bool ARTSPConnection::receiveRTSPReponse() {
600 AString statusLine;
601
602 if (!receiveLine(&statusLine)) {
Andreas Huber7a747b82010-06-07 15:19:40 -0700603 return false;
604 }
605
Andreas Huber0416da72010-08-26 11:17:32 -0700606 if (statusLine == "$") {
607 sp<ABuffer> buffer = receiveBinaryData();
608
609 if (buffer == NULL) {
610 return false;
611 }
612
613 if (mObserveBinaryMessage != NULL) {
614 sp<AMessage> notify = mObserveBinaryMessage->dup();
615 notify->setObject("buffer", buffer);
616 notify->post();
617 } else {
Andreas Huber6e3fa442010-09-21 13:13:15 -0700618 LOGW("received binary data, but no one cares.");
Andreas Huber0416da72010-08-26 11:17:32 -0700619 }
620
621 return true;
622 }
623
624 sp<ARTSPResponse> response = new ARTSPResponse;
625 response->mStatusLine = statusLine;
626
Steve Block6215d3f2012-01-04 20:05:49 +0000627 ALOGI("status: %s", response->mStatusLine.c_str());
Andreas Huber7a747b82010-06-07 15:19:40 -0700628
629 ssize_t space1 = response->mStatusLine.find(" ");
630 if (space1 < 0) {
631 return false;
632 }
633 ssize_t space2 = response->mStatusLine.find(" ", space1 + 1);
634 if (space2 < 0) {
635 return false;
636 }
637
Andreas Hubere0666162011-02-16 13:20:02 -0800638 bool isRequest = false;
Andreas Huber7a747b82010-06-07 15:19:40 -0700639
Andreas Hubere0666162011-02-16 13:20:02 -0800640 if (!IsRTSPVersion(AString(response->mStatusLine, 0, space1))) {
641 CHECK(IsRTSPVersion(
642 AString(
643 response->mStatusLine,
644 space2 + 1,
645 response->mStatusLine.size() - space2 - 1)));
646
647 isRequest = true;
648
649 response->mStatusCode = 0;
650 } else {
651 AString statusCodeStr(
652 response->mStatusLine, space1 + 1, space2 - space1 - 1);
653
654 if (!ParseSingleUnsignedLong(
655 statusCodeStr.c_str(), &response->mStatusCode)
656 || response->mStatusCode < 100 || response->mStatusCode > 999) {
657 return false;
658 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700659 }
660
661 AString line;
Andreas Huber9f62e152011-12-09 15:09:56 -0800662 ssize_t lastDictIndex = -1;
Andreas Huber7a747b82010-06-07 15:19:40 -0700663 for (;;) {
664 if (!receiveLine(&line)) {
665 break;
666 }
667
668 if (line.empty()) {
669 break;
670 }
671
Andreas Huber9f62e152011-12-09 15:09:56 -0800672 ALOGV("line: '%s'", line.c_str());
673
674 if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') {
675 // Support for folded header values.
676
677 if (lastDictIndex < 0) {
678 // First line cannot be a continuation of the previous one.
679 return false;
680 }
681
682 AString &value = response->mHeaders.editValueAt(lastDictIndex);
683 value.append(line);
684
685 continue;
686 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700687
688 ssize_t colonPos = line.find(":");
689 if (colonPos < 0) {
690 // Malformed header line.
691 return false;
692 }
693
694 AString key(line, 0, colonPos);
695 key.trim();
696 key.tolower();
697
698 line.erase(0, colonPos + 1);
Andreas Huber7a747b82010-06-07 15:19:40 -0700699
Andreas Huber9f62e152011-12-09 15:09:56 -0800700 lastDictIndex = response->mHeaders.add(key, line);
701 }
702
703 for (size_t i = 0; i < response->mHeaders.size(); ++i) {
704 response->mHeaders.editValueAt(i).trim();
Andreas Huber7a747b82010-06-07 15:19:40 -0700705 }
706
707 unsigned long contentLength = 0;
708
709 ssize_t i = response->mHeaders.indexOfKey("content-length");
710
711 if (i >= 0) {
712 AString value = response->mHeaders.valueAt(i);
713 if (!ParseSingleUnsignedLong(value.c_str(), &contentLength)) {
714 return false;
715 }
716 }
717
718 if (contentLength > 0) {
719 response->mContent = new ABuffer(contentLength);
720
Andreas Huber58c94bf2011-11-10 14:48:20 -0800721 if (receive(response->mContent->data(), contentLength) != OK) {
722 return false;
Andreas Huber7a747b82010-06-07 15:19:40 -0700723 }
724 }
725
Andreas Hubera0b442e2010-10-20 15:00:34 -0700726 if (response->mStatusCode == 401) {
727 if (mAuthType == NONE && mUser.size() > 0
728 && parseAuthMethod(response)) {
729 ssize_t i;
730 CHECK_EQ((status_t)OK, findPendingRequest(response, &i));
731 CHECK_GE(i, 0);
732
733 sp<AMessage> reply = mPendingRequests.valueAt(i);
734 mPendingRequests.removeItemsAt(i);
735
736 AString request;
737 CHECK(reply->findString("original-request", &request));
738
739 sp<AMessage> msg = new AMessage(kWhatSendRequest, id());
740 msg->setMessage("reply", reply);
741 msg->setString("request", request.c_str(), request.size());
742
Steve Block6215d3f2012-01-04 20:05:49 +0000743 ALOGI("re-sending request with authentication headers...");
Andreas Hubera0b442e2010-10-20 15:00:34 -0700744 onSendRequest(msg);
745
746 return true;
747 }
748 }
749
Andreas Hubere0666162011-02-16 13:20:02 -0800750 return isRequest
751 ? handleServerRequest(response)
752 : notifyResponseListener(response);
753}
754
755bool ARTSPConnection::handleServerRequest(const sp<ARTSPResponse> &request) {
756 // Implementation of server->client requests is optional for all methods
757 // but we do need to respond, even if it's just to say that we don't
758 // support the method.
759
760 ssize_t space1 = request->mStatusLine.find(" ");
761 CHECK_GE(space1, 0);
762
763 AString response;
764 response.append("RTSP/1.0 501 Not Implemented\r\n");
765
766 ssize_t i = request->mHeaders.indexOfKey("cseq");
767
768 if (i >= 0) {
769 AString value = request->mHeaders.valueAt(i);
770
771 unsigned long cseq;
772 if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) {
773 return false;
774 }
775
776 response.append("CSeq: ");
777 response.append(cseq);
778 response.append("\r\n");
779 }
780
781 response.append("\r\n");
782
783 size_t numBytesSent = 0;
784 while (numBytesSent < response.size()) {
785 ssize_t n =
786 send(mSocket, response.c_str() + numBytesSent,
787 response.size() - numBytesSent, 0);
788
Andreas Huber58c94bf2011-11-10 14:48:20 -0800789 if (n < 0 && errno == EINTR) {
790 continue;
791 }
Andreas Hubere0666162011-02-16 13:20:02 -0800792
Andreas Huber58c94bf2011-11-10 14:48:20 -0800793 if (n <= 0) {
794 if (n == 0) {
795 // Server closed the connection.
796 LOGE("Server unexpectedly closed the connection.");
797 } else {
798 LOGE("Error sending rtsp response (%s).", strerror(errno));
Andreas Hubere0666162011-02-16 13:20:02 -0800799 }
800
Andreas Huber58c94bf2011-11-10 14:48:20 -0800801 performDisconnect();
802
Andreas Hubere0666162011-02-16 13:20:02 -0800803 return false;
804 }
805
806 numBytesSent += (size_t)n;
807 }
808
809 return true;
Andreas Huber7a747b82010-06-07 15:19:40 -0700810}
811
812// static
813bool ARTSPConnection::ParseSingleUnsignedLong(
814 const char *from, unsigned long *x) {
815 char *end;
816 *x = strtoul(from, &end, 10);
817
818 if (end == from || *end != '\0') {
819 return false;
820 }
821
822 return true;
823}
824
Andreas Hubera0b442e2010-10-20 15:00:34 -0700825status_t ARTSPConnection::findPendingRequest(
826 const sp<ARTSPResponse> &response, ssize_t *index) const {
827 *index = 0;
828
Andreas Huber7a747b82010-06-07 15:19:40 -0700829 ssize_t i = response->mHeaders.indexOfKey("cseq");
830
831 if (i < 0) {
Andreas Hubera0b442e2010-10-20 15:00:34 -0700832 // This is an unsolicited server->client message.
833 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -0700834 }
835
836 AString value = response->mHeaders.valueAt(i);
837
838 unsigned long cseq;
839 if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) {
Andreas Hubera0b442e2010-10-20 15:00:34 -0700840 return ERROR_MALFORMED;
Andreas Huber7a747b82010-06-07 15:19:40 -0700841 }
842
843 i = mPendingRequests.indexOfKey(cseq);
844
845 if (i < 0) {
Andreas Hubera0b442e2010-10-20 15:00:34 -0700846 return -ENOENT;
847 }
848
849 *index = i;
850
851 return OK;
852}
853
854bool ARTSPConnection::notifyResponseListener(
855 const sp<ARTSPResponse> &response) {
856 ssize_t i;
857 status_t err = findPendingRequest(response, &i);
858
859 if (err == OK && i < 0) {
860 // An unsolicited server response is not a problem.
861 return true;
862 }
863
864 if (err != OK) {
865 return false;
Andreas Huber7a747b82010-06-07 15:19:40 -0700866 }
867
868 sp<AMessage> reply = mPendingRequests.valueAt(i);
869 mPendingRequests.removeItemsAt(i);
870
871 reply->setInt32("result", OK);
872 reply->setObject("response", response);
873 reply->post();
874
875 return true;
876}
877
Andreas Hubera0b442e2010-10-20 15:00:34 -0700878bool ARTSPConnection::parseAuthMethod(const sp<ARTSPResponse> &response) {
879 ssize_t i = response->mHeaders.indexOfKey("www-authenticate");
880
881 if (i < 0) {
882 return false;
883 }
884
885 AString value = response->mHeaders.valueAt(i);
886
887 if (!strncmp(value.c_str(), "Basic", 5)) {
888 mAuthType = BASIC;
889 } else {
Andreas Hubercf747542010-10-25 09:40:52 -0700890#if !defined(HAVE_ANDROID_OS)
891 // We don't have access to the MD5 implementation on the simulator,
892 // so we won't support digest authentication.
893 return false;
894#endif
895
Andreas Hubera0b442e2010-10-20 15:00:34 -0700896 CHECK(!strncmp(value.c_str(), "Digest", 6));
897 mAuthType = DIGEST;
898
899 i = value.find("nonce=");
900 CHECK_GE(i, 0);
901 CHECK_EQ(value.c_str()[i + 6], '\"');
902 ssize_t j = value.find("\"", i + 7);
903 CHECK_GE(j, 0);
904
905 mNonce.setTo(value, i + 7, j - i - 7);
906 }
907
908 return true;
909}
910
Andreas Hubercf747542010-10-25 09:40:52 -0700911#if defined(HAVE_ANDROID_OS)
Andreas Hubera0b442e2010-10-20 15:00:34 -0700912static void H(const AString &s, AString *out) {
913 out->clear();
914
915 MD5_CTX m;
916 MD5_Init(&m);
917 MD5_Update(&m, s.c_str(), s.size());
918
919 uint8_t key[16];
920 MD5_Final(key, &m);
921
922 for (size_t i = 0; i < 16; ++i) {
923 char nibble = key[i] >> 4;
924 if (nibble <= 9) {
925 nibble += '0';
926 } else {
927 nibble += 'a' - 10;
928 }
929 out->append(&nibble, 1);
930
931 nibble = key[i] & 0x0f;
932 if (nibble <= 9) {
933 nibble += '0';
934 } else {
935 nibble += 'a' - 10;
936 }
937 out->append(&nibble, 1);
938 }
939}
Andreas Hubercf747542010-10-25 09:40:52 -0700940#endif
Andreas Hubera0b442e2010-10-20 15:00:34 -0700941
942static void GetMethodAndURL(
943 const AString &request, AString *method, AString *url) {
944 ssize_t space1 = request.find(" ");
945 CHECK_GE(space1, 0);
946
947 ssize_t space2 = request.find(" ", space1 + 1);
948 CHECK_GE(space2, 0);
949
950 method->setTo(request, 0, space1);
951 url->setTo(request, space1 + 1, space2 - space1);
952}
953
954void ARTSPConnection::addAuthentication(AString *request) {
955 if (mAuthType == NONE) {
956 return;
957 }
958
959 // Find the boundary between headers and the body.
960 ssize_t i = request->find("\r\n\r\n");
961 CHECK_GE(i, 0);
962
963 if (mAuthType == BASIC) {
964 AString tmp;
965 tmp.append(mUser);
966 tmp.append(":");
967 tmp.append(mPass);
968
969 AString out;
970 encodeBase64(tmp.c_str(), tmp.size(), &out);
971
972 AString fragment;
973 fragment.append("Authorization: Basic ");
974 fragment.append(out);
975 fragment.append("\r\n");
976
977 request->insert(fragment, i + 2);
978
979 return;
980 }
981
Andreas Hubercf747542010-10-25 09:40:52 -0700982#if defined(HAVE_ANDROID_OS)
Andreas Hubera0b442e2010-10-20 15:00:34 -0700983 CHECK_EQ((int)mAuthType, (int)DIGEST);
984
985 AString method, url;
986 GetMethodAndURL(*request, &method, &url);
987
988 AString A1;
989 A1.append(mUser);
990 A1.append(":");
991 A1.append("Streaming Server");
992 A1.append(":");
993 A1.append(mPass);
994
995 AString A2;
996 A2.append(method);
997 A2.append(":");
998 A2.append(url);
999
1000 AString HA1, HA2;
1001 H(A1, &HA1);
1002 H(A2, &HA2);
1003
1004 AString tmp;
1005 tmp.append(HA1);
1006 tmp.append(":");
1007 tmp.append(mNonce);
1008 tmp.append(":");
1009 tmp.append(HA2);
1010
1011 AString digest;
1012 H(tmp, &digest);
1013
1014 AString fragment;
1015 fragment.append("Authorization: Digest ");
1016 fragment.append("nonce=\"");
1017 fragment.append(mNonce);
1018 fragment.append("\", ");
1019 fragment.append("username=\"");
1020 fragment.append(mUser);
1021 fragment.append("\", ");
1022 fragment.append("uri=\"");
1023 fragment.append(url);
1024 fragment.append("\", ");
1025 fragment.append("response=\"");
1026 fragment.append(digest);
1027 fragment.append("\"");
1028 fragment.append("\r\n");
1029
1030 request->insert(fragment, i + 2);
Andreas Hubercf747542010-10-25 09:40:52 -07001031#endif
Andreas Hubera0b442e2010-10-20 15:00:34 -07001032}
1033
Andreas Huberb0e73812011-03-29 13:34:28 -07001034// static
1035void ARTSPConnection::MakeUserAgent(AString *userAgent) {
1036 userAgent->clear();
1037 userAgent->setTo("User-Agent: stagefright/1.1 (Linux;Android ");
1038
1039#if (PROPERTY_VALUE_MAX < 8)
1040#error "PROPERTY_VALUE_MAX must be at least 8"
1041#endif
1042
1043 char value[PROPERTY_VALUE_MAX];
1044 property_get("ro.build.version.release", value, "Unknown");
1045 userAgent->append(value);
1046 userAgent->append(")\r\n");
1047}
1048
1049void ARTSPConnection::addUserAgent(AString *request) const {
1050 // Find the boundary between headers and the body.
1051 ssize_t i = request->find("\r\n\r\n");
1052 CHECK_GE(i, 0);
1053
1054 request->insert(mUserAgent, i + 2);
1055}
1056
Andreas Huber7a747b82010-06-07 15:19:40 -07001057} // namespace android