Don't report EINTR from select as an error, retry select instead
[libav.git] / libavformat / tcp.c
CommitLineData
171bbb03
FB
1/*
2 * TCP protocol
406792e7 3 * Copyright (c) 2002 Fabrice Bellard
171bbb03 4 *
b78e7197
DB
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
171bbb03
FB
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
b78e7197 10 * version 2.1 of the License, or (at your option) any later version.
171bbb03 11 *
b78e7197 12 * FFmpeg is distributed in the hope that it will be useful,
171bbb03
FB
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
b78e7197 18 * License along with FFmpeg; if not, write to the Free Software
5509bffa 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
171bbb03
FB
20 */
21#include "avformat.h"
22#include <unistd.h>
e4a9e3cc 23#include "internal.h"
42572ef5 24#include "network.h"
087b3272 25#include "os_support.h"
b250f9c6 26#if HAVE_SYS_SELECT_H
c75a0cce 27#include <sys/select.h>
6ad1c9c9 28#endif
09787fb8 29#include <sys/time.h>
171bbb03
FB
30
31typedef struct TCPContext {
32 int fd;
33} TCPContext;
34
171bbb03
FB
35/* return non zero if error */
36static int tcp_open(URLContext *h, const char *uri, int flags)
37{
fdcdd539 38 struct addrinfo hints, *ai, *cur_ai;
171bbb03 39 int port, fd = -1;
88730be6 40 TCPContext *s = NULL;
09787fb8
FB
41 fd_set wfds;
42 int fd_max, ret;
43 struct timeval tv;
44 socklen_t optlen;
f23a9759 45 char hostname[1024],proto[1024],path[1024];
fdcdd539 46 char portstr[10];
6ba5cbc6 47
c5c6e67c 48 ff_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
a3303add
RB
49 &port, path, sizeof(path), uri);
50 if (strcmp(proto,"tcp") || port <= 0 || port >= 65536)
8b9af28d 51 return AVERROR(EINVAL);
115329f1 52
fdcdd539 53 memset(&hints, 0, sizeof(hints));
88248b76 54 hints.ai_family = AF_UNSPEC;
fdcdd539
MS
55 hints.ai_socktype = SOCK_STREAM;
56 snprintf(portstr, sizeof(portstr), "%d", port);
57 if (getaddrinfo(hostname, portstr, &hints, &ai))
8b9af28d 58 return AVERROR(EIO);
171bbb03 59
fdcdd539
MS
60 cur_ai = ai;
61
62 restart:
63 fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
171bbb03 64 if (fd < 0)
fdcdd539 65 goto fail;
ba472aaf 66 ff_socket_nonblock(fd, 1);
115329f1 67
09787fb8 68 redo:
fdcdd539 69 ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
09787fb8 70 if (ret < 0) {
8da4034f 71 if (ff_neterrno() == FF_NETERROR(EINTR))
09787fb8 72 goto redo;
85060fe6
RP
73 if (ff_neterrno() != FF_NETERROR(EINPROGRESS) &&
74 ff_neterrno() != FF_NETERROR(EAGAIN))
09787fb8 75 goto fail;
171bbb03 76
09787fb8
FB
77 /* wait until we are connected or until abort */
78 for(;;) {
79 if (url_interrupt_cb()) {
8fa36ae0 80 ret = AVERROR(EINTR);
09787fb8
FB
81 goto fail1;
82 }
83 fd_max = fd;
84 FD_ZERO(&wfds);
85 FD_SET(fd, &wfds);
86 tv.tv_sec = 0;
87 tv.tv_usec = 100 * 1000;
88 ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
89 if (ret > 0 && FD_ISSET(fd, &wfds))
90 break;
91 }
115329f1 92
09787fb8
FB
93 /* test error */
94 optlen = sizeof(ret);
95 getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
96 if (ret != 0)
97 goto fail;
98 }
47f944a2 99 s = av_malloc(sizeof(TCPContext));
fdcdd539
MS
100 if (!s) {
101 freeaddrinfo(ai);
47f944a2 102 return AVERROR(ENOMEM);
fdcdd539 103 }
47f944a2
RB
104 h->priv_data = s;
105 h->is_streamed = 1;
171bbb03 106 s->fd = fd;
fdcdd539 107 freeaddrinfo(ai);
171bbb03
FB
108 return 0;
109
110 fail:
fdcdd539
MS
111 if (cur_ai->ai_next) {
112 /* Retry with the next sockaddr */
113 cur_ai = cur_ai->ai_next;
114 if (fd >= 0)
115 closesocket(fd);
116 goto restart;
117 }
6f3e0b21 118 ret = AVERROR(EIO);
09787fb8 119 fail1:
171bbb03 120 if (fd >= 0)
e9d511dc 121 closesocket(fd);
fdcdd539 122 freeaddrinfo(ai);
09787fb8 123 return ret;
171bbb03
FB
124}
125
0c1a9eda 126static int tcp_read(URLContext *h, uint8_t *buf, int size)
171bbb03
FB
127{
128 TCPContext *s = h->priv_data;
b51469a0 129 int len, fd_max, ret;
09787fb8
FB
130 fd_set rfds;
131 struct timeval tv;
171bbb03 132
9eef2b77 133 for (;;) {
09787fb8 134 if (url_interrupt_cb())
8fa36ae0 135 return AVERROR(EINTR);
09787fb8
FB
136 fd_max = s->fd;
137 FD_ZERO(&rfds);
138 FD_SET(s->fd, &rfds);
139 tv.tv_sec = 0;
140 tv.tv_usec = 100 * 1000;
b51469a0
LS
141 ret = select(fd_max + 1, &rfds, NULL, NULL, &tv);
142 if (ret > 0 && FD_ISSET(s->fd, &rfds)) {
b51469a0 143 len = recv(s->fd, buf, size, 0);
b51469a0 144 if (len < 0) {
8da4034f
AB
145 if (ff_neterrno() != FF_NETERROR(EINTR) &&
146 ff_neterrno() != FF_NETERROR(EAGAIN))
73c13268 147 return AVERROR(ff_neterrno());
b51469a0
LS
148 } else return len;
149 } else if (ret < 0) {
cae9a15c
MS
150 if (ff_neterrno() == FF_NETERROR(EINTR))
151 continue;
b51469a0
LS
152 return -1;
153 }
171bbb03 154 }
171bbb03
FB
155}
156
0c1a9eda 157static int tcp_write(URLContext *h, uint8_t *buf, int size)
171bbb03
FB
158{
159 TCPContext *s = h->priv_data;
b51469a0 160 int ret, size1, fd_max, len;
09787fb8
FB
161 fd_set wfds;
162 struct timeval tv;
171bbb03
FB
163
164 size1 = size;
165 while (size > 0) {
09787fb8 166 if (url_interrupt_cb())
8fa36ae0 167 return AVERROR(EINTR);
09787fb8
FB
168 fd_max = s->fd;
169 FD_ZERO(&wfds);
170 FD_SET(s->fd, &wfds);
171 tv.tv_sec = 0;
172 tv.tv_usec = 100 * 1000;
b51469a0
LS
173 ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
174 if (ret > 0 && FD_ISSET(s->fd, &wfds)) {
b51469a0 175 len = send(s->fd, buf, size, 0);
b51469a0 176 if (len < 0) {
8da4034f
AB
177 if (ff_neterrno() != FF_NETERROR(EINTR) &&
178 ff_neterrno() != FF_NETERROR(EAGAIN))
73c13268 179 return AVERROR(ff_neterrno());
b51469a0 180 continue;
6c8e0d4d 181 }
b51469a0
LS
182 size -= len;
183 buf += len;
184 } else if (ret < 0) {
cae9a15c
MS
185 if (ff_neterrno() == FF_NETERROR(EINTR))
186 continue;
b51469a0 187 return -1;
6c8e0d4d 188 }
171bbb03
FB
189 }
190 return size1 - size;
191}
192
193static int tcp_close(URLContext *h)
194{
195 TCPContext *s = h->priv_data;
9ddd71fc 196 closesocket(s->fd);
171bbb03
FB
197 av_free(s);
198 return 0;
199}
200
f0a80394
RB
201static int tcp_get_file_handle(URLContext *h)
202{
203 TCPContext *s = h->priv_data;
204 return s->fd;
205}
206
171bbb03
FB
207URLProtocol tcp_protocol = {
208 "tcp",
209 tcp_open,
210 tcp_read,
211 tcp_write,
212 NULL, /* seek */
213 tcp_close,
f0a80394 214 .url_get_file_handle = tcp_get_file_handle,
171bbb03 215};