tcp.c
Go to the documentation of this file.
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 "libavutil/parseutils.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/time.h"
25 #include "internal.h"
26 #include "network.h"
27 #include "os_support.h"
28 #include "url.h"
29 #if HAVE_POLL_H
30 #include <poll.h>
31 #endif
32 
33 typedef struct TCPContext {
34  const AVClass *class;
35  int fd;
36  int listen;
39 } TCPContext;
40 
41 #define OFFSET(x) offsetof(TCPContext, x)
42 #define D AV_OPT_FLAG_DECODING_PARAM
43 #define E AV_OPT_FLAG_ENCODING_PARAM
44 static const AVOption options[] = {
45 {"listen", "listen on port instead of connecting", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E },
46 {"timeout", "timeout of socket i/o operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E },
47 {"listen_timeout", "connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
48 {NULL}
49 };
50 
51 static const AVClass tcp_context_class = {
52  .class_name = "tcp",
53  .item_name = av_default_item_name,
54  .option = options,
55  .version = LIBAVUTIL_VERSION_INT,
56 };
57 
58 /* return non zero if error */
59 static int tcp_open(URLContext *h, const char *uri, int flags)
60 {
61  struct addrinfo hints = { 0 }, *ai, *cur_ai;
62  int port, fd = -1;
63  TCPContext *s = h->priv_data;
64  const char *p;
65  char buf[256];
66  int ret;
67  socklen_t optlen;
68  char hostname[1024],proto[1024],path[1024];
69  char portstr[10];
70  h->rw_timeout = 5000000;
71 
72  av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
73  &port, path, sizeof(path), uri);
74  if (strcmp(proto, "tcp"))
75  return AVERROR(EINVAL);
76  if (port <= 0 || port >= 65536) {
77  av_log(h, AV_LOG_ERROR, "Port missing in uri\n");
78  return AVERROR(EINVAL);
79  }
80  p = strchr(uri, '?');
81  if (p) {
82  if (av_find_info_tag(buf, sizeof(buf), "listen", p))
83  s->listen = 1;
84  if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
85  s->rw_timeout = strtol(buf, NULL, 10);
86  }
87  if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) {
88  s->listen_timeout = strtol(buf, NULL, 10);
89  }
90  }
91  h->rw_timeout = s->rw_timeout;
92  hints.ai_family = AF_UNSPEC;
93  hints.ai_socktype = SOCK_STREAM;
94  snprintf(portstr, sizeof(portstr), "%d", port);
95  if (s->listen)
96  hints.ai_flags |= AI_PASSIVE;
97  if (!hostname[0])
98  ret = getaddrinfo(NULL, portstr, &hints, &ai);
99  else
100  ret = getaddrinfo(hostname, portstr, &hints, &ai);
101  if (ret) {
102  av_log(h, AV_LOG_ERROR,
103  "Failed to resolve hostname %s: %s\n",
104  hostname, gai_strerror(ret));
105  return AVERROR(EIO);
106  }
107 
108  cur_ai = ai;
109 
110  restart:
111  ret = AVERROR(EIO);
112  fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
113  if (fd < 0)
114  goto fail;
115 
116  if (s->listen) {
117  int fd1;
118  int reuse = 1;
119  struct pollfd lp = { fd, POLLIN, 0 };
120  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
121  ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
122  if (ret) {
123  ret = ff_neterrno();
124  goto fail1;
125  }
126  ret = listen(fd, 1);
127  if (ret) {
128  ret = ff_neterrno();
129  goto fail1;
130  }
131  ret = poll(&lp, 1, s->listen_timeout >= 0 ? s->listen_timeout : -1);
132  if (ret <= 0) {
133  ret = AVERROR(ETIMEDOUT);
134  goto fail1;
135  }
136  fd1 = accept(fd, NULL, NULL);
137  if (fd1 < 0) {
138  ret = ff_neterrno();
139  goto fail1;
140  }
141  closesocket(fd);
142  fd = fd1;
143  ff_socket_nonblock(fd, 1);
144  } else {
145  redo:
146  ff_socket_nonblock(fd, 1);
147  ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
148  }
149 
150  if (ret < 0) {
151  struct pollfd p = {fd, POLLOUT, 0};
152  int64_t wait_started;
153  ret = ff_neterrno();
154  if (ret == AVERROR(EINTR)) {
156  ret = AVERROR_EXIT;
157  goto fail1;
158  }
159  goto redo;
160  }
161  if (ret != AVERROR(EINPROGRESS) &&
162  ret != AVERROR(EAGAIN))
163  goto fail;
164 
165  /* wait until we are connected or until abort */
166  wait_started = av_gettime();
167  do {
169  ret = AVERROR_EXIT;
170  goto fail1;
171  }
172  ret = poll(&p, 1, 100);
173  if (ret > 0)
174  break;
175  } while (!h->rw_timeout || (av_gettime() - wait_started < h->rw_timeout));
176  if (ret <= 0) {
177  ret = AVERROR(ETIMEDOUT);
178  goto fail;
179  }
180  /* test error */
181  optlen = sizeof(ret);
182  if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen))
183  ret = AVUNERROR(ff_neterrno());
184  if (ret != 0) {
185  char errbuf[100];
186  ret = AVERROR(ret);
187  av_strerror(ret, errbuf, sizeof(errbuf));
188  av_log(h, AV_LOG_ERROR,
189  "TCP connection to %s:%d failed: %s\n",
190  hostname, port, errbuf);
191  goto fail;
192  }
193  }
194  h->is_streamed = 1;
195  s->fd = fd;
196  freeaddrinfo(ai);
197  return 0;
198 
199  fail:
200  if (cur_ai->ai_next) {
201  /* Retry with the next sockaddr */
202  cur_ai = cur_ai->ai_next;
203  if (fd >= 0)
204  closesocket(fd);
205  goto restart;
206  }
207  fail1:
208  if (fd >= 0)
209  closesocket(fd);
210  freeaddrinfo(ai);
211  return ret;
212 }
213 
214 static int tcp_read(URLContext *h, uint8_t *buf, int size)
215 {
216  TCPContext *s = h->priv_data;
217  int ret;
218 
219  if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
221  if (ret)
222  return ret;
223  }
224  ret = recv(s->fd, buf, size, 0);
225  return ret < 0 ? ff_neterrno() : ret;
226 }
227 
228 static int tcp_write(URLContext *h, const uint8_t *buf, int size)
229 {
230  TCPContext *s = h->priv_data;
231  int ret;
232 
233  if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
235  if (ret)
236  return ret;
237  }
238  ret = send(s->fd, buf, size, 0);
239  return ret < 0 ? ff_neterrno() : ret;
240 }
241 
242 static int tcp_shutdown(URLContext *h, int flags)
243 {
244  TCPContext *s = h->priv_data;
245  int how;
246 
247  if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
248  how = SHUT_RDWR;
249  } else if (flags & AVIO_FLAG_WRITE) {
250  how = SHUT_WR;
251  } else {
252  how = SHUT_RD;
253  }
254 
255  return shutdown(s->fd, how);
256 }
257 
258 static int tcp_close(URLContext *h)
259 {
260  TCPContext *s = h->priv_data;
261  closesocket(s->fd);
262  return 0;
263 }
264 
266 {
267  TCPContext *s = h->priv_data;
268  return s->fd;
269 }
270 
272  .name = "tcp",
273  .url_open = tcp_open,
274  .url_read = tcp_read,
275  .url_write = tcp_write,
276  .url_close = tcp_close,
277  .url_get_file_handle = tcp_get_file_handle,
278  .url_shutdown = tcp_shutdown,
279  .priv_data_size = sizeof(TCPContext),
280  .priv_data_class = &tcp_context_class,
282 };
void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url)
Split a URL string into components.
const char * s
Definition: avisynth_c.h:668
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:35
static int tcp_open(URLContext *h, const char *uri, int flags)
Definition: tcp.c:59
AVOption.
Definition: opt.h:251
av_default_item_name
int is_streamed
true if streamed (no seek possible), default = false
Definition: url.h:48
AVIOInterruptCB interrupt_callback
Definition: url.h:50
int rw_timeout
Definition: tcp.c:37
#define AVIO_FLAG_READ
read-only
Definition: avio.h:332
int64_t rw_timeout
maximum time to wait for (network) read/write operation completion, in mcs
Definition: url.h:51
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:333
#define AI_PASSIVE
Definition: network.h:156
int listen_timeout
Definition: tcp.c:38
int flags
Definition: url.h:46
#define freeaddrinfo
Definition: network.h:195
URLProtocol ff_tcp_protocol
Definition: tcp.c:271
static const AVClass tcp_context_class
Definition: tcp.c:51
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:55
uint8_t
AVOptions.
miscellaneous OS support macros and functions.
int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
Attempt to find a specific tag in a URL.
Definition: parseutils.c:647
static int tcp_read(URLContext *h, uint8_t *buf, int size)
Definition: tcp.c:214
#define E
Definition: tcp.c:43
struct TCPContext TCPContext
#define closesocket
Definition: ffserver.c:28
#define D
Definition: tcp.c:42
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
#define OFFSET(x)
Definition: tcp.c:41
int listen
Definition: tcp.c:36
int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb)
This works similarly to ff_network_wait_fd, but waits up to &#39;timeout&#39; microseconds Uses ff_network_wa...
Definition: network.c:153
int size
static const AVOption options[]
Definition: tcp.c:44
static int tcp_close(URLContext *h)
Definition: tcp.c:258
static int tcp_shutdown(URLContext *h, int flags)
Definition: tcp.c:242
ret
Definition: avfilter.c:821
#define ff_neterrno()
Definition: network.h:63
Definition: tcp.c:33
int ff_socket_nonblock(int socket, int enable)
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:56
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:39
NULL
Definition: eval.c:55
int ff_check_interrupt(AVIOInterruptCB *cb)
Check if the user has requested to interrup a blocking function associated with cb.
Definition: avio.c:428
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:351
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
void * buf
Definition: avisynth_c.h:594
Definition: url.h:41
Describe the class of an AVClass context structure.
Definition: log.h:50
void * priv_data
Definition: url.h:44
#define gai_strerror
Definition: network.h:201
#define snprintf
Definition: snprintf.h:34
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
int fd
Definition: tcp.c:35
misc parsing utilities
const char * name
Definition: url.h:55
int ai_socktype
Definition: network.h:117
static int flags
Definition: cpu.c:23
int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
Put a description of the AVERROR code errnum in errbuf.
Definition: error.c:53
#define getaddrinfo
Definition: network.h:194
Main libavformat public API header.
#define AVUNERROR(e)
Definition: error.h:44
static int tcp_write(URLContext *h, const uint8_t *buf, int size)
Definition: tcp.c:228
int ai_flags
Definition: network.h:115
unbuffered private I/O API
static int tcp_get_file_handle(URLContext *h)
Definition: tcp.c:265
int ai_family
Definition: network.h:116