tcp: Pass NULL as hostname to getaddrinfo if the string is empty
[libav.git] / libavformat / tcp.c
CommitLineData
171bbb03
FB
1/*
2 * TCP protocol
406792e7 3 * Copyright (c) 2002 Fabrice Bellard
171bbb03 4 *
2912e87a 5 * This file is part of Libav.
b78e7197 6 *
2912e87a 7 * Libav 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 *
2912e87a 12 * Libav 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
2912e87a 18 * License along with Libav; 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"
3d42d493 22#include "libavutil/parseutils.h"
e4a9e3cc 23#include "internal.h"
42572ef5 24#include "network.h"
087b3272 25#include "os_support.h"
5cec8971 26#include "url.h"
a8475bbd
LB
27#if HAVE_POLL_H
28#include <poll.h>
6ad1c9c9 29#endif
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{
a92be9b8 38 struct addrinfo hints = { 0 }, *ai, *cur_ai;
171bbb03 39 int port, fd = -1;
7e580505 40 TCPContext *s = h->priv_data;
3d42d493
LB
41 int listen_socket = 0;
42 const char *p;
43 char buf[256];
a8475bbd 44 int ret;
09787fb8 45 socklen_t optlen;
ebb6b27a 46 int timeout = 100;
f23a9759 47 char hostname[1024],proto[1024],path[1024];
fdcdd539 48 char portstr[10];
6ba5cbc6 49
f3bfe388 50 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
a3303add
RB
51 &port, path, sizeof(path), uri);
52 if (strcmp(proto,"tcp") || port <= 0 || port >= 65536)
8b9af28d 53 return AVERROR(EINVAL);
115329f1 54
3d42d493
LB
55 p = strchr(uri, '?');
56 if (p) {
57 if (av_find_info_tag(buf, sizeof(buf), "listen", p))
58 listen_socket = 1;
ebb6b27a
LB
59 if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
60 timeout = strtol(buf, NULL, 10);
61 }
3d42d493 62 }
88248b76 63 hints.ai_family = AF_UNSPEC;
fdcdd539
MS
64 hints.ai_socktype = SOCK_STREAM;
65 snprintf(portstr, sizeof(portstr), "%d", port);
58f3e09e
JO
66 if (listen_socket)
67 hints.ai_flags |= AI_PASSIVE;
ef882e46
JO
68 if (!hostname[0])
69 ret = getaddrinfo(NULL, portstr, &hints, &ai);
70 else
71 ret = getaddrinfo(hostname, portstr, &hints, &ai);
63638a3c 72 if (ret) {
c60112f2 73 av_log(h, AV_LOG_ERROR,
63638a3c
RB
74 "Failed to resolve hostname %s: %s\n",
75 hostname, gai_strerror(ret));
8b9af28d 76 return AVERROR(EIO);
63638a3c 77 }
171bbb03 78
fdcdd539
MS
79 cur_ai = ai;
80
81 restart:
ebb6b27a 82 ret = AVERROR(EIO);
fdcdd539 83 fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
171bbb03 84 if (fd < 0)
fdcdd539 85 goto fail;
115329f1 86
3d42d493
LB
87 if (listen_socket) {
88 int fd1;
b7c3772b
MS
89 int reuse = 1;
90 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
3d42d493 91 ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
641f4a88
MS
92 if (ret) {
93 ret = ff_neterrno();
94 goto fail1;
95 }
a7cc78cb
JO
96 ret = listen(fd, 1);
97 if (ret) {
98 ret = ff_neterrno();
99 goto fail1;
100 }
3d42d493 101 fd1 = accept(fd, NULL, NULL);
641f4a88
MS
102 if (fd1 < 0) {
103 ret = ff_neterrno();
104 goto fail1;
105 }
3d42d493
LB
106 closesocket(fd);
107 fd = fd1;
ebb6b27a 108 ff_socket_nonblock(fd, 1);
3d42d493 109 } else {
09787fb8 110 redo:
ebb6b27a 111 ff_socket_nonblock(fd, 1);
3d42d493
LB
112 ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
113 }
114
09787fb8 115 if (ret < 0) {
a8475bbd 116 struct pollfd p = {fd, POLLOUT, 0};
ebb6b27a
LB
117 ret = ff_neterrno();
118 if (ret == AVERROR(EINTR)) {
9957cdbf 119 if (ff_check_interrupt(&h->interrupt_callback)) {
c76374c6 120 ret = AVERROR_EXIT;
1aa58c64 121 goto fail1;
c76374c6 122 }
09787fb8 123 goto redo;
1aa58c64 124 }
ebb6b27a
LB
125 if (ret != AVERROR(EINPROGRESS) &&
126 ret != AVERROR(EAGAIN))
09787fb8 127 goto fail;
171bbb03 128
09787fb8 129 /* wait until we are connected or until abort */
ebb6b27a 130 while(timeout--) {
9957cdbf 131 if (ff_check_interrupt(&h->interrupt_callback)) {
c76374c6 132 ret = AVERROR_EXIT;
09787fb8
FB
133 goto fail1;
134 }
a8475bbd
LB
135 ret = poll(&p, 1, 100);
136 if (ret > 0)
09787fb8
FB
137 break;
138 }
ebb6b27a
LB
139 if (ret <= 0) {
140 ret = AVERROR(ETIMEDOUT);
141 goto fail;
142 }
09787fb8
FB
143 /* test error */
144 optlen = sizeof(ret);
bb6c1abb
MS
145 if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
146 ret = AVUNERROR(ff_neterrno());
63638a3c 147 if (ret != 0) {
a840cdda
MS
148 char errbuf[100];
149 ret = AVERROR(ret);
150 av_strerror(ret, errbuf, sizeof(errbuf));
c60112f2 151 av_log(h, AV_LOG_ERROR,
63638a3c 152 "TCP connection to %s:%d failed: %s\n",
a840cdda 153 hostname, port, errbuf);
09787fb8 154 goto fail;
63638a3c 155 }
09787fb8 156 }
47f944a2 157 h->is_streamed = 1;
171bbb03 158 s->fd = fd;
fdcdd539 159 freeaddrinfo(ai);
171bbb03
FB
160 return 0;
161
162 fail:
fdcdd539
MS
163 if (cur_ai->ai_next) {
164 /* Retry with the next sockaddr */
165 cur_ai = cur_ai->ai_next;
166 if (fd >= 0)
167 closesocket(fd);
168 goto restart;
169 }
09787fb8 170 fail1:
171bbb03 171 if (fd >= 0)
e9d511dc 172 closesocket(fd);
fdcdd539 173 freeaddrinfo(ai);
09787fb8 174 return ret;
171bbb03
FB
175}
176
0c1a9eda 177static int tcp_read(URLContext *h, uint8_t *buf, int size)
171bbb03
FB
178{
179 TCPContext *s = h->priv_data;
ad3cffb6 180 int ret;
171bbb03 181
f87b1b37 182 if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
ebba2b3e 183 ret = ff_network_wait_fd(s->fd, 0);
ad3cffb6 184 if (ret < 0)
51b317d2 185 return ret;
171bbb03 186 }
ad3cffb6
NG
187 ret = recv(s->fd, buf, size, 0);
188 return ret < 0 ? ff_neterrno() : ret;
171bbb03
FB
189}
190
27241cbf 191static int tcp_write(URLContext *h, const uint8_t *buf, int size)
171bbb03
FB
192{
193 TCPContext *s = h->priv_data;
ad3cffb6 194 int ret;
171bbb03 195
f87b1b37 196 if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
ebba2b3e 197 ret = ff_network_wait_fd(s->fd, 1);
ad3cffb6 198 if (ret < 0)
51b317d2 199 return ret;
171bbb03 200 }
ad3cffb6
NG
201 ret = send(s->fd, buf, size, 0);
202 return ret < 0 ? ff_neterrno() : ret;
171bbb03
FB
203}
204
4a9ca935
SP
205static int tcp_shutdown(URLContext *h, int flags)
206{
207 TCPContext *s = h->priv_data;
208 int how;
209
210 if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
211 how = SHUT_RDWR;
212 } else if (flags & AVIO_FLAG_WRITE) {
213 how = SHUT_WR;
214 } else {
215 how = SHUT_RD;
216 }
217
218 return shutdown(s->fd, how);
219}
220
171bbb03
FB
221static int tcp_close(URLContext *h)
222{
223 TCPContext *s = h->priv_data;
9ddd71fc 224 closesocket(s->fd);
171bbb03
FB
225 return 0;
226}
227
f0a80394
RB
228static int tcp_get_file_handle(URLContext *h)
229{
230 TCPContext *s = h->priv_data;
231 return s->fd;
232}
233
c6610a21 234URLProtocol ff_tcp_protocol = {
f35ff97f
AK
235 .name = "tcp",
236 .url_open = tcp_open,
237 .url_read = tcp_read,
238 .url_write = tcp_write,
239 .url_close = tcp_close,
f0a80394 240 .url_get_file_handle = tcp_get_file_handle,
4a9ca935 241 .url_shutdown = tcp_shutdown,
7e580505 242 .priv_data_size = sizeof(TCPContext),
32b83aee 243 .flags = URL_PROTOCOL_FLAG_NETWORK,
171bbb03 244};