00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avformat.h"
00022 #include "libavutil/parseutils.h"
00023 #include <unistd.h>
00024 #include "internal.h"
00025 #include "network.h"
00026 #include "os_support.h"
00027 #include "url.h"
00028 #if HAVE_POLL_H
00029 #include <poll.h>
00030 #endif
00031 #include <sys/time.h>
00032
00033 typedef struct TCPContext {
00034 int fd;
00035 } TCPContext;
00036
00037
00038 static int tcp_open(URLContext *h, const char *uri, int flags)
00039 {
00040 struct addrinfo hints, *ai, *cur_ai;
00041 int port, fd = -1;
00042 TCPContext *s = h->priv_data;
00043 int listen_socket = 0;
00044 const char *p;
00045 char buf[256];
00046 int ret;
00047 socklen_t optlen;
00048 int timeout = 50;
00049 char hostname[1024],proto[1024],path[1024];
00050 char portstr[10];
00051
00052 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
00053 &port, path, sizeof(path), uri);
00054 if (strcmp(proto,"tcp") || port <= 0 || port >= 65536)
00055 return AVERROR(EINVAL);
00056
00057 p = strchr(uri, '?');
00058 if (p) {
00059 if (av_find_info_tag(buf, sizeof(buf), "listen", p))
00060 listen_socket = 1;
00061 if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
00062 timeout = strtol(buf, NULL, 10);
00063 }
00064 }
00065 memset(&hints, 0, sizeof(hints));
00066 hints.ai_family = AF_UNSPEC;
00067 hints.ai_socktype = SOCK_STREAM;
00068 snprintf(portstr, sizeof(portstr), "%d", port);
00069 ret = getaddrinfo(hostname, portstr, &hints, &ai);
00070 if (ret) {
00071 av_log(h, AV_LOG_ERROR,
00072 "Failed to resolve hostname %s: %s\n",
00073 hostname, gai_strerror(ret));
00074 return AVERROR(EIO);
00075 }
00076
00077 cur_ai = ai;
00078
00079 restart:
00080 ret = AVERROR(EIO);
00081 fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
00082 if (fd < 0)
00083 goto fail;
00084
00085 if (listen_socket) {
00086 int fd1;
00087 ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
00088 listen(fd, 1);
00089 fd1 = accept(fd, NULL, NULL);
00090 closesocket(fd);
00091 fd = fd1;
00092 ff_socket_nonblock(fd, 1);
00093 } else {
00094 redo:
00095 ff_socket_nonblock(fd, 1);
00096 ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
00097 }
00098
00099 if (ret < 0) {
00100 struct pollfd p = {fd, POLLOUT, 0};
00101 ret = ff_neterrno();
00102 if (ret == AVERROR(EINTR)) {
00103 if (ff_check_interrupt(&h->interrupt_callback)) {
00104 ret = AVERROR_EXIT;
00105 goto fail1;
00106 }
00107 goto redo;
00108 }
00109 if (ret != AVERROR(EINPROGRESS) &&
00110 ret != AVERROR(EAGAIN))
00111 goto fail;
00112
00113
00114 while(timeout--) {
00115 if (ff_check_interrupt(&h->interrupt_callback)) {
00116 ret = AVERROR_EXIT;
00117 goto fail1;
00118 }
00119 ret = poll(&p, 1, 100);
00120 if (ret > 0)
00121 break;
00122 }
00123 if (ret <= 0) {
00124 ret = AVERROR(ETIMEDOUT);
00125 goto fail;
00126 }
00127
00128 optlen = sizeof(ret);
00129 getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
00130 if (ret != 0) {
00131 av_log(h, AV_LOG_ERROR,
00132 "TCP connection to %s:%d failed: %s\n",
00133 hostname, port, strerror(ret));
00134 ret = AVERROR(ret);
00135 goto fail;
00136 }
00137 }
00138 h->is_streamed = 1;
00139 s->fd = fd;
00140 freeaddrinfo(ai);
00141 return 0;
00142
00143 fail:
00144 if (cur_ai->ai_next) {
00145
00146 cur_ai = cur_ai->ai_next;
00147 if (fd >= 0)
00148 closesocket(fd);
00149 goto restart;
00150 }
00151 fail1:
00152 if (fd >= 0)
00153 closesocket(fd);
00154 freeaddrinfo(ai);
00155 return ret;
00156 }
00157
00158 static int tcp_read(URLContext *h, uint8_t *buf, int size)
00159 {
00160 TCPContext *s = h->priv_data;
00161 int ret;
00162
00163 if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
00164 ret = ff_network_wait_fd(s->fd, 0);
00165 if (ret < 0)
00166 return ret;
00167 }
00168 ret = recv(s->fd, buf, size, 0);
00169 return ret < 0 ? ff_neterrno() : ret;
00170 }
00171
00172 static int tcp_write(URLContext *h, const uint8_t *buf, int size)
00173 {
00174 TCPContext *s = h->priv_data;
00175 int ret;
00176
00177 if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
00178 ret = ff_network_wait_fd(s->fd, 1);
00179 if (ret < 0)
00180 return ret;
00181 }
00182 ret = send(s->fd, buf, size, 0);
00183 return ret < 0 ? ff_neterrno() : ret;
00184 }
00185
00186 static int tcp_close(URLContext *h)
00187 {
00188 TCPContext *s = h->priv_data;
00189 closesocket(s->fd);
00190 return 0;
00191 }
00192
00193 static int tcp_get_file_handle(URLContext *h)
00194 {
00195 TCPContext *s = h->priv_data;
00196 return s->fd;
00197 }
00198
00199 URLProtocol ff_tcp_protocol = {
00200 .name = "tcp",
00201 .url_open = tcp_open,
00202 .url_read = tcp_read,
00203 .url_write = tcp_write,
00204 .url_close = tcp_close,
00205 .url_get_file_handle = tcp_get_file_handle,
00206 .priv_data_size = sizeof(TCPContext),
00207 };