Statistics
| Branch: | Revision:

ffmpeg / libavformat / tcp.c @ a33cc951

History | View | Annotate | Download (5.24 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)) {
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 AVERROR(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(AF_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 = AVERROR(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 AVERROR(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
                    return AVERROR(errno);
145
            } else return len;
146
        } else if (ret < 0) {
147
            return -1;
148
        }
149
    }
150
}
151

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

    
159
    size1 = size;
160
    while (size > 0) {
161
        if (url_interrupt_cb())
162
            return AVERROR(EINTR);
163
        fd_max = s->fd;
164
        FD_ZERO(&wfds);
165
        FD_SET(s->fd, &wfds);
166
        tv.tv_sec = 0;
167
        tv.tv_usec = 100 * 1000;
168
        ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
169
        if (ret > 0 && FD_ISSET(s->fd, &wfds)) {
170
            len = send(s->fd, buf, size, 0);
171
            if (len < 0) {
172
                if (errno != EINTR && errno != EAGAIN)
173
                    return AVERROR(errno);
174
                continue;
175
            }
176
            size -= len;
177
            buf += len;
178
        } else if (ret < 0) {
179
            return -1;
180
        }
181
    }
182
    return size1 - size;
183
}
184

    
185
static int tcp_close(URLContext *h)
186
{
187
    TCPContext *s = h->priv_data;
188
    closesocket(s->fd);
189
    av_free(s);
190
    return 0;
191
}
192

    
193
URLProtocol tcp_protocol = {
194
    "tcp",
195
    tcp_open,
196
    tcp_read,
197
    tcp_write,
198
    NULL, /* seek */
199
    tcp_close,
200
};