Statistics
| Branch: | Revision:

ffmpeg / libavformat / tcp.c @ 438fcb75

History | View | Annotate | Download (5.48 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 <ctype.h>
22
#include <sys/types.h>
23
#include <sys/socket.h>
24
#include <netinet/in.h>
25
#if defined(__APPLE__) || defined(__BEOS__)
26
typedef int socklen_t;
27
#endif
28
#ifndef __BEOS__
29
# include <arpa/inet.h>
30
#else
31
# include "barpainet.h"
32
#endif
33
#include <netdb.h>
34
#include <sys/time.h>
35
#include <fcntl.h>
36

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

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

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

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

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

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

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

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

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

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

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

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

    
228
URLProtocol tcp_protocol = {
229
    "tcp",
230
    tcp_open,
231
    tcp_read,
232
    tcp_write,
233
    NULL, /* seek */
234
    tcp_close,
235
};