Statistics
| Branch: | Revision:

ffmpeg / libavformat / tcp.c @ 20f269dc

History | View | Annotate | Download (5.54 KB)

1
/*
2
 * TCP protocol
3
 * Copyright (c) 2002 Fabrice Bellard.
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19
#include "avformat.h"
20
#include <unistd.h>
21
#include <sys/types.h>
22
#include <sys/socket.h>
23
#include <netinet/in.h>
24
#if defined(__APPLE__) || defined(__BEOS__)
25
typedef int socklen_t;
26
#endif
27
#ifndef __BEOS__
28
# include <arpa/inet.h>
29
#else
30
# include "barpainet.h"
31
#endif
32
#include <netdb.h>
33
#include <sys/time.h>
34
#include <fcntl.h>
35

    
36
typedef struct TCPContext {
37
    int fd;
38
} TCPContext;
39

    
40
/* resolve host with also IP address parsing */
41
int resolve_host(struct in_addr *sin_addr, const char *hostname)
42
{
43
    struct hostent *hp;
44

    
45
    if ((inet_aton(hostname, sin_addr)) == 0) {
46
        hp = gethostbyname(hostname);
47
        if (!hp)
48
            return -1;
49
        memcpy (sin_addr, hp->h_addr, sizeof(struct in_addr));
50
    }
51
    return 0;
52
}
53

    
54
/* return non zero if error */
55
static int tcp_open(URLContext *h, const char *uri, int flags)
56
{
57
    struct sockaddr_in dest_addr;
58
    char hostname[1024], *q;
59
    int port, fd = -1;
60
    TCPContext *s;
61
    const char *p;
62
    fd_set wfds;
63
    int fd_max, ret;
64
    struct timeval tv;
65
    socklen_t optlen;
66
    
67
    s = av_malloc(sizeof(TCPContext));
68
    if (!s)
69
        return -ENOMEM;
70
    h->priv_data = s;
71
    p = uri;
72
    if (!strstart(p, "tcp://", &p))
73
        goto fail;
74
    q = hostname;
75
    while (*p != ':' && *p != '/' && *p != '\0') {
76
        if ((q - hostname) < sizeof(hostname) - 1)
77
            *q++ = *p;
78
        p++;
79
    }
80
    *q = '\0';
81
    if (*p != ':')
82
        goto fail;
83
    p++;
84
    port = strtoul(p, (char **)&p, 10);
85
    if (port <= 0 || port >= 65536)
86
        goto fail;
87
    
88
    dest_addr.sin_family = AF_INET;
89
    dest_addr.sin_port = htons(port);
90
    if (resolve_host(&dest_addr.sin_addr, hostname) < 0)
91
        goto fail;
92

    
93
    fd = socket(PF_INET, SOCK_STREAM, 0);
94
    if (fd < 0)
95
        goto fail;
96
    fcntl(fd, F_SETFL, O_NONBLOCK);
97
    
98
 redo:
99
    ret = connect(fd, (struct sockaddr *)&dest_addr, 
100
                  sizeof(dest_addr));
101
    if (ret < 0) {
102
        if (errno == EINTR)
103
            goto redo;
104
        if (errno != EINPROGRESS)
105
            goto fail;
106

    
107
        /* wait until we are connected or until abort */
108
        for(;;) {
109
            if (url_interrupt_cb()) {
110
                ret = -EINTR;
111
                goto fail1;
112
            }
113
            fd_max = fd;
114
            FD_ZERO(&wfds);
115
            FD_SET(fd, &wfds);
116
            tv.tv_sec = 0;
117
            tv.tv_usec = 100 * 1000;
118
            ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
119
            if (ret > 0 && FD_ISSET(fd, &wfds))
120
                break;
121
        }
122
        
123
        /* test error */
124
        optlen = sizeof(ret);
125
        getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
126
        if (ret != 0)
127
            goto fail;
128
    }
129
    s->fd = fd;
130
    return 0;
131

    
132
 fail:
133
    ret = -EIO;
134
 fail1:
135
    if (fd >= 0)
136
        close(fd);
137
    av_free(s);
138
    return ret;
139
}
140

    
141
static int tcp_read(URLContext *h, uint8_t *buf, int size)
142
{
143
    TCPContext *s = h->priv_data;
144
    int size1, len, fd_max;
145
    fd_set rfds;
146
    struct timeval tv;
147

    
148
    size1 = size;
149
    while (size > 0) {
150
        if (url_interrupt_cb())
151
            return -EINTR;
152
        fd_max = s->fd;
153
        FD_ZERO(&rfds);
154
        FD_SET(s->fd, &rfds);
155
        tv.tv_sec = 0;
156
        tv.tv_usec = 100 * 1000;
157
        select(fd_max + 1, &rfds, NULL, NULL, &tv);
158
#ifdef __BEOS__
159
        len = recv(s->fd, buf, size, 0);
160
#else
161
        len = read(s->fd, buf, size);
162
#endif
163
        if (len < 0) {
164
            if (errno != EINTR && errno != EAGAIN)
165
#ifdef __BEOS__
166
                return errno;
167
#else
168
                return -errno;
169
#endif
170
            else
171
                continue;
172
        } else if (len == 0) {
173
            break;
174
        }
175
        size -= len;
176
        buf += len;
177
    }
178
    return size1 - size;
179
}
180

    
181
static int tcp_write(URLContext *h, uint8_t *buf, int size)
182
{
183
    TCPContext *s = h->priv_data;
184
    int ret, size1, fd_max;
185
    fd_set wfds;
186
    struct timeval tv;
187

    
188
    size1 = size;
189
    while (size > 0) {
190
        if (url_interrupt_cb())
191
            return -EINTR;
192
        fd_max = s->fd;
193
        FD_ZERO(&wfds);
194
        FD_SET(s->fd, &wfds);
195
        tv.tv_sec = 0;
196
        tv.tv_usec = 100 * 1000;
197
        select(fd_max + 1, NULL, &wfds, NULL, &tv);
198
#ifdef __BEOS__
199
        ret = send(s->fd, buf, size, 0);
200
#else
201
        ret = write(s->fd, buf, size);
202
#endif
203
        if (ret < 0) {
204
            if (errno != EINTR && errno != EAGAIN) {
205
#ifdef __BEOS__
206
                return errno;
207
#else
208
                return -errno;
209
#endif
210
            }
211
            continue;
212
        }
213
        size -= ret;
214
        buf += ret;
215
    }
216
    return size1 - size;
217
}
218

    
219
static int tcp_close(URLContext *h)
220
{
221
    TCPContext *s = h->priv_data;
222
#ifdef CONFIG_BEOS_NETSERVER
223
    closesocket(s->fd);
224
#else
225
    close(s->fd);
226
#endif
227
    av_free(s);
228
    return 0;
229
}
230

    
231
URLProtocol tcp_protocol = {
232
    "tcp",
233
    tcp_open,
234
    tcp_read,
235
    tcp_write,
236
    NULL, /* seek */
237
    tcp_close,
238
};