Subversion Repositories Kolibri OS

Rev

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
}