Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * Copyright (c) 2007 The FFmpeg Project |
||
3 | * |
||
4 | * This file is part of FFmpeg. |
||
5 | * |
||
6 | * FFmpeg is free software; you can redistribute it and/or |
||
7 | * modify it under the terms of the GNU Lesser General Public |
||
8 | * License as published by the Free Software Foundation; either |
||
9 | * version 2.1 of the License, or (at your option) any later version. |
||
10 | * |
||
11 | * FFmpeg is distributed in the hope that it will be useful, |
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
14 | * Lesser General Public License for more details. |
||
15 | * |
||
16 | * You should have received a copy of the GNU Lesser General Public |
||
17 | * License along with FFmpeg; if not, write to the Free Software |
||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
19 | */ |
||
20 | |||
21 | #include |
||
22 | #include "network.h" |
||
23 | #include "url.h" |
||
24 | #include "libavcodec/internal.h" |
||
25 | #include "libavutil/avutil.h" |
||
26 | #include "libavutil/mem.h" |
||
27 | #include "libavutil/time.h" |
||
28 | |||
29 | #if HAVE_THREADS |
||
30 | #if HAVE_PTHREADS |
||
31 | #include |
||
32 | #elif HAVE_OS2THREADS |
||
33 | #include "compat/os2threads.h" |
||
34 | #else |
||
35 | #include "compat/w32pthreads.h" |
||
36 | #endif |
||
37 | #endif |
||
38 | |||
39 | #if CONFIG_OPENSSL |
||
40 | #include |
||
41 | static int openssl_init; |
||
42 | #if HAVE_THREADS |
||
43 | #include |
||
44 | pthread_mutex_t *openssl_mutexes; |
||
45 | static void openssl_lock(int mode, int type, const char *file, int line) |
||
46 | { |
||
47 | if (mode & CRYPTO_LOCK) |
||
48 | pthread_mutex_lock(&openssl_mutexes[type]); |
||
49 | else |
||
50 | pthread_mutex_unlock(&openssl_mutexes[type]); |
||
51 | } |
||
52 | #if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000 |
||
53 | static unsigned long openssl_thread_id(void) |
||
54 | { |
||
55 | return (intptr_t) pthread_self(); |
||
56 | } |
||
57 | #endif |
||
58 | #endif |
||
59 | #endif |
||
60 | #if CONFIG_GNUTLS |
||
61 | #include |
||
62 | #if HAVE_THREADS && GNUTLS_VERSION_NUMBER <= 0x020b00 |
||
63 | #include |
||
64 | #include |
||
65 | GCRY_THREAD_OPTION_PTHREAD_IMPL; |
||
66 | #endif |
||
67 | #endif |
||
68 | |||
69 | void ff_tls_init(void) |
||
70 | { |
||
71 | avpriv_lock_avformat(); |
||
72 | #if CONFIG_OPENSSL |
||
73 | if (!openssl_init) { |
||
74 | SSL_library_init(); |
||
75 | SSL_load_error_strings(); |
||
76 | #if HAVE_THREADS |
||
77 | if (!CRYPTO_get_locking_callback()) { |
||
78 | int i; |
||
79 | openssl_mutexes = av_malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks()); |
||
80 | for (i = 0; i < CRYPTO_num_locks(); i++) |
||
81 | pthread_mutex_init(&openssl_mutexes[i], NULL); |
||
82 | CRYPTO_set_locking_callback(openssl_lock); |
||
83 | #if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000 |
||
84 | CRYPTO_set_id_callback(openssl_thread_id); |
||
85 | #endif |
||
86 | } |
||
87 | #endif |
||
88 | } |
||
89 | openssl_init++; |
||
90 | #endif |
||
91 | #if CONFIG_GNUTLS |
||
92 | #if HAVE_THREADS && GNUTLS_VERSION_NUMBER < 0x020b00 |
||
93 | if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0) |
||
94 | gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); |
||
95 | #endif |
||
96 | gnutls_global_init(); |
||
97 | #endif |
||
98 | avpriv_unlock_avformat(); |
||
99 | } |
||
100 | |||
101 | void ff_tls_deinit(void) |
||
102 | { |
||
103 | avpriv_lock_avformat(); |
||
104 | #if CONFIG_OPENSSL |
||
105 | openssl_init--; |
||
106 | if (!openssl_init) { |
||
107 | #if HAVE_THREADS |
||
108 | if (CRYPTO_get_locking_callback() == openssl_lock) { |
||
109 | int i; |
||
110 | CRYPTO_set_locking_callback(NULL); |
||
111 | for (i = 0; i < CRYPTO_num_locks(); i++) |
||
112 | pthread_mutex_destroy(&openssl_mutexes[i]); |
||
113 | av_free(openssl_mutexes); |
||
114 | } |
||
115 | #endif |
||
116 | } |
||
117 | #endif |
||
118 | #if CONFIG_GNUTLS |
||
119 | gnutls_global_deinit(); |
||
120 | #endif |
||
121 | avpriv_unlock_avformat(); |
||
122 | } |
||
123 | |||
124 | int ff_network_inited_globally; |
||
125 | |||
126 | int ff_network_init(void) |
||
127 | { |
||
128 | #if HAVE_WINSOCK2_H |
||
129 | WSADATA wsaData; |
||
130 | #endif |
||
131 | |||
132 | if (!ff_network_inited_globally) |
||
133 | av_log(NULL, AV_LOG_WARNING, "Using network protocols without global " |
||
134 | "network initialization. Please use " |
||
135 | "avformat_network_init(), this will " |
||
136 | "become mandatory later.\n"); |
||
137 | #if HAVE_WINSOCK2_H |
||
138 | if (WSAStartup(MAKEWORD(1,1), &wsaData)) |
||
139 | return 0; |
||
140 | #endif |
||
141 | return 1; |
||
142 | } |
||
143 | |||
144 | int ff_network_wait_fd(int fd, int write) |
||
145 | { |
||
146 | int ev = write ? POLLOUT : POLLIN; |
||
147 | struct pollfd p = { .fd = fd, .events = ev, .revents = 0 }; |
||
148 | int ret; |
||
149 | ret = poll(&p, 1, 100); |
||
150 | return ret < 0 ? ff_neterrno() : p.revents & (ev | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN); |
||
151 | } |
||
152 | |||
153 | int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb) |
||
154 | { |
||
155 | int ret; |
||
156 | int64_t wait_start = 0; |
||
157 | |||
158 | while (1) { |
||
159 | if (ff_check_interrupt(int_cb)) |
||
160 | return AVERROR_EXIT; |
||
161 | ret = ff_network_wait_fd(fd, write); |
||
162 | if (ret != AVERROR(EAGAIN)) |
||
163 | return ret; |
||
164 | if (timeout > 0) { |
||
165 | if (!wait_start) |
||
166 | wait_start = av_gettime(); |
||
167 | else if (av_gettime() - wait_start > timeout) |
||
168 | return AVERROR(ETIMEDOUT); |
||
169 | } |
||
170 | } |
||
171 | } |
||
172 | |||
173 | void ff_network_close(void) |
||
174 | { |
||
175 | #if HAVE_WINSOCK2_H |
||
176 | WSACleanup(); |
||
177 | #endif |
||
178 | } |
||
179 | |||
180 | #if HAVE_WINSOCK2_H |
||
181 | int ff_neterrno(void) |
||
182 | { |
||
183 | int err = WSAGetLastError(); |
||
184 | switch (err) { |
||
185 | case WSAEWOULDBLOCK: |
||
186 | return AVERROR(EAGAIN); |
||
187 | case WSAEINTR: |
||
188 | return AVERROR(EINTR); |
||
189 | case WSAEPROTONOSUPPORT: |
||
190 | return AVERROR(EPROTONOSUPPORT); |
||
191 | case WSAETIMEDOUT: |
||
192 | return AVERROR(ETIMEDOUT); |
||
193 | case WSAECONNREFUSED: |
||
194 | return AVERROR(ECONNREFUSED); |
||
195 | case WSAEINPROGRESS: |
||
196 | return AVERROR(EINPROGRESS); |
||
197 | } |
||
198 | return -err; |
||
199 | } |
||
200 | #endif |
||
201 | |||
202 | int ff_is_multicast_address(struct sockaddr *addr) |
||
203 | { |
||
204 | if (addr->sa_family == AF_INET) { |
||
205 | return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr)); |
||
206 | } |
||
207 | #if HAVE_STRUCT_SOCKADDR_IN6 |
||
208 | if (addr->sa_family == AF_INET6) { |
||
209 | return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr); |
||
210 | } |
||
211 | #endif |
||
212 | |||
213 | return 0; |
||
214 | } |
||
215 | |||
216 | static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout, |
||
217 | AVIOInterruptCB *cb) |
||
218 | { |
||
219 | int runs = timeout / POLLING_TIME; |
||
220 | int ret = 0; |
||
221 | |||
222 | do { |
||
223 | if (ff_check_interrupt(cb)) |
||
224 | return AVERROR_EXIT; |
||
225 | ret = poll(p, nfds, POLLING_TIME); |
||
226 | if (ret != 0) |
||
227 | break; |
||
228 | } while (timeout <= 0 || runs-- > 0); |
||
229 | |||
230 | if (!ret) |
||
231 | return AVERROR(ETIMEDOUT); |
||
232 | if (ret < 0) |
||
233 | return AVERROR(errno); |
||
234 | return ret; |
||
235 | } |
||
236 | |||
237 | int ff_socket(int af, int type, int proto) |
||
238 | { |
||
239 | int fd; |
||
240 | |||
241 | #ifdef SOCK_CLOEXEC |
||
242 | fd = socket(af, type | SOCK_CLOEXEC, proto); |
||
243 | if (fd == -1 && errno == EINVAL) |
||
244 | #endif |
||
245 | { |
||
246 | fd = socket(af, type, proto); |
||
247 | #if HAVE_FCNTL |
||
248 | if (fd != -1) { |
||
249 | if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) |
||
250 | av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n"); |
||
251 | } |
||
252 | #endif |
||
253 | } |
||
254 | return fd; |
||
255 | } |
||
256 | |||
257 | int ff_listen_bind(int fd, const struct sockaddr *addr, |
||
258 | socklen_t addrlen, int timeout, URLContext *h) |
||
259 | { |
||
260 | int ret; |
||
261 | int reuse = 1; |
||
262 | struct pollfd lp = { fd, POLLIN, 0 }; |
||
263 | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) { |
||
264 | av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n"); |
||
265 | } |
||
266 | ret = bind(fd, addr, addrlen); |
||
267 | if (ret) |
||
268 | return ff_neterrno(); |
||
269 | |||
270 | ret = listen(fd, 1); |
||
271 | if (ret) |
||
272 | return ff_neterrno(); |
||
273 | |||
274 | ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback); |
||
275 | if (ret < 0) |
||
276 | return ret; |
||
277 | |||
278 | ret = accept(fd, NULL, NULL); |
||
279 | if (ret < 0) |
||
280 | return ff_neterrno(); |
||
281 | |||
282 | closesocket(fd); |
||
283 | |||
284 | ff_socket_nonblock(ret, 1); |
||
285 | return ret; |
||
286 | } |
||
287 | |||
288 | int ff_listen_connect(int fd, const struct sockaddr *addr, |
||
289 | socklen_t addrlen, int timeout, URLContext *h, |
||
290 | int will_try_next) |
||
291 | { |
||
292 | struct pollfd p = {fd, POLLOUT, 0}; |
||
293 | int ret; |
||
294 | socklen_t optlen; |
||
295 | |||
296 | ff_socket_nonblock(fd, 1); |
||
297 | |||
298 | while ((ret = connect(fd, addr, addrlen))) { |
||
299 | ret = ff_neterrno(); |
||
300 | switch (ret) { |
||
301 | case AVERROR(EINTR): |
||
302 | if (ff_check_interrupt(&h->interrupt_callback)) |
||
303 | return AVERROR_EXIT; |
||
304 | continue; |
||
305 | case AVERROR(EINPROGRESS): |
||
306 | case AVERROR(EAGAIN): |
||
307 | ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback); |
||
308 | if (ret < 0) |
||
309 | return ret; |
||
310 | optlen = sizeof(ret); |
||
311 | if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) |
||
312 | ret = AVUNERROR(ff_neterrno()); |
||
313 | if (ret != 0) { |
||
314 | char errbuf[100]; |
||
315 | ret = AVERROR(ret); |
||
316 | av_strerror(ret, errbuf, sizeof(errbuf)); |
||
317 | if (will_try_next) |
||
318 | av_log(h, AV_LOG_WARNING, |
||
319 | "Connection to %s failed (%s), trying next address\n", |
||
320 | h->filename, errbuf); |
||
321 | else |
||
322 | av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n", |
||
323 | h->filename, errbuf); |
||
324 | } |
||
325 | default: |
||
326 | return ret; |
||
327 | } |
||
328 | } |
||
329 | return ret; |
||
330 | } |
||
331 | |||
332 | static int match_host_pattern(const char *pattern, const char *hostname) |
||
333 | { |
||
334 | int len_p, len_h; |
||
335 | if (!strcmp(pattern, "*")) |
||
336 | return 1; |
||
337 | // Skip a possible *. at the start of the pattern |
||
338 | if (pattern[0] == '*') |
||
339 | pattern++; |
||
340 | if (pattern[0] == '.') |
||
341 | pattern++; |
||
342 | len_p = strlen(pattern); |
||
343 | len_h = strlen(hostname); |
||
344 | if (len_p > len_h) |
||
345 | return 0; |
||
346 | // Simply check if the end of hostname is equal to 'pattern' |
||
347 | if (!strcmp(pattern, &hostname[len_h - len_p])) { |
||
348 | if (len_h == len_p) |
||
349 | return 1; // Exact match |
||
350 | if (hostname[len_h - len_p - 1] == '.') |
||
351 | return 1; // The matched substring is a domain and not just a substring of a domain |
||
352 | } |
||
353 | return 0; |
||
354 | } |
||
355 | |||
356 | int ff_http_match_no_proxy(const char *no_proxy, const char *hostname) |
||
357 | { |
||
358 | char *buf, *start; |
||
359 | int ret = 0; |
||
360 | if (!no_proxy) |
||
361 | return 0; |
||
362 | if (!hostname) |
||
363 | return 0; |
||
364 | buf = av_strdup(no_proxy); |
||
365 | if (!buf) |
||
366 | return 0; |
||
367 | start = buf; |
||
368 | while (start) { |
||
369 | char *sep, *next = NULL; |
||
370 | start += strspn(start, " ,"); |
||
371 | sep = start + strcspn(start, " ,"); |
||
372 | if (*sep) { |
||
373 | next = sep + 1; |
||
374 | *sep = '\0'; |
||
375 | } |
||
376 | if (match_host_pattern(start, hostname)) { |
||
377 | ret = 1; |
||
378 | break; |
||
379 | } |
||
380 | start = next; |
||
381 | } |
||
382 | av_free(buf); |
||
383 | return ret; |
||
384 | }>>>>=>>>>>>=>> |