Statistics
| Branch: | Revision:

ffmpeg / libavformat / tcp.c @ 0d9f8633

History | View | Annotate | Download (5.34 KB)

1
/*
2
 * TCP protocol
3
 * Copyright (c) 2002 Fabrice Bellard.
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
#include "avformat.h"
22
#include <unistd.h>
23
#include "network.h"
24
#include <sys/time.h>
25
#include <fcntl.h>
26

    
27
typedef struct TCPContext {
28
    int fd;
29
} TCPContext;
30

    
31
/* resolve host with also IP address parsing */
32
int resolve_host(struct in_addr *sin_addr, const char *hostname)
33
{
34
    struct hostent *hp;
35

    
36
    if ((inet_aton(hostname, sin_addr)) == 0) {
37
        hp = gethostbyname(hostname);
38
        if (!hp)
39
            return -1;
40
        memcpy (sin_addr, hp->h_addr, sizeof(struct in_addr));
41
    }
42
    return 0;
43
}
44

    
45
/* return non zero if error */
46
static int tcp_open(URLContext *h, const char *uri, int flags)
47
{
48
    struct sockaddr_in dest_addr;
49
    char hostname[1024], *q;
50
    int port, fd = -1;
51
    TCPContext *s = NULL;
52
    fd_set wfds;
53
    int fd_max, ret;
54
    struct timeval tv;
55
    socklen_t optlen;
56
    char proto[1024],path[1024],tmp[1024];  // PETR: protocol and path strings
57

    
58
    url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
59
      &port, path, sizeof(path), uri);  // PETR: use url_split
60
    if (strcmp(proto,"tcp")) goto fail; // PETR: check protocol
61
    if ((q = strchr(hostname,'@'))) { strcpy(tmp,q+1); strcpy(hostname,tmp); } // PETR: take only the part after '@' for tcp protocol
62

    
63
    s = av_malloc(sizeof(TCPContext));
64
    if (!s)
65
        return -ENOMEM;
66
    h->priv_data = s;
67

    
68
    if (port <= 0 || port >= 65536)
69
        goto fail;
70

    
71
    dest_addr.sin_family = AF_INET;
72
    dest_addr.sin_port = htons(port);
73
    if (resolve_host(&dest_addr.sin_addr, hostname) < 0)
74
        goto fail;
75

    
76
    fd = socket(PF_INET, SOCK_STREAM, 0);
77
    if (fd < 0)
78
        goto fail;
79
    fcntl(fd, F_SETFL, O_NONBLOCK);
80

    
81
 redo:
82
    ret = connect(fd, (struct sockaddr *)&dest_addr,
83
                  sizeof(dest_addr));
84
    if (ret < 0) {
85
        if (errno == EINTR)
86
            goto redo;
87
        if (errno != EINPROGRESS)
88
            goto fail;
89

    
90
        /* wait until we are connected or until abort */
91
        for(;;) {
92
            if (url_interrupt_cb()) {
93
                ret = -EINTR;
94
                goto fail1;
95
            }
96
            fd_max = fd;
97
            FD_ZERO(&wfds);
98
            FD_SET(fd, &wfds);
99
            tv.tv_sec = 0;
100
            tv.tv_usec = 100 * 1000;
101
            ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
102
            if (ret > 0 && FD_ISSET(fd, &wfds))
103
                break;
104
        }
105

    
106
        /* test error */
107
        optlen = sizeof(ret);
108
        getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
109
        if (ret != 0)
110
            goto fail;
111
    }
112
    s->fd = fd;
113
    return 0;
114

    
115
 fail:
116
    ret = AVERROR_IO;
117
 fail1:
118
    if (fd >= 0)
119
        closesocket(fd);
120
    av_free(s);
121
    return ret;
122
}
123

    
124
static int tcp_read(URLContext *h, uint8_t *buf, int size)
125
{
126
    TCPContext *s = h->priv_data;
127
    int len, fd_max, ret;
128
    fd_set rfds;
129
    struct timeval tv;
130

    
131
    for (;;) {
132
        if (url_interrupt_cb())
133
            return -EINTR;
134
        fd_max = s->fd;
135
        FD_ZERO(&rfds);
136
        FD_SET(s->fd, &rfds);
137
        tv.tv_sec = 0;
138
        tv.tv_usec = 100 * 1000;
139
        ret = select(fd_max + 1, &rfds, NULL, NULL, &tv);
140
        if (ret > 0 && FD_ISSET(s->fd, &rfds)) {
141
            len = recv(s->fd, buf, size, 0);
142
            if (len < 0) {
143
                if (errno != EINTR && errno != EAGAIN)
144
#ifdef __BEOS__
145
                    return errno;
146
#else
147
                    return -errno;
148
#endif
149
            } else return len;
150
        } else if (ret < 0) {
151
            return -1;
152
        }
153
    }
154
}
155

    
156
static int tcp_write(URLContext *h, uint8_t *buf, int size)
157
{
158
    TCPContext *s = h->priv_data;
159
    int ret, size1, fd_max, len;
160
    fd_set wfds;
161
    struct timeval tv;
162

    
163
    size1 = size;
164
    while (size > 0) {
165
        if (url_interrupt_cb())
166
            return -EINTR;
167
        fd_max = s->fd;
168
        FD_ZERO(&wfds);
169
        FD_SET(s->fd, &wfds);
170
        tv.tv_sec = 0;
171
        tv.tv_usec = 100 * 1000;
172
        ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
173
        if (ret > 0 && FD_ISSET(s->fd, &wfds)) {
174
            len = send(s->fd, buf, size, 0);
175
            if (len < 0) {
176
                if (errno != EINTR && errno != EAGAIN) {
177
#ifdef __BEOS__
178
                    return errno;
179
#else
180
                    return -errno;
181
#endif
182
                }
183
                continue;
184
            }
185
            size -= len;
186
            buf += len;
187
        } else if (ret < 0) {
188
            return -1;
189
        }
190
    }
191
    return size1 - size;
192
}
193

    
194
static int tcp_close(URLContext *h)
195
{
196
    TCPContext *s = h->priv_data;
197
    closesocket(s->fd);
198
    av_free(s);
199
    return 0;
200
}
201

    
202
URLProtocol tcp_protocol = {
203
    "tcp",
204
    tcp_open,
205
    tcp_read,
206
    tcp_write,
207
    NULL, /* seek */
208
    tcp_close,
209
};