blob: 0740515c6d438e28243bad319cbaefba5408dec3 [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
23#include <media/stagefright/foundation/ABuffer.h>
24#include <media/stagefright/foundation/ADebug.h>
25#include <media/stagefright/foundation/AMessage.h>
Andreas Hubera0b442e2010-10-20 15:00:34 -070026#include <media/stagefright/foundation/base64.h>
Andreas Huber0416da72010-08-26 11:17:32 -070027#include <media/stagefright/MediaErrors.h>
Andreas Huber7a747b82010-06-07 15:19:40 -070028
29#include <arpa/inet.h>
30#include <fcntl.h>
31#include <netdb.h>
Andreas Hubera0b442e2010-10-20 15:00:34 -070032#include <openssl/md5.h>
Andreas Huber7a747b82010-06-07 15:19:40 -070033#include <sys/socket.h>
34
35namespace android {
36
37// static
38const int64_t ARTSPConnection::kSelectTimeoutUs = 1000ll;
39
40ARTSPConnection::ARTSPConnection()
41 : mState(DISCONNECTED),
Andreas Hubera0b442e2010-10-20 15:00:34 -070042 mAuthType(NONE),
Andreas Huber7a747b82010-06-07 15:19:40 -070043 mSocket(-1),
44 mConnectionID(0),
45 mNextCSeq(0),
46 mReceiveResponseEventPending(false) {
47}
48
49ARTSPConnection::~ARTSPConnection() {
50 if (mSocket >= 0) {
Andreas Huber6e3fa442010-09-21 13:13:15 -070051 LOGE("Connection is still open, closing the socket.");
Andreas Huber7a747b82010-06-07 15:19:40 -070052 close(mSocket);
53 mSocket = -1;
54 }
55}
56
57void ARTSPConnection::connect(const char *url, const sp<AMessage> &reply) {
58 sp<AMessage> msg = new AMessage(kWhatConnect, id());
59 msg->setString("url", url);
60 msg->setMessage("reply", reply);
61 msg->post();
62}
63
64void ARTSPConnection::disconnect(const sp<AMessage> &reply) {
65 sp<AMessage> msg = new AMessage(kWhatDisconnect, id());
66 msg->setMessage("reply", reply);
67 msg->post();
68}
69
70void ARTSPConnection::sendRequest(
71 const char *request, const sp<AMessage> &reply) {
72 sp<AMessage> msg = new AMessage(kWhatSendRequest, id());
73 msg->setString("request", request);
74 msg->setMessage("reply", reply);
75 msg->post();
76}
77
Andreas Huber0416da72010-08-26 11:17:32 -070078void ARTSPConnection::observeBinaryData(const sp<AMessage> &reply) {
79 sp<AMessage> msg = new AMessage(kWhatObserveBinaryData, id());
80 msg->setMessage("reply", reply);
81 msg->post();
82}
83
Andreas Huber7a747b82010-06-07 15:19:40 -070084void ARTSPConnection::onMessageReceived(const sp<AMessage> &msg) {
85 switch (msg->what()) {
86 case kWhatConnect:
87 onConnect(msg);
88 break;
89
90 case kWhatDisconnect:
91 onDisconnect(msg);
92 break;
93
94 case kWhatCompleteConnection:
95 onCompleteConnection(msg);
96 break;
97
98 case kWhatSendRequest:
99 onSendRequest(msg);
100 break;
101
102 case kWhatReceiveResponse:
103 onReceiveResponse();
104 break;
105
Andreas Huber0416da72010-08-26 11:17:32 -0700106 case kWhatObserveBinaryData:
107 {
108 CHECK(msg->findMessage("reply", &mObserveBinaryMessage));
109 break;
110 }
111
Andreas Huber7a747b82010-06-07 15:19:40 -0700112 default:
113 TRESPASS();
114 break;
115 }
116}
117
118// static
119bool ARTSPConnection::ParseURL(
Andreas Hubera0b442e2010-10-20 15:00:34 -0700120 const char *url, AString *host, unsigned *port, AString *path,
121 AString *user, AString *pass) {
Andreas Huber7a747b82010-06-07 15:19:40 -0700122 host->clear();
123 *port = 0;
124 path->clear();
Andreas Hubera0b442e2010-10-20 15:00:34 -0700125 user->clear();
126 pass->clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700127
128 if (strncasecmp("rtsp://", url, 7)) {
129 return false;
130 }
131
132 const char *slashPos = strchr(&url[7], '/');
133
134 if (slashPos == NULL) {
135 host->setTo(&url[7]);
136 path->setTo("/");
137 } else {
138 host->setTo(&url[7], slashPos - &url[7]);
139 path->setTo(slashPos);
140 }
141
Andreas Hubera0b442e2010-10-20 15:00:34 -0700142 ssize_t atPos = host->find("@");
143
144 if (atPos >= 0) {
145 // Split of user:pass@ from hostname.
146
147 AString userPass(*host, 0, atPos);
148 host->erase(0, atPos + 1);
149
150 ssize_t colonPos = userPass.find(":");
151
152 if (colonPos < 0) {
153 *user = userPass;
154 } else {
155 user->setTo(userPass, 0, colonPos);
156 pass->setTo(userPass, colonPos + 1, userPass.size() - colonPos - 1);
157 }
158 }
159
Mike Lockwood5a23f8c2010-07-15 14:58:25 -0400160 const char *colonPos = strchr(host->c_str(), ':');
Andreas Huber7a747b82010-06-07 15:19:40 -0700161
162 if (colonPos != NULL) {
163 unsigned long x;
164 if (!ParseSingleUnsignedLong(colonPos + 1, &x) || x >= 65536) {
165 return false;
166 }
167
168 *port = x;
169
170 size_t colonOffset = colonPos - host->c_str();
171 size_t trailing = host->size() - colonOffset;
172 host->erase(colonOffset, trailing);
173 } else {
174 *port = 554;
175 }
176
177 return true;
178}
179
Andreas Huberaf063a62010-08-18 10:17:18 -0700180static void MakeSocketBlocking(int s, bool blocking) {
181 // Make socket non-blocking.
182 int flags = fcntl(s, F_GETFL, 0);
183 CHECK_NE(flags, -1);
184
185 if (blocking) {
186 flags &= ~O_NONBLOCK;
187 } else {
188 flags |= O_NONBLOCK;
189 }
190
191 CHECK_NE(fcntl(s, F_SETFL, flags), -1);
192}
193
Andreas Huber7a747b82010-06-07 15:19:40 -0700194void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
195 ++mConnectionID;
196
197 if (mState != DISCONNECTED) {
198 close(mSocket);
199 mSocket = -1;
200
201 flushPendingRequests();
202 }
203
204 mState = CONNECTING;
205
Andreas Huber7a747b82010-06-07 15:19:40 -0700206 AString url;
207 CHECK(msg->findString("url", &url));
208
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700209 sp<AMessage> reply;
210 CHECK(msg->findMessage("reply", &reply));
211
Andreas Huber7a747b82010-06-07 15:19:40 -0700212 AString host, path;
213 unsigned port;
Andreas Hubera0b442e2010-10-20 15:00:34 -0700214 if (!ParseURL(url.c_str(), &host, &port, &path, &mUser, &mPass)
215 || (mUser.size() > 0 && mPass.size() == 0)) {
216 // If we have a user name but no password we have to give up
217 // right here, since we currently have no way of asking the user
218 // for this information.
219
Andreas Huber6e3fa442010-09-21 13:13:15 -0700220 LOGE("Malformed rtsp url %s", url.c_str());
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700221
222 reply->setInt32("result", ERROR_MALFORMED);
223 reply->post();
224
225 mState = DISCONNECTED;
226 return;
227 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700228
Andreas Hubera0b442e2010-10-20 15:00:34 -0700229 if (mUser.size() > 0) {
230 LOGV("user = '%s', pass = '%s'", mUser.c_str(), mPass.c_str());
231 }
232
Andreas Huber7a747b82010-06-07 15:19:40 -0700233 struct hostent *ent = gethostbyname(host.c_str());
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700234 if (ent == NULL) {
Andreas Huber6e3fa442010-09-21 13:13:15 -0700235 LOGE("Unknown host %s", host.c_str());
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700236
237 reply->setInt32("result", -ENOENT);
238 reply->post();
239
240 mState = DISCONNECTED;
241 return;
242 }
243
244 mSocket = socket(AF_INET, SOCK_STREAM, 0);
245
246 MakeSocketBlocking(mSocket, false);
Andreas Huber7a747b82010-06-07 15:19:40 -0700247
248 struct sockaddr_in remote;
249 memset(remote.sin_zero, 0, sizeof(remote.sin_zero));
250 remote.sin_family = AF_INET;
251 remote.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
252 remote.sin_port = htons(port);
253
254 int err = ::connect(
255 mSocket, (const struct sockaddr *)&remote, sizeof(remote));
256
Andreas Huber7a747b82010-06-07 15:19:40 -0700257 reply->setInt32("server-ip", ntohl(remote.sin_addr.s_addr));
258
259 if (err < 0) {
260 if (errno == EINPROGRESS) {
261 sp<AMessage> msg = new AMessage(kWhatCompleteConnection, id());
262 msg->setMessage("reply", reply);
263 msg->setInt32("connection-id", mConnectionID);
264 msg->post();
265 return;
266 }
267
268 reply->setInt32("result", -errno);
269 mState = DISCONNECTED;
270
271 close(mSocket);
272 mSocket = -1;
273 } else {
274 reply->setInt32("result", OK);
275 mState = CONNECTED;
276 mNextCSeq = 1;
277
278 postReceiveReponseEvent();
279 }
280
281 reply->post();
282}
283
284void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) {
285 if (mState == CONNECTED || mState == CONNECTING) {
286 close(mSocket);
287 mSocket = -1;
288
289 flushPendingRequests();
Andreas Huberaf063a62010-08-18 10:17:18 -0700290 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700291
292 sp<AMessage> reply;
293 CHECK(msg->findMessage("reply", &reply));
294
295 reply->setInt32("result", OK);
296 mState = DISCONNECTED;
297
Andreas Hubera0b442e2010-10-20 15:00:34 -0700298 mUser.clear();
299 mPass.clear();
300 mAuthType = NONE;
301 mNonce.clear();
302
Andreas Huber7a747b82010-06-07 15:19:40 -0700303 reply->post();
304}
305
306void ARTSPConnection::onCompleteConnection(const sp<AMessage> &msg) {
307 sp<AMessage> reply;
308 CHECK(msg->findMessage("reply", &reply));
309
310 int32_t connectionID;
311 CHECK(msg->findInt32("connection-id", &connectionID));
312
313 if ((connectionID != mConnectionID) || mState != CONNECTING) {
314 // While we were attempting to connect, the attempt was
315 // cancelled.
316 reply->setInt32("result", -ECONNABORTED);
317 reply->post();
318 return;
319 }
320
321 struct timeval tv;
322 tv.tv_sec = 0;
323 tv.tv_usec = kSelectTimeoutUs;
324
325 fd_set ws;
326 FD_ZERO(&ws);
327 FD_SET(mSocket, &ws);
328
329 int res = select(mSocket + 1, NULL, &ws, NULL, &tv);
330 CHECK_GE(res, 0);
331
332 if (res == 0) {
333 // Timed out. Not yet connected.
334
335 msg->post();
336 return;
337 }
338
339 int err;
340 socklen_t optionLen = sizeof(err);
341 CHECK_EQ(getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &err, &optionLen), 0);
342 CHECK_EQ(optionLen, (socklen_t)sizeof(err));
343
344 if (err != 0) {
Andreas Huber6e3fa442010-09-21 13:13:15 -0700345 LOGE("err = %d (%s)", err, strerror(err));
Andreas Huber7a747b82010-06-07 15:19:40 -0700346
347 reply->setInt32("result", -err);
348
349 mState = DISCONNECTED;
350 close(mSocket);
351 mSocket = -1;
352 } else {
353 reply->setInt32("result", OK);
354 mState = CONNECTED;
355 mNextCSeq = 1;
356
357 postReceiveReponseEvent();
358 }
359
360 reply->post();
361}
362
363void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) {
364 sp<AMessage> reply;
365 CHECK(msg->findMessage("reply", &reply));
366
367 if (mState != CONNECTED) {
368 reply->setInt32("result", -ENOTCONN);
369 reply->post();
370 return;
371 }
372
373 AString request;
374 CHECK(msg->findString("request", &request));
375
Andreas Hubera0b442e2010-10-20 15:00:34 -0700376 // Just in case we need to re-issue the request with proper authentication
377 // later, stash it away.
378 reply->setString("original-request", request.c_str(), request.size());
379
380 addAuthentication(&request);
381
Andreas Huber7a747b82010-06-07 15:19:40 -0700382 // Find the boundary between headers and the body.
383 ssize_t i = request.find("\r\n\r\n");
384 CHECK_GE(i, 0);
385
386 int32_t cseq = mNextCSeq++;
387
388 AString cseqHeader = "CSeq: ";
389 cseqHeader.append(cseq);
390 cseqHeader.append("\r\n");
391
392 request.insert(cseqHeader, i + 2);
393
Andreas Hubera0b442e2010-10-20 15:00:34 -0700394 LOGV("request: '%s'", request.c_str());
Andreas Huber7a747b82010-06-07 15:19:40 -0700395
396 size_t numBytesSent = 0;
397 while (numBytesSent < request.size()) {
398 ssize_t n =
399 send(mSocket, request.c_str() + numBytesSent,
400 request.size() - numBytesSent, 0);
401
402 if (n == 0) {
403 // Server closed the connection.
Andreas Huber6e3fa442010-09-21 13:13:15 -0700404 LOGE("Server unexpectedly closed the connection.");
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700405
406 reply->setInt32("result", ERROR_IO);
407 reply->post();
408 return;
Andreas Huber7a747b82010-06-07 15:19:40 -0700409 } else if (n < 0) {
410 if (errno == EINTR) {
411 continue;
412 }
413
Andreas Huber6e3fa442010-09-21 13:13:15 -0700414 LOGE("Error sending rtsp request.");
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700415 reply->setInt32("result", -errno);
416 reply->post();
417 return;
Andreas Huber7a747b82010-06-07 15:19:40 -0700418 }
419
420 numBytesSent += (size_t)n;
421 }
422
423 mPendingRequests.add(cseq, reply);
424}
425
426void ARTSPConnection::onReceiveResponse() {
427 mReceiveResponseEventPending = false;
428
429 if (mState != CONNECTED) {
430 return;
431 }
432
433 struct timeval tv;
434 tv.tv_sec = 0;
435 tv.tv_usec = kSelectTimeoutUs;
436
437 fd_set rs;
438 FD_ZERO(&rs);
439 FD_SET(mSocket, &rs);
440
441 int res = select(mSocket + 1, &rs, NULL, NULL, &tv);
442 CHECK_GE(res, 0);
443
444 if (res == 1) {
Andreas Huberaf063a62010-08-18 10:17:18 -0700445 MakeSocketBlocking(mSocket, true);
446
447 bool success = receiveRTSPReponse();
448
449 MakeSocketBlocking(mSocket, false);
450
451 if (!success) {
Andreas Huber7a747b82010-06-07 15:19:40 -0700452 // Something horrible, irreparable has happened.
453 flushPendingRequests();
454 return;
455 }
456 }
457
458 postReceiveReponseEvent();
459}
460
461void ARTSPConnection::flushPendingRequests() {
462 for (size_t i = 0; i < mPendingRequests.size(); ++i) {
463 sp<AMessage> reply = mPendingRequests.valueAt(i);
464
465 reply->setInt32("result", -ECONNABORTED);
466 reply->post();
467 }
468
469 mPendingRequests.clear();
470}
471
472void ARTSPConnection::postReceiveReponseEvent() {
473 if (mReceiveResponseEventPending) {
474 return;
475 }
476
477 sp<AMessage> msg = new AMessage(kWhatReceiveResponse, id());
478 msg->post();
479
480 mReceiveResponseEventPending = true;
481}
482
Andreas Huber0416da72010-08-26 11:17:32 -0700483status_t ARTSPConnection::receive(void *data, size_t size) {
484 size_t offset = 0;
485 while (offset < size) {
486 ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0);
Andreas Huber7a747b82010-06-07 15:19:40 -0700487 if (n == 0) {
488 // Server closed the connection.
Andreas Huber6e3fa442010-09-21 13:13:15 -0700489 LOGE("Server unexpectedly closed the connection.");
Andreas Huber0416da72010-08-26 11:17:32 -0700490 return ERROR_IO;
Andreas Huber7a747b82010-06-07 15:19:40 -0700491 } else if (n < 0) {
492 if (errno == EINTR) {
493 continue;
494 }
495
Andreas Huber6e3fa442010-09-21 13:13:15 -0700496 LOGE("Error reading rtsp response.");
Andreas Huberf3d2bdf2010-09-15 11:18:13 -0700497 return -errno;
Andreas Huber7a747b82010-06-07 15:19:40 -0700498 }
499
Andreas Huber0416da72010-08-26 11:17:32 -0700500 offset += (size_t)n;
501 }
502
503 return OK;
504}
505
506bool ARTSPConnection::receiveLine(AString *line) {
507 line->clear();
508
509 bool sawCR = false;
510 for (;;) {
511 char c;
512 if (receive(&c, 1) != OK) {
513 return false;
514 }
515
Andreas Huber7a747b82010-06-07 15:19:40 -0700516 if (sawCR && c == '\n') {
517 line->erase(line->size() - 1, 1);
518 return true;
519 }
520
521 line->append(&c, 1);
522
Andreas Huber0416da72010-08-26 11:17:32 -0700523 if (c == '$' && line->size() == 1) {
524 // Special-case for interleaved binary data.
525 return true;
526 }
527
Andreas Huber7a747b82010-06-07 15:19:40 -0700528 sawCR = (c == '\r');
529 }
530}
531
Andreas Huber0416da72010-08-26 11:17:32 -0700532sp<ABuffer> ARTSPConnection::receiveBinaryData() {
533 uint8_t x[3];
534 if (receive(x, 3) != OK) {
535 return NULL;
536 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700537
Andreas Huber0416da72010-08-26 11:17:32 -0700538 sp<ABuffer> buffer = new ABuffer((x[1] << 8) | x[2]);
539 if (receive(buffer->data(), buffer->size()) != OK) {
540 return NULL;
541 }
542
543 buffer->meta()->setInt32("index", (int32_t)x[0]);
544
545 return buffer;
546}
547
Andreas Hubere0666162011-02-16 13:20:02 -0800548static bool IsRTSPVersion(const AString &s) {
549 return s == "RTSP/1.0";
550}
551
Andreas Huber0416da72010-08-26 11:17:32 -0700552bool ARTSPConnection::receiveRTSPReponse() {
553 AString statusLine;
554
555 if (!receiveLine(&statusLine)) {
Andreas Huber7a747b82010-06-07 15:19:40 -0700556 return false;
557 }
558
Andreas Huber0416da72010-08-26 11:17:32 -0700559 if (statusLine == "$") {
560 sp<ABuffer> buffer = receiveBinaryData();
561
562 if (buffer == NULL) {
563 return false;
564 }
565
566 if (mObserveBinaryMessage != NULL) {
567 sp<AMessage> notify = mObserveBinaryMessage->dup();
568 notify->setObject("buffer", buffer);
569 notify->post();
570 } else {
Andreas Huber6e3fa442010-09-21 13:13:15 -0700571 LOGW("received binary data, but no one cares.");
Andreas Huber0416da72010-08-26 11:17:32 -0700572 }
573
574 return true;
575 }
576
577 sp<ARTSPResponse> response = new ARTSPResponse;
578 response->mStatusLine = statusLine;
579
Andreas Huber6e3fa442010-09-21 13:13:15 -0700580 LOGI("status: %s", response->mStatusLine.c_str());
Andreas Huber7a747b82010-06-07 15:19:40 -0700581
582 ssize_t space1 = response->mStatusLine.find(" ");
583 if (space1 < 0) {
584 return false;
585 }
586 ssize_t space2 = response->mStatusLine.find(" ", space1 + 1);
587 if (space2 < 0) {
588 return false;
589 }
590
Andreas Hubere0666162011-02-16 13:20:02 -0800591 bool isRequest = false;
Andreas Huber7a747b82010-06-07 15:19:40 -0700592
Andreas Hubere0666162011-02-16 13:20:02 -0800593 if (!IsRTSPVersion(AString(response->mStatusLine, 0, space1))) {
594 CHECK(IsRTSPVersion(
595 AString(
596 response->mStatusLine,
597 space2 + 1,
598 response->mStatusLine.size() - space2 - 1)));
599
600 isRequest = true;
601
602 response->mStatusCode = 0;
603 } else {
604 AString statusCodeStr(
605 response->mStatusLine, space1 + 1, space2 - space1 - 1);
606
607 if (!ParseSingleUnsignedLong(
608 statusCodeStr.c_str(), &response->mStatusCode)
609 || response->mStatusCode < 100 || response->mStatusCode > 999) {
610 return false;
611 }
Andreas Huber7a747b82010-06-07 15:19:40 -0700612 }
613
614 AString line;
615 for (;;) {
616 if (!receiveLine(&line)) {
617 break;
618 }
619
620 if (line.empty()) {
621 break;
622 }
623
Andreas Huber6e3fa442010-09-21 13:13:15 -0700624 LOGV("line: %s", line.c_str());
Andreas Huber7a747b82010-06-07 15:19:40 -0700625
626 ssize_t colonPos = line.find(":");
627 if (colonPos < 0) {
628 // Malformed header line.
629 return false;
630 }
631
632 AString key(line, 0, colonPos);
633 key.trim();
634 key.tolower();
635
636 line.erase(0, colonPos + 1);
637 line.trim();
638
639 response->mHeaders.add(key, line);
640 }
641
642 unsigned long contentLength = 0;
643
644 ssize_t i = response->mHeaders.indexOfKey("content-length");
645
646 if (i >= 0) {
647 AString value = response->mHeaders.valueAt(i);
648 if (!ParseSingleUnsignedLong(value.c_str(), &contentLength)) {
649 return false;
650 }
651 }
652
653 if (contentLength > 0) {
654 response->mContent = new ABuffer(contentLength);
655
656 size_t numBytesRead = 0;
657 while (numBytesRead < contentLength) {
658 ssize_t n = recv(
659 mSocket, response->mContent->data() + numBytesRead,
660 contentLength - numBytesRead, 0);
661
662 if (n == 0) {
663 // Server closed the connection.
664 TRESPASS();
665 } else if (n < 0) {
666 if (errno == EINTR) {
667 continue;
668 }
669
670 TRESPASS();
671 }
672
673 numBytesRead += (size_t)n;
674 }
675 }
676
Andreas Hubera0b442e2010-10-20 15:00:34 -0700677 if (response->mStatusCode == 401) {
678 if (mAuthType == NONE && mUser.size() > 0
679 && parseAuthMethod(response)) {
680 ssize_t i;
681 CHECK_EQ((status_t)OK, findPendingRequest(response, &i));
682 CHECK_GE(i, 0);
683
684 sp<AMessage> reply = mPendingRequests.valueAt(i);
685 mPendingRequests.removeItemsAt(i);
686
687 AString request;
688 CHECK(reply->findString("original-request", &request));
689
690 sp<AMessage> msg = new AMessage(kWhatSendRequest, id());
691 msg->setMessage("reply", reply);
692 msg->setString("request", request.c_str(), request.size());
693
694 LOGI("re-sending request with authentication headers...");
695 onSendRequest(msg);
696
697 return true;
698 }
699 }
700
Andreas Hubere0666162011-02-16 13:20:02 -0800701 return isRequest
702 ? handleServerRequest(response)
703 : notifyResponseListener(response);
704}
705
706bool ARTSPConnection::handleServerRequest(const sp<ARTSPResponse> &request) {
707 // Implementation of server->client requests is optional for all methods
708 // but we do need to respond, even if it's just to say that we don't
709 // support the method.
710
711 ssize_t space1 = request->mStatusLine.find(" ");
712 CHECK_GE(space1, 0);
713
714 AString response;
715 response.append("RTSP/1.0 501 Not Implemented\r\n");
716
717 ssize_t i = request->mHeaders.indexOfKey("cseq");
718
719 if (i >= 0) {
720 AString value = request->mHeaders.valueAt(i);
721
722 unsigned long cseq;
723 if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) {
724 return false;
725 }
726
727 response.append("CSeq: ");
728 response.append(cseq);
729 response.append("\r\n");
730 }
731
732 response.append("\r\n");
733
734 size_t numBytesSent = 0;
735 while (numBytesSent < response.size()) {
736 ssize_t n =
737 send(mSocket, response.c_str() + numBytesSent,
738 response.size() - numBytesSent, 0);
739
740 if (n == 0) {
741 // Server closed the connection.
742 LOGE("Server unexpectedly closed the connection.");
743
744 return false;
745 } else if (n < 0) {
746 if (errno == EINTR) {
747 continue;
748 }
749
750 LOGE("Error sending rtsp response.");
751 return false;
752 }
753
754 numBytesSent += (size_t)n;
755 }
756
757 return true;
Andreas Huber7a747b82010-06-07 15:19:40 -0700758}
759
760// static
761bool ARTSPConnection::ParseSingleUnsignedLong(
762 const char *from, unsigned long *x) {
763 char *end;
764 *x = strtoul(from, &end, 10);
765
766 if (end == from || *end != '\0') {
767 return false;
768 }
769
770 return true;
771}
772
Andreas Hubera0b442e2010-10-20 15:00:34 -0700773status_t ARTSPConnection::findPendingRequest(
774 const sp<ARTSPResponse> &response, ssize_t *index) const {
775 *index = 0;
776
Andreas Huber7a747b82010-06-07 15:19:40 -0700777 ssize_t i = response->mHeaders.indexOfKey("cseq");
778
779 if (i < 0) {
Andreas Hubera0b442e2010-10-20 15:00:34 -0700780 // This is an unsolicited server->client message.
781 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -0700782 }
783
784 AString value = response->mHeaders.valueAt(i);
785
786 unsigned long cseq;
787 if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) {
Andreas Hubera0b442e2010-10-20 15:00:34 -0700788 return ERROR_MALFORMED;
Andreas Huber7a747b82010-06-07 15:19:40 -0700789 }
790
791 i = mPendingRequests.indexOfKey(cseq);
792
793 if (i < 0) {
Andreas Hubera0b442e2010-10-20 15:00:34 -0700794 return -ENOENT;
795 }
796
797 *index = i;
798
799 return OK;
800}
801
802bool ARTSPConnection::notifyResponseListener(
803 const sp<ARTSPResponse> &response) {
804 ssize_t i;
805 status_t err = findPendingRequest(response, &i);
806
807 if (err == OK && i < 0) {
808 // An unsolicited server response is not a problem.
809 return true;
810 }
811
812 if (err != OK) {
813 return false;
Andreas Huber7a747b82010-06-07 15:19:40 -0700814 }
815
816 sp<AMessage> reply = mPendingRequests.valueAt(i);
817 mPendingRequests.removeItemsAt(i);
818
819 reply->setInt32("result", OK);
820 reply->setObject("response", response);
821 reply->post();
822
823 return true;
824}
825
Andreas Hubera0b442e2010-10-20 15:00:34 -0700826bool ARTSPConnection::parseAuthMethod(const sp<ARTSPResponse> &response) {
827 ssize_t i = response->mHeaders.indexOfKey("www-authenticate");
828
829 if (i < 0) {
830 return false;
831 }
832
833 AString value = response->mHeaders.valueAt(i);
834
835 if (!strncmp(value.c_str(), "Basic", 5)) {
836 mAuthType = BASIC;
837 } else {
Andreas Hubercf747542010-10-25 09:40:52 -0700838#if !defined(HAVE_ANDROID_OS)
839 // We don't have access to the MD5 implementation on the simulator,
840 // so we won't support digest authentication.
841 return false;
842#endif
843
Andreas Hubera0b442e2010-10-20 15:00:34 -0700844 CHECK(!strncmp(value.c_str(), "Digest", 6));
845 mAuthType = DIGEST;
846
847 i = value.find("nonce=");
848 CHECK_GE(i, 0);
849 CHECK_EQ(value.c_str()[i + 6], '\"');
850 ssize_t j = value.find("\"", i + 7);
851 CHECK_GE(j, 0);
852
853 mNonce.setTo(value, i + 7, j - i - 7);
854 }
855
856 return true;
857}
858
Andreas Hubercf747542010-10-25 09:40:52 -0700859#if defined(HAVE_ANDROID_OS)
Andreas Hubera0b442e2010-10-20 15:00:34 -0700860static void H(const AString &s, AString *out) {
861 out->clear();
862
863 MD5_CTX m;
864 MD5_Init(&m);
865 MD5_Update(&m, s.c_str(), s.size());
866
867 uint8_t key[16];
868 MD5_Final(key, &m);
869
870 for (size_t i = 0; i < 16; ++i) {
871 char nibble = key[i] >> 4;
872 if (nibble <= 9) {
873 nibble += '0';
874 } else {
875 nibble += 'a' - 10;
876 }
877 out->append(&nibble, 1);
878
879 nibble = key[i] & 0x0f;
880 if (nibble <= 9) {
881 nibble += '0';
882 } else {
883 nibble += 'a' - 10;
884 }
885 out->append(&nibble, 1);
886 }
887}
Andreas Hubercf747542010-10-25 09:40:52 -0700888#endif
Andreas Hubera0b442e2010-10-20 15:00:34 -0700889
890static void GetMethodAndURL(
891 const AString &request, AString *method, AString *url) {
892 ssize_t space1 = request.find(" ");
893 CHECK_GE(space1, 0);
894
895 ssize_t space2 = request.find(" ", space1 + 1);
896 CHECK_GE(space2, 0);
897
898 method->setTo(request, 0, space1);
899 url->setTo(request, space1 + 1, space2 - space1);
900}
901
902void ARTSPConnection::addAuthentication(AString *request) {
903 if (mAuthType == NONE) {
904 return;
905 }
906
907 // Find the boundary between headers and the body.
908 ssize_t i = request->find("\r\n\r\n");
909 CHECK_GE(i, 0);
910
911 if (mAuthType == BASIC) {
912 AString tmp;
913 tmp.append(mUser);
914 tmp.append(":");
915 tmp.append(mPass);
916
917 AString out;
918 encodeBase64(tmp.c_str(), tmp.size(), &out);
919
920 AString fragment;
921 fragment.append("Authorization: Basic ");
922 fragment.append(out);
923 fragment.append("\r\n");
924
925 request->insert(fragment, i + 2);
926
927 return;
928 }
929
Andreas Hubercf747542010-10-25 09:40:52 -0700930#if defined(HAVE_ANDROID_OS)
Andreas Hubera0b442e2010-10-20 15:00:34 -0700931 CHECK_EQ((int)mAuthType, (int)DIGEST);
932
933 AString method, url;
934 GetMethodAndURL(*request, &method, &url);
935
936 AString A1;
937 A1.append(mUser);
938 A1.append(":");
939 A1.append("Streaming Server");
940 A1.append(":");
941 A1.append(mPass);
942
943 AString A2;
944 A2.append(method);
945 A2.append(":");
946 A2.append(url);
947
948 AString HA1, HA2;
949 H(A1, &HA1);
950 H(A2, &HA2);
951
952 AString tmp;
953 tmp.append(HA1);
954 tmp.append(":");
955 tmp.append(mNonce);
956 tmp.append(":");
957 tmp.append(HA2);
958
959 AString digest;
960 H(tmp, &digest);
961
962 AString fragment;
963 fragment.append("Authorization: Digest ");
964 fragment.append("nonce=\"");
965 fragment.append(mNonce);
966 fragment.append("\", ");
967 fragment.append("username=\"");
968 fragment.append(mUser);
969 fragment.append("\", ");
970 fragment.append("uri=\"");
971 fragment.append(url);
972 fragment.append("\", ");
973 fragment.append("response=\"");
974 fragment.append(digest);
975 fragment.append("\"");
976 fragment.append("\r\n");
977
978 request->insert(fragment, i + 2);
Andreas Hubercf747542010-10-25 09:40:52 -0700979#endif
Andreas Hubera0b442e2010-10-20 15:00:34 -0700980}
981
Andreas Huber7a747b82010-06-07 15:19:40 -0700982} // namespace android