56 #include <stdlib.h> |
56 #include <stdlib.h> |
57 #include <string.h> |
57 #include <string.h> |
58 |
58 |
59 #include "gstrtspurl.h" |
59 #include "gstrtspurl.h" |
60 |
60 |
61 #define RTSP_PROTO "rtsp://" |
61 static void |
62 #define RTSP_PROTO_LEN 7 |
62 register_rtsp_url_type (GType * id) |
63 #define RTSPU_PROTO "rtspu://" |
63 { |
64 #define RTSPU_PROTO_LEN 8 |
64 *id = g_boxed_type_register_static ("GstRTSPUrl", |
65 #define RTSPT_PROTO "rtspt://" |
65 (GBoxedCopyFunc) gst_rtsp_url_copy, (GBoxedFreeFunc) gst_rtsp_url_free); |
66 #define RTSPT_PROTO_LEN 8 |
66 } |
67 |
67 |
68 /* format is rtsp[u]://[user:passwd@]host[:port]/abspath[?query] */ |
68 GType |
|
69 gst_rtsp_url_get_type (void) |
|
70 { |
|
71 static GType id; |
|
72 static GOnce once = G_ONCE_INIT; |
|
73 |
|
74 g_once (&once, (GThreadFunc) register_rtsp_url_type, &id); |
|
75 return id; |
|
76 } |
|
77 |
|
78 static const gchar *rtsp_url_schemes[] = { |
|
79 "rtsp", |
|
80 "rtspu", |
|
81 "rtspt", |
|
82 "rtsph", |
|
83 NULL |
|
84 }; |
|
85 |
|
86 static GstRTSPLowerTrans rtsp_url_transports[] = { |
|
87 GST_RTSP_LOWER_TRANS_TCP | GST_RTSP_LOWER_TRANS_UDP | |
|
88 GST_RTSP_LOWER_TRANS_UDP_MCAST, |
|
89 GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST, |
|
90 GST_RTSP_LOWER_TRANS_TCP, |
|
91 GST_RTSP_LOWER_TRANS_HTTP | GST_RTSP_LOWER_TRANS_TCP, |
|
92 }; |
|
93 |
|
94 /* format is rtsp[u]://[user:passwd@]host[:port]/abspath[?query] where host |
|
95 * is a host name, an IPv4 dotted decimal address ("aaa.bbb.ccc.ddd") or an |
|
96 * [IPv6] address ("[aabb:ccdd:eeff:gghh::sstt]" note the brackets around the |
|
97 * address to allow the distinction between ':' as an IPv6 hexgroup separator |
|
98 * and as a host/port separator) */ |
69 |
99 |
70 /** |
100 /** |
71 * gst_rtsp_url_parse: |
101 * gst_rtsp_url_parse: |
72 * @urlstr: the url string to parse |
102 * @urlstr: the url string to parse |
73 * @url: location to hold the result. |
103 * @url: location to hold the result. |
80 GstRTSPResult |
110 GstRTSPResult |
81 gst_rtsp_url_parse (const gchar * urlstr, GstRTSPUrl ** url) |
111 gst_rtsp_url_parse (const gchar * urlstr, GstRTSPUrl ** url) |
82 { |
112 { |
83 GstRTSPUrl *res; |
113 GstRTSPUrl *res; |
84 gchar *p, *delim, *at, *col; |
114 gchar *p, *delim, *at, *col; |
|
115 gchar *host_end = NULL; |
|
116 guint scheme; |
85 |
117 |
86 g_return_val_if_fail (urlstr != NULL, GST_RTSP_EINVAL); |
118 g_return_val_if_fail (urlstr != NULL, GST_RTSP_EINVAL); |
87 g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL); |
119 g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL); |
88 |
120 |
89 res = g_new0 (GstRTSPUrl, 1); |
121 res = g_new0 (GstRTSPUrl, 1); |
90 |
122 |
91 p = (gchar *) urlstr; |
123 p = (gchar *) urlstr; |
92 if (g_str_has_prefix (p, RTSP_PROTO)) { |
124 |
93 res->transports = |
125 col = strstr (p, "://"); |
94 GST_RTSP_LOWER_TRANS_TCP | GST_RTSP_LOWER_TRANS_UDP | |
126 if (col == NULL) |
95 GST_RTSP_LOWER_TRANS_UDP_MCAST; |
127 goto invalid; |
96 p += RTSP_PROTO_LEN; |
128 |
97 } else if (g_str_has_prefix (p, RTSPU_PROTO)) { |
129 for (scheme = 0; rtsp_url_schemes[scheme] != NULL; scheme++) { |
98 res->transports = GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST; |
130 if (g_ascii_strncasecmp (rtsp_url_schemes[scheme], p, col - p) == 0) { |
99 p += RTSPU_PROTO_LEN; |
131 res->transports = rtsp_url_transports[scheme]; |
100 } else if (g_str_has_prefix (p, RTSPT_PROTO)) { |
132 p = col + 3; |
101 res->transports = GST_RTSP_LOWER_TRANS_TCP; |
133 break; |
102 p += RTSPT_PROTO_LEN; |
134 } |
103 } else |
135 } |
|
136 |
|
137 if (res->transports == GST_RTSP_LOWER_TRANS_UNKNOWN) |
104 goto invalid; |
138 goto invalid; |
105 |
139 |
106 delim = strpbrk (p, "/?"); |
140 delim = strpbrk (p, "/?"); |
107 at = strchr (p, '@'); |
141 at = strchr (p, '@'); |
108 |
142 |
122 |
156 |
123 /* move to host */ |
157 /* move to host */ |
124 p = at + 1; |
158 p = at + 1; |
125 } |
159 } |
126 |
160 |
127 col = strchr (p, ':'); |
161 if (*p == '[') { |
128 /* we have a ':' and a delimiter but the ':' is after the delimiter, it's |
162 res->family = GST_RTSP_FAM_INET6; |
129 * not really part of the hostname */ |
163 |
130 if (col && delim && col >= delim) |
164 /* we have an IPv6 address in the URL, find the ending ] which must be |
131 col = NULL; |
165 * before any delimiter */ |
132 |
166 host_end = strchr (++p, ']'); |
133 if (col) { |
167 if (!host_end || (delim && host_end >= delim)) |
134 res->host = g_strndup (p, col - p); |
168 goto invalid; |
135 p = col + 1; |
169 |
136 res->port = strtoul (p, (char **) &p, 10); |
170 /* a port specifier must follow the address immediately */ |
137 if (delim) |
171 col = host_end[1] == ':' ? host_end + 1 : NULL; |
138 p = delim; |
|
139 } else { |
172 } else { |
140 /* no port specified, set to 0. _get_port() will return the default port. */ |
173 res->family = GST_RTSP_FAM_INET; |
141 res->port = 0; |
174 |
142 if (!delim) { |
175 col = strchr (p, ':'); |
143 res->host = g_strdup (p); |
176 |
144 p = NULL; |
177 /* we have a ':' and a delimiter but the ':' is after the delimiter, it's |
|
178 * not really part of the hostname */ |
|
179 if (col && delim && col >= delim) |
|
180 col = NULL; |
|
181 |
|
182 host_end = col ? col : delim; |
|
183 } |
|
184 |
|
185 if (!host_end) |
|
186 res->host = g_strdup (p); |
|
187 else { |
|
188 res->host = g_strndup (p, host_end - p); |
|
189 |
|
190 if (col) { |
|
191 res->port = strtoul (col + 1, NULL, 10); |
145 } else { |
192 } else { |
146 res->host = g_strndup (p, delim - p); |
193 /* no port specified, set to 0. gst_rtsp_url_get_port() will return the |
147 p = delim; |
194 * default port */ |
|
195 res->port = 0; |
148 } |
196 } |
149 } |
197 } |
|
198 p = delim; |
150 |
199 |
151 if (p && *p == '/') { |
200 if (p && *p == '/') { |
152 delim = strchr (p, '?'); |
201 delim = strchr (p, '?'); |
153 if (!delim) { |
202 if (!delim) |
154 res->abspath = g_strdup (p); |
203 res->abspath = g_strdup (p); |
155 p = NULL; |
204 else |
156 } else { |
|
157 res->abspath = g_strndup (p, delim - p); |
205 res->abspath = g_strndup (p, delim - p); |
158 p = delim; |
206 p = delim; |
159 } |
|
160 } else { |
207 } else { |
161 res->abspath = g_strdup ("/"); |
208 res->abspath = g_strdup ("/"); |
162 } |
209 } |
163 |
210 |
164 if (p && *p == '?') |
211 if (p && *p == '?') |
172 invalid: |
219 invalid: |
173 { |
220 { |
174 gst_rtsp_url_free (res); |
221 gst_rtsp_url_free (res); |
175 return GST_RTSP_EINVAL; |
222 return GST_RTSP_EINVAL; |
176 } |
223 } |
|
224 } |
|
225 |
|
226 /** |
|
227 * gst_rtsp_url_copy: |
|
228 * @url: a #GstRTSPUrl |
|
229 * |
|
230 * Make a copy of @url. |
|
231 * |
|
232 * Returns: a copy of @url. Free with gst_rtsp_url_free () after usage. |
|
233 * |
|
234 * Since: 0.10.22 |
|
235 */ |
|
236 GstRTSPUrl * |
|
237 gst_rtsp_url_copy (const GstRTSPUrl * url) |
|
238 { |
|
239 GstRTSPUrl *res; |
|
240 |
|
241 g_return_val_if_fail (url != NULL, NULL); |
|
242 |
|
243 res = g_new0 (GstRTSPUrl, 1); |
|
244 |
|
245 res->transports = url->transports; |
|
246 res->family = url->family; |
|
247 res->user = g_strdup (url->user); |
|
248 res->passwd = g_strdup (url->passwd); |
|
249 res->host = g_strdup (url->host); |
|
250 res->port = url->port; |
|
251 res->abspath = g_strdup (url->abspath); |
|
252 res->query = g_strdup (url->query); |
|
253 |
|
254 return res; |
177 } |
255 } |
178 |
256 |
179 /** |
257 /** |
180 * gst_rtsp_url_free: |
258 * gst_rtsp_url_free: |
181 * @url: a #GstRTSPUrl |
259 * @url: a #GstRTSPUrl |
223 * Get the port number of @url. |
301 * Get the port number of @url. |
224 * |
302 * |
225 * Returns: #GST_RTSP_OK. |
303 * Returns: #GST_RTSP_OK. |
226 */ |
304 */ |
227 GstRTSPResult |
305 GstRTSPResult |
228 gst_rtsp_url_get_port (GstRTSPUrl * url, guint16 * port) |
306 gst_rtsp_url_get_port (const GstRTSPUrl * url, guint16 * port) |
229 { |
307 { |
230 g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL); |
308 g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL); |
231 g_return_val_if_fail (port != NULL, GST_RTSP_EINVAL); |
309 g_return_val_if_fail (port != NULL, GST_RTSP_EINVAL); |
232 |
310 |
233 /* if a port was specified, use that else use the default port. */ |
311 /* if a port was specified, use that else use the default port. */ |
246 * Get a newly allocated string describing the request URI for @url. |
324 * Get a newly allocated string describing the request URI for @url. |
247 * |
325 * |
248 * Returns: a string with the request URI. g_free() after usage. |
326 * Returns: a string with the request URI. g_free() after usage. |
249 */ |
327 */ |
250 gchar * |
328 gchar * |
251 gst_rtsp_url_get_request_uri (GstRTSPUrl * url) |
329 gst_rtsp_url_get_request_uri (const GstRTSPUrl * url) |
252 { |
330 { |
253 gchar *uri; |
331 gchar *uri; |
|
332 gchar *pre_host; |
|
333 gchar *post_host; |
|
334 gchar *pre_query; |
|
335 gchar *query; |
254 |
336 |
255 g_return_val_if_fail (url != NULL, NULL); |
337 g_return_val_if_fail (url != NULL, NULL); |
256 |
338 |
|
339 pre_host = url->family == GST_RTSP_FAM_INET6 ? "[" : ""; |
|
340 post_host = url->family == GST_RTSP_FAM_INET6 ? "]" : ""; |
|
341 pre_query = url->query ? "?" : ""; |
|
342 query = url->query ? url->query : ""; |
|
343 |
257 if (url->port != 0) { |
344 if (url->port != 0) { |
258 uri = g_strdup_printf ("rtsp://%s:%u%s%s%s", url->host, url->port, |
345 uri = g_strdup_printf ("rtsp://%s%s%s:%u%s%s%s", pre_host, url->host, |
259 url->abspath, url->query ? "?" : "", url->query ? url->query : ""); |
346 post_host, url->port, url->abspath, pre_query, query); |
260 } else { |
347 } else { |
261 uri = g_strdup_printf ("rtsp://%s%s%s%s", url->host, url->abspath, |
348 uri = g_strdup_printf ("rtsp://%s%s%s%s%s%s", pre_host, url->host, |
262 url->query ? "?" : "", url->query ? url->query : ""); |
349 post_host, url->abspath, pre_query, query); |
263 } |
350 } |
264 |
351 |
265 return uri; |
352 return uri; |
266 } |
353 } |