3 * Copyright (c) 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
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.
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.
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
25 #include "os_support.h"
27 #include <sys/select.h>
31 typedef struct TCPContext
{
35 /* return non zero if error */
36 static int tcp_open(URLContext
*h
, const char *uri
, int flags
)
38 struct addrinfo hints
, *ai
, *cur_ai
;
45 char hostname
[1024],proto
[1024],path
[1024];
48 ff_url_split(proto
, sizeof(proto
), NULL
, 0, hostname
, sizeof(hostname
),
49 &port
, path
, sizeof(path
), uri
);
50 if (strcmp(proto
,"tcp") || port
<= 0 || port
>= 65536)
51 return AVERROR(EINVAL
);
53 memset(&hints
, 0, sizeof(hints
));
54 hints
.ai_family
= AF_UNSPEC
;
55 hints
.ai_socktype
= SOCK_STREAM
;
56 snprintf(portstr
, sizeof(portstr
), "%d", port
);
57 if (getaddrinfo(hostname
, portstr
, &hints
, &ai
))
63 fd
= socket(cur_ai
->ai_family
, cur_ai
->ai_socktype
, cur_ai
->ai_protocol
);
66 ff_socket_nonblock(fd
, 1);
69 ret
= connect(fd
, cur_ai
->ai_addr
, cur_ai
->ai_addrlen
);
71 if (ff_neterrno() == FF_NETERROR(EINTR
))
73 if (ff_neterrno() != FF_NETERROR(EINPROGRESS
) &&
74 ff_neterrno() != FF_NETERROR(EAGAIN
))
77 /* wait until we are connected or until abort */
79 if (url_interrupt_cb()) {
87 tv
.tv_usec
= 100 * 1000;
88 ret
= select(fd_max
+ 1, NULL
, &wfds
, NULL
, &tv
);
89 if (ret
> 0 && FD_ISSET(fd
, &wfds
))
95 getsockopt (fd
, SOL_SOCKET
, SO_ERROR
, &ret
, &optlen
);
99 s
= av_malloc(sizeof(TCPContext
));
102 return AVERROR(ENOMEM
);
111 if (cur_ai
->ai_next
) {
112 /* Retry with the next sockaddr */
113 cur_ai
= cur_ai
->ai_next
;
126 static int tcp_read(URLContext
*h
, uint8_t *buf
, int size
)
128 TCPContext
*s
= h
->priv_data
;
129 int len
, fd_max
, ret
;
134 if (url_interrupt_cb())
135 return AVERROR(EINTR
);
138 FD_SET(s
->fd
, &rfds
);
140 tv
.tv_usec
= 100 * 1000;
141 ret
= select(fd_max
+ 1, &rfds
, NULL
, NULL
, &tv
);
142 if (ret
> 0 && FD_ISSET(s
->fd
, &rfds
)) {
143 len
= recv(s
->fd
, buf
, size
, 0);
145 if (ff_neterrno() != FF_NETERROR(EINTR
) &&
146 ff_neterrno() != FF_NETERROR(EAGAIN
))
147 return AVERROR(ff_neterrno());
149 } else if (ret
< 0) {
150 if (ff_neterrno() == FF_NETERROR(EINTR
))
157 static int tcp_write(URLContext
*h
, uint8_t *buf
, int size
)
159 TCPContext
*s
= h
->priv_data
;
160 int ret
, size1
, fd_max
, len
;
166 if (url_interrupt_cb())
167 return AVERROR(EINTR
);
170 FD_SET(s
->fd
, &wfds
);
172 tv
.tv_usec
= 100 * 1000;
173 ret
= select(fd_max
+ 1, NULL
, &wfds
, NULL
, &tv
);
174 if (ret
> 0 && FD_ISSET(s
->fd
, &wfds
)) {
175 len
= send(s
->fd
, buf
, size
, 0);
177 if (ff_neterrno() != FF_NETERROR(EINTR
) &&
178 ff_neterrno() != FF_NETERROR(EAGAIN
))
179 return AVERROR(ff_neterrno());
184 } else if (ret
< 0) {
185 if (ff_neterrno() == FF_NETERROR(EINTR
))
193 static int tcp_close(URLContext
*h
)
195 TCPContext
*s
= h
->priv_data
;
201 static int tcp_get_file_handle(URLContext
*h
)
203 TCPContext
*s
= h
->priv_data
;
207 URLProtocol tcp_protocol
= {
214 .url_get_file_handle
= tcp_get_file_handle
,