Libav
network.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 The Libav Project
3  *
4  * This file is part of Libav.
5  *
6  * Libav 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  * Libav 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 Libav; 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/mem.h"
26 
27 #if HAVE_THREADS
28 #if HAVE_PTHREADS
29 #include <pthread.h>
30 #else
31 #include "compat/w32pthreads.h"
32 #endif
33 #endif
34 
35 #if CONFIG_OPENSSL
36 #include <openssl/ssl.h>
37 static int openssl_init;
38 #if HAVE_THREADS
39 #include <openssl/crypto.h>
40 #include "libavutil/avutil.h"
41 pthread_mutex_t *openssl_mutexes;
42 static void openssl_lock(int mode, int type, const char *file, int line)
43 {
44  if (mode & CRYPTO_LOCK)
45  pthread_mutex_lock(&openssl_mutexes[type]);
46  else
47  pthread_mutex_unlock(&openssl_mutexes[type]);
48 }
49 #if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000
50 static unsigned long openssl_thread_id(void)
51 {
52  return (intptr_t) pthread_self();
53 }
54 #endif
55 #endif
56 #endif
57 #if CONFIG_GNUTLS
58 #include <gnutls/gnutls.h>
59 #if HAVE_THREADS && GNUTLS_VERSION_NUMBER <= 0x020b00
60 #include <gcrypt.h>
61 #include <errno.h>
62 GCRY_THREAD_OPTION_PTHREAD_IMPL;
63 #endif
64 #endif
65 
66 void ff_tls_init(void)
67 {
69 #if CONFIG_OPENSSL
70  if (!openssl_init) {
71  SSL_library_init();
72  SSL_load_error_strings();
73 #if HAVE_THREADS
74  if (!CRYPTO_get_locking_callback()) {
75  int i;
76  openssl_mutexes = av_malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks());
77  for (i = 0; i < CRYPTO_num_locks(); i++)
78  pthread_mutex_init(&openssl_mutexes[i], NULL);
79  CRYPTO_set_locking_callback(openssl_lock);
80 #if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000
81  CRYPTO_set_id_callback(openssl_thread_id);
82 #endif
83  }
84 #endif
85  }
86  openssl_init++;
87 #endif
88 #if CONFIG_GNUTLS
89 #if HAVE_THREADS && GNUTLS_VERSION_NUMBER < 0x020b00
90  if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
91  gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
92 #endif
93  gnutls_global_init();
94 #endif
96 }
97 
98 void ff_tls_deinit(void)
99 {
101 #if CONFIG_OPENSSL
102  openssl_init--;
103  if (!openssl_init) {
104 #if HAVE_THREADS
105  if (CRYPTO_get_locking_callback() == openssl_lock) {
106  int i;
107  CRYPTO_set_locking_callback(NULL);
108  for (i = 0; i < CRYPTO_num_locks(); i++)
109  pthread_mutex_destroy(&openssl_mutexes[i]);
110  av_free(openssl_mutexes);
111  }
112 #endif
113  }
114 #endif
115 #if CONFIG_GNUTLS
116  gnutls_global_deinit();
117 #endif
119 }
120 
122 
124 {
125 #if HAVE_WINSOCK2_H
126  WSADATA wsaData;
127 #endif
128 
129  if (!ff_network_inited_globally)
130  av_log(NULL, AV_LOG_WARNING, "Using network protocols without global "
131  "network initialization. Please use "
132  "avformat_network_init(), this will "
133  "become mandatory later.\n");
134 #if HAVE_WINSOCK2_H
135  if (WSAStartup(MAKEWORD(1,1), &wsaData))
136  return 0;
137 #endif
138  return 1;
139 }
140 
141 int ff_network_wait_fd(int fd, int write)
142 {
143  int ev = write ? POLLOUT : POLLIN;
144  struct pollfd p = { .fd = fd, .events = ev, .revents = 0 };
145  int ret;
146  ret = poll(&p, 1, 100);
147  return ret < 0 ? ff_neterrno() : p.revents & (ev | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN);
148 }
149 
151 {
152 #if HAVE_WINSOCK2_H
153  WSACleanup();
154 #endif
155 }
156 
157 #if HAVE_WINSOCK2_H
158 int ff_neterrno(void)
159 {
160  int err = WSAGetLastError();
161  switch (err) {
162  case WSAEWOULDBLOCK:
163  return AVERROR(EAGAIN);
164  case WSAEINTR:
165  return AVERROR(EINTR);
166  case WSAEPROTONOSUPPORT:
167  return AVERROR(EPROTONOSUPPORT);
168  case WSAETIMEDOUT:
169  return AVERROR(ETIMEDOUT);
170  case WSAECONNREFUSED:
171  return AVERROR(ECONNREFUSED);
172  case WSAEINPROGRESS:
173  return AVERROR(EINPROGRESS);
174  }
175  return -err;
176 }
177 #endif
178 
179 int ff_is_multicast_address(struct sockaddr *addr)
180 {
181  if (addr->sa_family == AF_INET) {
182  return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
183  }
184 #if HAVE_STRUCT_SOCKADDR_IN6
185  if (addr->sa_family == AF_INET6) {
186  return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr);
187  }
188 #endif
189 
190  return 0;
191 }
192 
193 static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout,
194  AVIOInterruptCB *cb)
195 {
196  int runs = timeout / POLLING_TIME;
197  int ret = 0;
198 
199  do {
200  if (ff_check_interrupt(cb))
201  return AVERROR_EXIT;
202  ret = poll(p, nfds, POLLING_TIME);
203  if (ret != 0)
204  break;
205  } while (timeout < 0 || runs-- > 0);
206 
207  if (!ret)
208  return AVERROR(ETIMEDOUT);
209  if (ret < 0)
210  return AVERROR(errno);
211  return ret;
212 }
213 
214 int ff_socket(int af, int type, int proto)
215 {
216  int fd;
217 
218 #ifdef SOCK_CLOEXEC
219  fd = socket(af, type | SOCK_CLOEXEC, proto);
220  if (fd == -1 && errno == EINVAL)
221 #endif
222  {
223  fd = socket(af, type, proto);
224 #if HAVE_FCNTL
225  if (fd != -1)
226  fcntl(fd, F_SETFD, FD_CLOEXEC);
227 #endif
228  }
229  return fd;
230 }
231 
232 int ff_listen_bind(int fd, const struct sockaddr *addr,
233  socklen_t addrlen, int timeout, URLContext *h)
234 {
235  int ret;
236  int reuse = 1;
237  struct pollfd lp = { fd, POLLIN, 0 };
238  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
239  ret = bind(fd, addr, addrlen);
240  if (ret)
241  return ff_neterrno();
242 
243  ret = listen(fd, 1);
244  if (ret)
245  return ff_neterrno();
246 
247  ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback);
248  if (ret < 0)
249  return ret;
250 
251  ret = accept(fd, NULL, NULL);
252  if (ret < 0)
253  return ff_neterrno();
254 
255  closesocket(fd);
256 
257  ff_socket_nonblock(ret, 1);
258  return ret;
259 }
260 
261 int ff_listen_connect(int fd, const struct sockaddr *addr,
262  socklen_t addrlen, int timeout, URLContext *h,
263  int will_try_next)
264 {
265  struct pollfd p = {fd, POLLOUT, 0};
266  int ret;
267  socklen_t optlen;
268 
269  ff_socket_nonblock(fd, 1);
270 
271  while ((ret = connect(fd, addr, addrlen))) {
272  ret = ff_neterrno();
273  switch (ret) {
274  case AVERROR(EINTR):
276  return AVERROR_EXIT;
277  continue;
278  case AVERROR(EINPROGRESS):
279  case AVERROR(EAGAIN):
280  ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback);
281  if (ret < 0)
282  return ret;
283  optlen = sizeof(ret);
284  if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
285  ret = AVUNERROR(ff_neterrno());
286  if (ret != 0) {
287  char errbuf[100];
288  ret = AVERROR(ret);
289  av_strerror(ret, errbuf, sizeof(errbuf));
290  if (will_try_next)
292  "Connection to %s failed (%s), trying next address\n",
293  h->filename, errbuf);
294  else
295  av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
296  h->filename, errbuf);
297  }
298  default:
299  return ret;
300  }
301  }
302  return ret;
303 }
304 
305 static int match_host_pattern(const char *pattern, const char *hostname)
306 {
307  int len_p, len_h;
308  if (!strcmp(pattern, "*"))
309  return 1;
310  // Skip a possible *. at the start of the pattern
311  if (pattern[0] == '*')
312  pattern++;
313  if (pattern[0] == '.')
314  pattern++;
315  len_p = strlen(pattern);
316  len_h = strlen(hostname);
317  if (len_p > len_h)
318  return 0;
319  // Simply check if the end of hostname is equal to 'pattern'
320  if (!strcmp(pattern, &hostname[len_h - len_p])) {
321  if (len_h == len_p)
322  return 1; // Exact match
323  if (hostname[len_h - len_p - 1] == '.')
324  return 1; // The matched substring is a domain and not just a substring of a domain
325  }
326  return 0;
327 }
328 
329 int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
330 {
331  char *buf, *start;
332  int ret = 0;
333  if (!no_proxy)
334  return 0;
335  if (!hostname)
336  return 0;
337  buf = av_strdup(no_proxy);
338  if (!buf)
339  return 0;
340  start = buf;
341  while (start) {
342  char *sep, *next = NULL;
343  start += strspn(start, " ,");
344  sep = start + strcspn(start, " ,");
345  if (*sep) {
346  next = sep + 1;
347  *sep = '\0';
348  }
349  if (match_host_pattern(start, hostname)) {
350  ret = 1;
351  break;
352  }
353  start = next;
354  }
355  av_free(buf);
356  return ret;
357 }
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:62
int avpriv_unlock_avformat(void)
Definition: utils.c:2220
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:129
memory handling functions
static int match_host_pattern(const char *pattern, const char *hostname)
Definition: network.c:305
AVIOInterruptCB interrupt_callback
Definition: url.h:50
external API header
void ff_network_close(void)
Definition: network.c:150
static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout, AVIOInterruptCB *cb)
Definition: network.c:193
int ff_socket(int af, int type, int proto)
Definition: network.c:214
int ff_network_inited_globally
Definition: network.c:121
#define IN6_IS_ADDR_MULTICAST(a)
Definition: network.h:209
int ff_listen_bind(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h)
Bind to a file descriptor and poll for a connection.
Definition: network.c:232
int ff_network_init(void)
Definition: network.c:123
CRITICAL_SECTION pthread_mutex_t
Definition: w32pthreads.h:54
int ff_listen_connect(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next)
Connect to a file descriptor and poll for result.
Definition: network.c:261
Callback for checking whether to abort blocking functions.
Definition: avio.h:51
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:123
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:186
#define closesocket
Definition: avserver.c:24
#define AVERROR(e)
Definition: error.h:43
static int pthread_mutex_init(pthread_mutex_t *m, void *attr)
Definition: w32pthreads.h:104
static int pthread_mutex_unlock(pthread_mutex_t *m)
Definition: w32pthreads.h:119
Definition: graph2dot.c:49
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:148
int avpriv_lock_avformat(void)
Definition: utils.c:2211
int ff_is_multicast_address(struct sockaddr *addr)
Definition: network.c:179
static int pthread_mutex_destroy(pthread_mutex_t *m)
Definition: w32pthreads.h:109
#define ff_neterrno()
Definition: network.h:63
int ff_http_match_no_proxy(const char *no_proxy, const char *hostname)
Definition: network.c:329
int ff_socket_nonblock(int socket, int enable)
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:52
NULL
Definition: eval.c:55
static int pthread_mutex_lock(pthread_mutex_t *m)
Definition: w32pthreads.h:114
int ff_check_interrupt(AVIOInterruptCB *cb)
Check if the user has requested to interrup a blocking function associated with cb.
Definition: avio.c:381
char * av_strdup(const char *s)
Duplicate the string s.
Definition: mem.c:213
Definition: url.h:41
#define IN_MULTICAST(a)
Definition: network.h:206
#define POLLING_TIME
Definition: network.h:214
int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
Put a description of the AVERROR code errnum in errbuf.
Definition: error.c:23
common internal api header.
char * filename
specified URL
Definition: url.h:45
#define AVUNERROR(e)
Definition: error.h:44
void ff_tls_init(void)
Definition: network.c:66
w32threads to pthreads wrapper
void ff_tls_deinit(void)
Definition: network.c:98
int ff_network_wait_fd(int fd, int write)
Definition: network.c:141
unbuffered private I/O API