1 /* GStreamer
2 * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19 /*
20 * Unless otherwise indicated, Source Code is licensed under MIT license.
21 * See further explanation attached in License Statement (distributed in the file
22 * LICENSE).
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a copy of
25 * this software and associated documentation files (the "Software"), to deal in
26 * the Software without restriction, including without limitation the rights to
27 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
28 * of the Software, and to permit persons to whom the Software is furnished to do
29 * so, subject to the following conditions:
30 *
31 * The above copyright notice and this permission notice shall be included in all
32 * copies or substantial portions of the Software.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40 * SOFTWARE.
41 */
42
43 /**
44 * SECTION:gstrtspdefs
45 * @title: GstRtspdefs
46 * @short_description: common RTSP defines
47 * @see_also: gstrtspurl, gstrtspconnection
48 *
49 * Provides common defines for the RTSP library.
50 */
51
52 #ifdef HAVE_CONFIG_H
53 #include "config.h"
54 #endif
55
56 #include <errno.h>
57 #include <string.h>
58
59 #include "gstrtspdefs.h"
60 #include <gst/gst.h>
61
62 struct rtsp_header
63 {
64 const gchar *name;
65 gboolean multiple;
66 };
67
68 static const gchar *rtsp_methods[] = {
69 "DESCRIBE",
70 "ANNOUNCE",
71 "GET_PARAMETER",
72 "OPTIONS",
73 "PAUSE",
74 "PLAY",
75 "RECORD",
76 "REDIRECT",
77 "SETUP",
78 "SET_PARAMETER",
79 "TEARDOWN",
80 "GET",
81 "POST",
82 NULL
83 };
84
85 static struct rtsp_header rtsp_headers[] = {
86 {"Accept", TRUE},
87 {"Accept-Encoding", TRUE},
88 {"Accept-Language", TRUE},
89 {"Allow", TRUE},
90 {"Authorization", FALSE},
91 {"Bandwidth", FALSE},
92 {"Blocksize", FALSE},
93 {"Cache-Control", TRUE},
94 {"Conference", FALSE},
95 {"Connection", TRUE},
96 {"Content-Base", FALSE},
97 {"Content-Encoding", TRUE},
98 {"Content-Language", TRUE},
99 {"Content-Length", FALSE},
100 {"Content-Location", FALSE},
101 {"Content-Type", FALSE},
102 {"CSeq", FALSE},
103 {"Date", FALSE},
104 {"Expires", FALSE},
105 {"From", FALSE},
106 {"If-Modified-Since", FALSE},
107 {"Last-Modified", FALSE},
108 {"Proxy-Authenticate", TRUE},
109 {"Proxy-Require", TRUE},
110 {"Public", TRUE},
111 {"Range", FALSE},
112 {"Referer", FALSE},
113 {"Require", TRUE},
114 {"Retry-After", FALSE},
115 {"RTP-Info", TRUE},
116 {"Scale", FALSE},
117 {"Session", FALSE},
118 {"Server", FALSE},
119 {"Speed", FALSE},
120 {"Transport", TRUE},
121 {"Unsupported", FALSE},
122 {"User-Agent", FALSE},
123 {"Via", TRUE},
124 {"WWW-Authenticate", TRUE},
125
126 /* Real extensions */
127 {"ClientChallenge", FALSE},
128 {"RealChallenge1", FALSE},
129 {"RealChallenge2", FALSE},
130 {"RealChallenge3", FALSE},
131 {"Subscribe", FALSE},
132 {"Alert", FALSE},
133 {"ClientID", FALSE},
134 {"CompanyID", FALSE},
135 {"GUID", FALSE},
136 {"RegionData", FALSE},
137 {"SupportsMaximumASMBandwidth", FALSE},
138 {"Language", FALSE},
139 {"PlayerStarttime", FALSE},
140
141 {"Location", FALSE},
142
143 {"ETag", FALSE},
144 {"If-Match", TRUE},
145
146 /* WM extensions [MS-RTSP] */
147 {"Accept-Charset", TRUE},
148 {"Supported", TRUE},
149 {"Vary", TRUE},
150 {"X-Accelerate-Streaming", FALSE},
151 {"X-Accept-Authentication", FALSE},
152 {"X-Accept-Proxy-Authentication", FALSE},
153 {"X-Broadcast-Id", FALSE},
154 {"X-Burst-Streaming", FALSE},
155 {"X-Notice", FALSE},
156 {"X-Player-Lag-Time", FALSE},
157 {"X-Playlist", FALSE},
158 {"X-Playlist-Change-Notice", FALSE},
159 {"X-Playlist-Gen-Id", FALSE},
160 {"X-Playlist-Seek-Id", FALSE},
161 {"X-Proxy-Client-Agent", FALSE},
162 {"X-Proxy-Client-Verb", FALSE},
163 {"X-Receding-PlaylistChange", FALSE},
164 {"X-RTP-Info", FALSE},
165 {"X-StartupProfile", FALSE},
166
167 {"Timestamp", FALSE},
168
169 {"Authentication-Info", FALSE},
170 {"Host", FALSE},
171 {"Pragma", TRUE},
172 {"X-Server-IP-Address", FALSE},
173 {"x-sessioncookie", FALSE},
174
175 {"RTCP-Interval", FALSE},
176
177 /* Since: 1.4 */
178 {"KeyMgmt", FALSE},
179
180 /* Since: 1.14 */
181 {"Pipelined-Requests", FALSE},
182 {"Media-Properties", FALSE},
183 {"Seek-Style", FALSE},
184 {"Accept-Ranges", FALSE},
185
186 /* Onvif extensions */
187 {"Frames", FALSE},
188 {"Rate-Control", FALSE},
189
190 {NULL, FALSE}
191 };
192
193 #define DEF_STATUS(c, t) \
194 g_hash_table_insert (statuses, GUINT_TO_POINTER(c), (gpointer) t)
195
196 static GHashTable *
rtsp_init_status(void)197 rtsp_init_status (void)
198 {
199 GHashTable *statuses = g_hash_table_new (NULL, NULL);
200
201 DEF_STATUS (GST_RTSP_STS_CONTINUE, "Continue");
202 DEF_STATUS (GST_RTSP_STS_OK, "OK");
203 DEF_STATUS (GST_RTSP_STS_CREATED, "Created");
204 DEF_STATUS (GST_RTSP_STS_LOW_ON_STORAGE, "Low on Storage Space");
205 DEF_STATUS (GST_RTSP_STS_MULTIPLE_CHOICES, "Multiple Choices");
206 DEF_STATUS (GST_RTSP_STS_MOVED_PERMANENTLY, "Moved Permanently");
207 DEF_STATUS (GST_RTSP_STS_MOVE_TEMPORARILY, "Move Temporarily");
208 DEF_STATUS (GST_RTSP_STS_SEE_OTHER, "See Other");
209 DEF_STATUS (GST_RTSP_STS_NOT_MODIFIED, "Not Modified");
210 DEF_STATUS (GST_RTSP_STS_USE_PROXY, "Use Proxy");
211 DEF_STATUS (GST_RTSP_STS_BAD_REQUEST, "Bad Request");
212 DEF_STATUS (GST_RTSP_STS_UNAUTHORIZED, "Unauthorized");
213 DEF_STATUS (GST_RTSP_STS_PAYMENT_REQUIRED, "Payment Required");
214 DEF_STATUS (GST_RTSP_STS_FORBIDDEN, "Forbidden");
215 DEF_STATUS (GST_RTSP_STS_NOT_FOUND, "Not Found");
216 DEF_STATUS (GST_RTSP_STS_METHOD_NOT_ALLOWED, "Method Not Allowed");
217 DEF_STATUS (GST_RTSP_STS_NOT_ACCEPTABLE, "Not Acceptable");
218 DEF_STATUS (GST_RTSP_STS_PROXY_AUTH_REQUIRED,
219 "Proxy Authentication Required");
220 DEF_STATUS (GST_RTSP_STS_REQUEST_TIMEOUT, "Request Time-out");
221 DEF_STATUS (GST_RTSP_STS_GONE, "Gone");
222 DEF_STATUS (GST_RTSP_STS_LENGTH_REQUIRED, "Length Required");
223 DEF_STATUS (GST_RTSP_STS_PRECONDITION_FAILED, "Precondition Failed");
224 DEF_STATUS (GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE,
225 "Request Entity Too Large");
226 DEF_STATUS (GST_RTSP_STS_REQUEST_URI_TOO_LARGE, "Request-URI Too Large");
227 DEF_STATUS (GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
228 DEF_STATUS (GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD,
229 "Parameter Not Understood");
230 DEF_STATUS (GST_RTSP_STS_CONFERENCE_NOT_FOUND, "Conference Not Found");
231 DEF_STATUS (GST_RTSP_STS_NOT_ENOUGH_BANDWIDTH, "Not Enough Bandwidth");
232 DEF_STATUS (GST_RTSP_STS_SESSION_NOT_FOUND, "Session Not Found");
233 DEF_STATUS (GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
234 "Method Not Valid in This State");
235 DEF_STATUS (GST_RTSP_STS_HEADER_FIELD_NOT_VALID_FOR_RESOURCE,
236 "Header Field Not Valid for Resource");
237 DEF_STATUS (GST_RTSP_STS_INVALID_RANGE, "Invalid Range");
238 DEF_STATUS (GST_RTSP_STS_PARAMETER_IS_READONLY, "Parameter Is Read-Only");
239 DEF_STATUS (GST_RTSP_STS_AGGREGATE_OPERATION_NOT_ALLOWED,
240 "Aggregate operation not allowed");
241 DEF_STATUS (GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED,
242 "Only aggregate operation allowed");
243 DEF_STATUS (GST_RTSP_STS_UNSUPPORTED_TRANSPORT, "Unsupported transport");
244 DEF_STATUS (GST_RTSP_STS_DESTINATION_UNREACHABLE, "Destination unreachable");
245 DEF_STATUS (GST_RTSP_STS_KEY_MANAGEMENT_FAILURE, "Key management failure");
246 DEF_STATUS (GST_RTSP_STS_INTERNAL_SERVER_ERROR, "Internal Server Error");
247 DEF_STATUS (GST_RTSP_STS_NOT_IMPLEMENTED, "Not Implemented");
248 DEF_STATUS (GST_RTSP_STS_BAD_GATEWAY, "Bad Gateway");
249 DEF_STATUS (GST_RTSP_STS_SERVICE_UNAVAILABLE, "Service Unavailable");
250 DEF_STATUS (GST_RTSP_STS_GATEWAY_TIMEOUT, "Gateway Time-out");
251 DEF_STATUS (GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
252 "RTSP Version not supported");
253 DEF_STATUS (GST_RTSP_STS_OPTION_NOT_SUPPORTED, "Option not supported");
254
255 return statuses;
256 }
257
258 /**
259 * gst_rtsp_strresult:
260 * @result: a #GstRTSPResult
261 *
262 * Convert @result in a human readable string.
263 *
264 * Returns: a newly allocated string. g_free() after usage.
265 */
266 gchar *
gst_rtsp_strresult(GstRTSPResult result)267 gst_rtsp_strresult (GstRTSPResult result)
268 {
269 switch (result) {
270 case GST_RTSP_OK:
271 return g_strdup ("OK");
272 case GST_RTSP_ESYS:
273 return g_strdup ("System error");
274 case GST_RTSP_ENET:
275 return g_strdup ("Network error");
276 case GST_RTSP_ERROR:
277 return g_strdup ("Generic error");
278 case GST_RTSP_EINVAL:
279 return g_strdup ("Invalid parameter specified");
280 case GST_RTSP_EINTR:
281 return g_strdup ("Operation interrupted");
282 case GST_RTSP_ENOMEM:
283 return g_strdup ("Out of memory");
284 case GST_RTSP_ERESOLV:
285 return g_strdup ("Cannot resolve host");
286 case GST_RTSP_ENOTIMPL:
287 return g_strdup ("Function not implemented");
288 case GST_RTSP_EPARSE:
289 return g_strdup ("Parse error");
290 case GST_RTSP_EWSASTART:
291 return g_strdup ("Error on WSAStartup");
292 case GST_RTSP_EWSAVERSION:
293 return g_strdup ("Windows sockets are not version 0x202");
294 case GST_RTSP_EEOF:
295 return g_strdup ("Received end-of-file");
296 case GST_RTSP_ENOTIP:
297 return g_strdup ("Host is not a valid IP address");
298 case GST_RTSP_ETIMEOUT:
299 return g_strdup ("Timeout while waiting for server response");
300 case GST_RTSP_ETGET:
301 return g_strdup ("Tunnel GET request received");
302 case GST_RTSP_ETPOST:
303 return g_strdup ("Tunnel POST request received");
304 case GST_RTSP_ELAST:
305 default:
306 return g_strdup_printf ("Unknown error (%d)", result);
307 }
308 }
309
310 /**
311 * gst_rtsp_method_as_text:
312 * @method: a #GstRTSPMethod
313 *
314 * Convert @method to a string.
315 *
316 * Returns: a string representation of @method.
317 */
318 const gchar *
gst_rtsp_method_as_text(GstRTSPMethod method)319 gst_rtsp_method_as_text (GstRTSPMethod method)
320 {
321 gint i;
322
323 if (method == GST_RTSP_INVALID)
324 return NULL;
325
326 i = 0;
327 while ((method & 1) == 0) {
328 i++;
329 method >>= 1;
330 }
331 return rtsp_methods[i];
332 }
333
334 /**
335 * gst_rtsp_version_as_text:
336 * @version: a #GstRTSPVersion
337 *
338 * Convert @version to a string.
339 *
340 * Returns: a string representation of @version.
341 */
342 const gchar *
gst_rtsp_version_as_text(GstRTSPVersion version)343 gst_rtsp_version_as_text (GstRTSPVersion version)
344 {
345 switch (version) {
346 case GST_RTSP_VERSION_1_0:
347 return "1.0";
348
349 case GST_RTSP_VERSION_1_1:
350 return "1.1";
351
352 case GST_RTSP_VERSION_2_0:
353 return "2.0";
354
355
356 default:
357 return "0.0";
358 }
359 }
360
361 /**
362 * gst_rtsp_header_as_text:
363 * @field: a #GstRTSPHeaderField
364 *
365 * Convert @field to a string.
366 *
367 * Returns: a string representation of @field.
368 */
369 const gchar *
gst_rtsp_header_as_text(GstRTSPHeaderField field)370 gst_rtsp_header_as_text (GstRTSPHeaderField field)
371 {
372 if (field == GST_RTSP_HDR_INVALID)
373 return NULL;
374 else
375 return rtsp_headers[field - 1].name;
376 }
377
378 /**
379 * gst_rtsp_status_as_text:
380 * @code: a #GstRTSPStatusCode
381 *
382 * Convert @code to a string.
383 *
384 * Returns: a string representation of @code.
385 */
386 const gchar *
gst_rtsp_status_as_text(GstRTSPStatusCode code)387 gst_rtsp_status_as_text (GstRTSPStatusCode code)
388 {
389 static GHashTable *statuses;
390
391 if (G_UNLIKELY (statuses == NULL))
392 statuses = rtsp_init_status ();
393
394 return g_hash_table_lookup (statuses, GUINT_TO_POINTER (code));
395 }
396
397 /**
398 * gst_rtsp_find_header_field:
399 * @header: a header string
400 *
401 * Convert @header to a #GstRTSPHeaderField.
402 *
403 * Returns: a #GstRTSPHeaderField for @header or #GST_RTSP_HDR_INVALID if the
404 * header field is unknown.
405 */
406 GstRTSPHeaderField
gst_rtsp_find_header_field(const gchar * header)407 gst_rtsp_find_header_field (const gchar * header)
408 {
409 gint idx;
410
411 for (idx = 0; rtsp_headers[idx].name; idx++) {
412 if (g_ascii_strcasecmp (rtsp_headers[idx].name, header) == 0) {
413 return idx + 1;
414 }
415 }
416 return GST_RTSP_HDR_INVALID;
417 }
418
419 /**
420 * gst_rtsp_find_method:
421 * @method: a method
422 *
423 * Convert @method to a #GstRTSPMethod.
424 *
425 * Returns: a #GstRTSPMethod for @method or #GST_RTSP_INVALID if the
426 * method is unknown.
427 */
428 GstRTSPMethod
gst_rtsp_find_method(const gchar * method)429 gst_rtsp_find_method (const gchar * method)
430 {
431 gint idx;
432
433 for (idx = 0; rtsp_methods[idx]; idx++) {
434 if (g_ascii_strcasecmp (rtsp_methods[idx], method) == 0) {
435 return (1 << idx);
436 }
437 }
438 return GST_RTSP_INVALID;
439 }
440
441 /**
442 * gst_rtsp_options_as_text:
443 * @options: one or more #GstRTSPMethod
444 *
445 * Convert @options to a string.
446 *
447 * Returns: a new string of @options. g_free() after usage.
448 */
449 gchar *
gst_rtsp_options_as_text(GstRTSPMethod options)450 gst_rtsp_options_as_text (GstRTSPMethod options)
451 {
452 GString *str;
453
454 str = g_string_new ("");
455
456 if (options & GST_RTSP_OPTIONS)
457 g_string_append (str, "OPTIONS, ");
458 if (options & GST_RTSP_DESCRIBE)
459 g_string_append (str, "DESCRIBE, ");
460 if (options & GST_RTSP_ANNOUNCE)
461 g_string_append (str, "ANNOUNCE, ");
462 if (options & GST_RTSP_GET_PARAMETER)
463 g_string_append (str, "GET_PARAMETER, ");
464 if (options & GST_RTSP_PAUSE)
465 g_string_append (str, "PAUSE, ");
466 if (options & GST_RTSP_PLAY)
467 g_string_append (str, "PLAY, ");
468 if (options & GST_RTSP_RECORD)
469 g_string_append (str, "RECORD, ");
470 if (options & GST_RTSP_REDIRECT)
471 g_string_append (str, "REDIRECT, ");
472 if (options & GST_RTSP_SETUP)
473 g_string_append (str, "SETUP, ");
474 if (options & GST_RTSP_SET_PARAMETER)
475 g_string_append (str, "SET_PARAMETER, ");
476 if (options & GST_RTSP_TEARDOWN)
477 g_string_append (str, "TEARDOWN, ");
478
479 /* remove trailing ", " if there is one */
480 if (str->len > 2)
481 str = g_string_truncate (str, str->len - 2);
482
483 return g_string_free (str, FALSE);
484 }
485
486 /**
487 * gst_rtsp_options_from_text:
488 * @options: a comma separated list of options
489 *
490 * Convert the comma separated list @options to a #GstRTSPMethod bitwise or
491 * of methods. This functions is the reverse of gst_rtsp_options_as_text().
492 *
493 * Returns: a #GstRTSPMethod
494 *
495 * Since: 1.2
496 */
497 GstRTSPMethod
gst_rtsp_options_from_text(const gchar * options)498 gst_rtsp_options_from_text (const gchar * options)
499 {
500 GstRTSPMethod methods;
501 gchar **ostr;
502 gint i;
503
504 /* The string is like:
505 * OPTIONS, DESCRIBE, ANNOUNCE, PLAY, SETUP, ...
506 */
507 ostr = g_strsplit (options, ",", 0);
508
509 methods = 0;
510 for (i = 0; ostr[i]; i++) {
511 gchar *stripped;
512 GstRTSPMethod method;
513
514 stripped = g_strstrip (ostr[i]);
515 method = gst_rtsp_find_method (stripped);
516
517 /* keep bitfield of supported methods */
518 if (method != GST_RTSP_INVALID)
519 methods |= method;
520 }
521 g_strfreev (ostr);
522
523 return methods;
524 }
525
526 /**
527 * gst_rtsp_header_allow_multiple:
528 * @field: a #GstRTSPHeaderField
529 *
530 * Check whether @field may appear multiple times in a message.
531 *
532 * Returns: %TRUE if multiple headers are allowed.
533 */
534 gboolean
gst_rtsp_header_allow_multiple(GstRTSPHeaderField field)535 gst_rtsp_header_allow_multiple (GstRTSPHeaderField field)
536 {
537 if (field == GST_RTSP_HDR_INVALID)
538 return FALSE;
539 else
540 return rtsp_headers[field - 1].multiple;
541 }
542
543 static gchar *
auth_digest_compute_a1_md5(const gchar * realm,const gchar * username,const gchar * password)544 auth_digest_compute_a1_md5 (const gchar * realm, const gchar * username,
545 const gchar * password)
546 {
547 GChecksum *md5_context = g_checksum_new (G_CHECKSUM_MD5);
548 gchar *ret;
549
550 g_checksum_update (md5_context, (const guchar *) username, strlen (username));
551 g_checksum_update (md5_context, (const guchar *) ":", 1);
552 g_checksum_update (md5_context, (const guchar *) realm, strlen (realm));
553 g_checksum_update (md5_context, (const guchar *) ":", 1);
554 g_checksum_update (md5_context, (const guchar *) password, strlen (password));
555 ret = g_strdup (g_checksum_get_string (md5_context));
556 g_assert (strlen (ret) == 32);
557 g_checksum_free (md5_context);
558
559 return ret;
560 }
561
562 /* See RFC2069, 2.1.2 */
563 static gchar *
auth_digest_compute_response_md5(const gchar * method,const gchar * a1,const gchar * uri,const gchar * nonce)564 auth_digest_compute_response_md5 (const gchar * method, const gchar * a1,
565 const gchar * uri, const gchar * nonce)
566 {
567 gchar hex_a1[33] = { 0, };
568 gchar hex_a2[33] = { 0, };
569 GChecksum *md5_context = g_checksum_new (G_CHECKSUM_MD5);
570 const gchar *digest_string;
571 gchar *response = NULL;
572
573 if (strlen (a1) != 32)
574 goto done;
575
576 memcpy (hex_a1, a1, 32);
577 g_checksum_reset (md5_context);
578
579 /* compute A2 */
580 g_checksum_update (md5_context, (const guchar *) method, strlen (method));
581 g_checksum_update (md5_context, (const guchar *) ":", 1);
582 g_checksum_update (md5_context, (const guchar *) uri, strlen (uri));
583 digest_string = g_checksum_get_string (md5_context);
584 g_assert (strlen (digest_string) == 32);
585 memcpy (hex_a2, digest_string, 32);
586
587 /* compute KD */
588 g_checksum_reset (md5_context);
589 g_checksum_update (md5_context, (const guchar *) hex_a1, strlen (hex_a1));
590 g_checksum_update (md5_context, (const guchar *) ":", 1);
591 g_checksum_update (md5_context, (const guchar *) nonce, strlen (nonce));
592 g_checksum_update (md5_context, (const guchar *) ":", 1);
593
594 g_checksum_update (md5_context, (const guchar *) hex_a2, 32);
595 response = g_strdup (g_checksum_get_string (md5_context));
596
597 done:
598 g_checksum_free (md5_context);
599
600 return response;
601 }
602
603 /**
604 * gst_rtsp_generate_digest_auth_response:
605 * @algorithm: (allow-none): Hash algorithm to use, or %NULL for MD5
606 * @method: Request method, e.g. PLAY
607 * @realm: Realm
608 * @username: Username
609 * @password: Password
610 * @uri: Original request URI
611 * @nonce: Nonce
612 *
613 * Calculates the digest auth response from the values given by the server and
614 * the username and password. See RFC2069 for details.
615 *
616 * Currently only supported algorithm "md5".
617 *
618 * Returns: Authentication response or %NULL if unsupported
619 *
620 * Since: 1.12
621 */
622 gchar *
gst_rtsp_generate_digest_auth_response(const gchar * algorithm,const gchar * method,const gchar * realm,const gchar * username,const gchar * password,const gchar * uri,const gchar * nonce)623 gst_rtsp_generate_digest_auth_response (const gchar * algorithm,
624 const gchar * method, const gchar * realm, const gchar * username,
625 const gchar * password, const gchar * uri, const gchar * nonce)
626 {
627 gchar *ret = NULL;
628 g_return_val_if_fail (method != NULL, NULL);
629 g_return_val_if_fail (realm != NULL, NULL);
630 g_return_val_if_fail (username != NULL, NULL);
631 g_return_val_if_fail (password != NULL, NULL);
632 g_return_val_if_fail (uri != NULL, NULL);
633 g_return_val_if_fail (nonce != NULL, NULL);
634
635 if (algorithm == NULL || g_ascii_strcasecmp (algorithm, "md5") == 0) {
636 gchar *a1 = auth_digest_compute_a1_md5 (realm, username, password);
637 ret = auth_digest_compute_response_md5 (method, a1, uri, nonce);
638 g_free (a1);
639 }
640
641 return ret;
642 }
643
644 /**
645 * gst_rtsp_generate_digest_auth_response_from_md5:
646 * @algorithm: (allow-none): Hash algorithm to use, or %NULL for MD5
647 * @method: Request method, e.g. PLAY
648 * @md5: The md5 sum of username:realm:password
649 * @uri: Original request URI
650 * @nonce: Nonce
651 *
652 * Calculates the digest auth response from the values given by the server and
653 * the md5sum. See RFC2069 for details.
654 *
655 * This function is useful when the passwords are not stored in clear text,
656 * but instead in the same format as the .htdigest file.
657 *
658 * Currently only supported algorithm "md5".
659 *
660 * Returns: Authentication response or %NULL if unsupported
661 *
662 * Since: 1.16
663 */
664 gchar *
gst_rtsp_generate_digest_auth_response_from_md5(const gchar * algorithm,const gchar * method,const gchar * md5,const gchar * uri,const gchar * nonce)665 gst_rtsp_generate_digest_auth_response_from_md5 (const gchar * algorithm,
666 const gchar * method, const gchar * md5, const gchar * uri,
667 const gchar * nonce)
668 {
669 if (algorithm == NULL || g_ascii_strcasecmp (algorithm, "md5") == 0)
670 return auth_digest_compute_response_md5 (method, md5, uri, nonce);
671
672 return NULL;
673 }
674