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 = NULL;
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(NULL, 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 (url_interrupt_cb()) {
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 (url_interrupt_cb()) {
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(NULL, 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 s = av_malloc(sizeof(TCPContext));
00139 if (!s) {
00140 freeaddrinfo(ai);
00141 return AVERROR(ENOMEM);
00142 }
00143 h->priv_data = s;
00144 h->is_streamed = 1;
00145 s->fd = fd;
00146 freeaddrinfo(ai);
00147 return 0;
00148
00149 fail:
00150 if (cur_ai->ai_next) {
00151
00152 cur_ai = cur_ai->ai_next;
00153 if (fd >= 0)
00154 closesocket(fd);
00155 goto restart;
00156 }
00157 fail1:
00158 if (fd >= 0)
00159 closesocket(fd);
00160 freeaddrinfo(ai);
00161 return ret;
00162 }
00163
00164 static int tcp_read(URLContext *h, uint8_t *buf, int size)
00165 {
00166 TCPContext *s = h->priv_data;
00167 int ret;
00168
00169 if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
00170 ret = ff_network_wait_fd(s->fd, 0);
00171 if (ret < 0)
00172 return ret;
00173 }
00174 ret = recv(s->fd, buf, size, 0);
00175 return ret < 0 ? ff_neterrno() : ret;
00176 }
00177
00178 static int tcp_write(URLContext *h, const uint8_t *buf, int size)
00179 {
00180 TCPContext *s = h->priv_data;
00181 int ret;
00182
00183 if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
00184 ret = ff_network_wait_fd(s->fd, 1);
00185 if (ret < 0)
00186 return ret;
00187 }
00188 ret = send(s->fd, buf, size, 0);
00189 return ret < 0 ? ff_neterrno() : ret;
00190 }
00191
00192 static int tcp_close(URLContext *h)
00193 {
00194 TCPContext *s = h->priv_data;
00195 closesocket(s->fd);
00196 av_free(s);
00197 return 0;
00198 }
00199
00200 static int tcp_get_file_handle(URLContext *h)
00201 {
00202 TCPContext *s = h->priv_data;
00203 return s->fd;
00204 }
00205
00206 URLProtocol ff_tcp_protocol = {
00207 .name = "tcp",
00208 .url_open = tcp_open,
00209 .url_read = tcp_read,
00210 .url_write = tcp_write,
00211 .url_close = tcp_close,
00212 .url_get_file_handle = tcp_get_file_handle,
00213 };