]> git.sesse.net Git - ffmpeg/blob - libavformat/network.c
Merge commit '82a10225f817b2612fdd2b23af9d4f0a3408df3b'
[ffmpeg] / libavformat / network.c
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 <fcntl.h>
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 <pthread.h>
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 <openssl/ssl.h>
41 static int openssl_init;
42 #if HAVE_THREADS
43 #include <openssl/crypto.h>
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 <gnutls/gnutls.h>
62 #if HAVE_THREADS && GNUTLS_VERSION_NUMBER <= 0x020b00
63 #include <gcrypt.h>
64 #include <errno.h>
65 GCRY_THREAD_OPTION_PTHREAD_IMPL;
66 #endif
67 #endif
68
69 int 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_array(sizeof(pthread_mutex_t), CRYPTO_num_locks());
80             if (!openssl_mutexes) {
81                 avpriv_unlock_avformat();
82                 return AVERROR(ENOMEM);
83             }
84             for (i = 0; i < CRYPTO_num_locks(); i++)
85                 pthread_mutex_init(&openssl_mutexes[i], NULL);
86             CRYPTO_set_locking_callback(openssl_lock);
87 #if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000
88             CRYPTO_set_id_callback(openssl_thread_id);
89 #endif
90         }
91 #endif
92     }
93     openssl_init++;
94 #endif
95 #if CONFIG_GNUTLS
96 #if HAVE_THREADS && GNUTLS_VERSION_NUMBER < 0x020b00
97     if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
98         gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
99 #endif
100     gnutls_global_init();
101 #endif
102     avpriv_unlock_avformat();
103
104     return 0;
105 }
106
107 void ff_tls_deinit(void)
108 {
109     avpriv_lock_avformat();
110 #if CONFIG_OPENSSL
111     openssl_init--;
112     if (!openssl_init) {
113 #if HAVE_THREADS
114         if (CRYPTO_get_locking_callback() == openssl_lock) {
115             int i;
116             CRYPTO_set_locking_callback(NULL);
117             for (i = 0; i < CRYPTO_num_locks(); i++)
118                 pthread_mutex_destroy(&openssl_mutexes[i]);
119             av_free(openssl_mutexes);
120         }
121 #endif
122     }
123 #endif
124 #if CONFIG_GNUTLS
125     gnutls_global_deinit();
126 #endif
127     avpriv_unlock_avformat();
128 }
129
130 int ff_network_inited_globally;
131
132 int ff_network_init(void)
133 {
134 #if HAVE_WINSOCK2_H
135     WSADATA wsaData;
136 #endif
137
138     if (!ff_network_inited_globally)
139         av_log(NULL, AV_LOG_WARNING, "Using network protocols without global "
140                                      "network initialization. Please use "
141                                      "avformat_network_init(), this will "
142                                      "become mandatory later.\n");
143 #if HAVE_WINSOCK2_H
144     if (WSAStartup(MAKEWORD(1,1), &wsaData))
145         return 0;
146 #endif
147     return 1;
148 }
149
150 int ff_network_wait_fd(int fd, int write)
151 {
152     int ev = write ? POLLOUT : POLLIN;
153     struct pollfd p = { .fd = fd, .events = ev, .revents = 0 };
154     int ret;
155     ret = poll(&p, 1, 100);
156     return ret < 0 ? ff_neterrno() : p.revents & (ev | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN);
157 }
158
159 int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb)
160 {
161     int ret;
162     int64_t wait_start = 0;
163
164     while (1) {
165         if (ff_check_interrupt(int_cb))
166             return AVERROR_EXIT;
167         ret = ff_network_wait_fd(fd, write);
168         if (ret != AVERROR(EAGAIN))
169             return ret;
170         if (timeout > 0) {
171             if (!wait_start)
172                 wait_start = av_gettime_relative();
173             else if (av_gettime_relative() - wait_start > timeout)
174                 return AVERROR(ETIMEDOUT);
175         }
176     }
177 }
178
179 void ff_network_close(void)
180 {
181 #if HAVE_WINSOCK2_H
182     WSACleanup();
183 #endif
184 }
185
186 #if HAVE_WINSOCK2_H
187 int ff_neterrno(void)
188 {
189     int err = WSAGetLastError();
190     switch (err) {
191     case WSAEWOULDBLOCK:
192         return AVERROR(EAGAIN);
193     case WSAEINTR:
194         return AVERROR(EINTR);
195     case WSAEPROTONOSUPPORT:
196         return AVERROR(EPROTONOSUPPORT);
197     case WSAETIMEDOUT:
198         return AVERROR(ETIMEDOUT);
199     case WSAECONNREFUSED:
200         return AVERROR(ECONNREFUSED);
201     case WSAEINPROGRESS:
202         return AVERROR(EINPROGRESS);
203     }
204     return -err;
205 }
206 #endif
207
208 int ff_is_multicast_address(struct sockaddr *addr)
209 {
210     if (addr->sa_family == AF_INET) {
211         return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
212     }
213 #if HAVE_STRUCT_SOCKADDR_IN6
214     if (addr->sa_family == AF_INET6) {
215         return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr);
216     }
217 #endif
218
219     return 0;
220 }
221
222 static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout,
223                              AVIOInterruptCB *cb)
224 {
225     int runs = timeout / POLLING_TIME;
226     int ret = 0;
227
228     do {
229         if (ff_check_interrupt(cb))
230             return AVERROR_EXIT;
231         ret = poll(p, nfds, POLLING_TIME);
232         if (ret != 0)
233             break;
234     } while (timeout <= 0 || runs-- > 0);
235
236     if (!ret)
237         return AVERROR(ETIMEDOUT);
238     if (ret < 0)
239         return AVERROR(errno);
240     return ret;
241 }
242
243 int ff_socket(int af, int type, int proto)
244 {
245     int fd;
246
247 #ifdef SOCK_CLOEXEC
248     fd = socket(af, type | SOCK_CLOEXEC, proto);
249     if (fd == -1 && errno == EINVAL)
250 #endif
251     {
252         fd = socket(af, type, proto);
253 #if HAVE_FCNTL
254         if (fd != -1) {
255             if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
256                 av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n");
257         }
258 #endif
259     }
260     return fd;
261 }
262
263 int ff_listen_bind(int fd, const struct sockaddr *addr,
264                    socklen_t addrlen, int timeout, URLContext *h)
265 {
266     int ret;
267     int reuse = 1;
268     struct pollfd lp = { fd, POLLIN, 0 };
269     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
270         av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n");
271     }
272     ret = bind(fd, addr, addrlen);
273     if (ret)
274         return ff_neterrno();
275
276     ret = listen(fd, 1);
277     if (ret)
278         return ff_neterrno();
279
280     ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback);
281     if (ret < 0)
282         return ret;
283
284     ret = accept(fd, NULL, NULL);
285     if (ret < 0)
286         return ff_neterrno();
287
288     closesocket(fd);
289
290     if (ff_socket_nonblock(ret, 1) < 0)
291         av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
292
293     return ret;
294 }
295
296 int ff_listen_connect(int fd, const struct sockaddr *addr,
297                       socklen_t addrlen, int timeout, URLContext *h,
298                       int will_try_next)
299 {
300     struct pollfd p = {fd, POLLOUT, 0};
301     int ret;
302     socklen_t optlen;
303
304     if (ff_socket_nonblock(fd, 1) < 0)
305         av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
306
307     while ((ret = connect(fd, addr, addrlen))) {
308         ret = ff_neterrno();
309         switch (ret) {
310         case AVERROR(EINTR):
311             if (ff_check_interrupt(&h->interrupt_callback))
312                 return AVERROR_EXIT;
313             continue;
314         case AVERROR(EINPROGRESS):
315         case AVERROR(EAGAIN):
316             ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback);
317             if (ret < 0)
318                 return ret;
319             optlen = sizeof(ret);
320             if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
321                 ret = AVUNERROR(ff_neterrno());
322             if (ret != 0) {
323                 char errbuf[100];
324                 ret = AVERROR(ret);
325                 av_strerror(ret, errbuf, sizeof(errbuf));
326                 if (will_try_next)
327                     av_log(h, AV_LOG_WARNING,
328                            "Connection to %s failed (%s), trying next address\n",
329                            h->filename, errbuf);
330                 else
331                     av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
332                            h->filename, errbuf);
333             }
334         default:
335             return ret;
336         }
337     }
338     return ret;
339 }
340
341 static int match_host_pattern(const char *pattern, const char *hostname)
342 {
343     int len_p, len_h;
344     if (!strcmp(pattern, "*"))
345         return 1;
346     // Skip a possible *. at the start of the pattern
347     if (pattern[0] == '*')
348         pattern++;
349     if (pattern[0] == '.')
350         pattern++;
351     len_p = strlen(pattern);
352     len_h = strlen(hostname);
353     if (len_p > len_h)
354         return 0;
355     // Simply check if the end of hostname is equal to 'pattern'
356     if (!strcmp(pattern, &hostname[len_h - len_p])) {
357         if (len_h == len_p)
358             return 1; // Exact match
359         if (hostname[len_h - len_p - 1] == '.')
360             return 1; // The matched substring is a domain and not just a substring of a domain
361     }
362     return 0;
363 }
364
365 int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
366 {
367     char *buf, *start;
368     int ret = 0;
369     if (!no_proxy)
370         return 0;
371     if (!hostname)
372         return 0;
373     buf = av_strdup(no_proxy);
374     if (!buf)
375         return 0;
376     start = buf;
377     while (start) {
378         char *sep, *next = NULL;
379         start += strspn(start, " ,");
380         sep = start + strcspn(start, " ,");
381         if (*sep) {
382             next = sep + 1;
383             *sep = '\0';
384         }
385         if (match_host_pattern(start, hostname)) {
386             ret = 1;
387             break;
388         }
389         start = next;
390     }
391     av_free(buf);
392     return ret;
393 }