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 <unistd.h>
00023 #include "internal.h"
00024 #include "network.h"
00025 #include "os_support.h"
00026 #if HAVE_SYS_SELECT_H
00027 #include <sys/select.h>
00028 #endif
00029 #include <sys/time.h>
00030
00031 typedef struct TCPContext {
00032 int fd;
00033 } TCPContext;
00034
00035
00036 static int tcp_open(URLContext *h, const char *uri, int flags)
00037 {
00038 struct addrinfo hints, *ai, *cur_ai;
00039 int port, fd = -1;
00040 TCPContext *s = NULL;
00041 fd_set wfds, efds;
00042 int fd_max, ret;
00043 struct timeval tv;
00044 socklen_t optlen;
00045 char hostname[1024],proto[1024],path[1024];
00046 char portstr[10];
00047
00048 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
00049 &port, path, sizeof(path), uri);
00050 if (strcmp(proto,"tcp") || port <= 0 || port >= 65536)
00051 return AVERROR(EINVAL);
00052
00053 memset(&hints, 0, sizeof(hints));
00054 hints.ai_family = AF_UNSPEC;
00055 hints.ai_socktype = SOCK_STREAM;
00056 snprintf(portstr, sizeof(portstr), "%d", port);
00057 ret = getaddrinfo(hostname, portstr, &hints, &ai);
00058 if (ret) {
00059 av_log(NULL, AV_LOG_ERROR,
00060 "Failed to resolve hostname %s: %s\n",
00061 hostname, gai_strerror(ret));
00062 return AVERROR(EIO);
00063 }
00064
00065 cur_ai = ai;
00066
00067 restart:
00068 fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
00069 if (fd < 0)
00070 goto fail;
00071 ff_socket_nonblock(fd, 1);
00072
00073 redo:
00074 ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
00075 if (ret < 0) {
00076 if (ff_neterrno() == FF_NETERROR(EINTR)) {
00077 if (url_interrupt_cb())
00078 goto fail1;
00079 goto redo;
00080 }
00081 if (ff_neterrno() != FF_NETERROR(EINPROGRESS) &&
00082 ff_neterrno() != FF_NETERROR(EAGAIN))
00083 goto fail;
00084
00085
00086 for(;;) {
00087 if (url_interrupt_cb()) {
00088 ret = AVERROR(EINTR);
00089 goto fail1;
00090 }
00091 fd_max = fd;
00092 FD_ZERO(&wfds);
00093 FD_ZERO(&efds);
00094 FD_SET(fd, &wfds);
00095 FD_SET(fd, &efds);
00096 tv.tv_sec = 0;
00097 tv.tv_usec = 100 * 1000;
00098 ret = select(fd_max + 1, NULL, &wfds, &efds, &tv);
00099 if (ret > 0 && (FD_ISSET(fd, &wfds) || FD_ISSET(fd, &efds)))
00100 break;
00101 }
00102
00103
00104 optlen = sizeof(ret);
00105 getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
00106 if (ret != 0) {
00107 av_log(NULL, AV_LOG_ERROR,
00108 "TCP connection to %s:%d failed: %s\n",
00109 hostname, port, strerror(ret));
00110 goto fail;
00111 }
00112 }
00113 s = av_malloc(sizeof(TCPContext));
00114 if (!s) {
00115 freeaddrinfo(ai);
00116 return AVERROR(ENOMEM);
00117 }
00118 h->priv_data = s;
00119 h->is_streamed = 1;
00120 s->fd = fd;
00121 freeaddrinfo(ai);
00122 return 0;
00123
00124 fail:
00125 if (cur_ai->ai_next) {
00126
00127 cur_ai = cur_ai->ai_next;
00128 if (fd >= 0)
00129 closesocket(fd);
00130 goto restart;
00131 }
00132 ret = AVERROR(EIO);
00133 fail1:
00134 if (fd >= 0)
00135 closesocket(fd);
00136 freeaddrinfo(ai);
00137 return ret;
00138 }
00139
00140 static int tcp_read(URLContext *h, uint8_t *buf, int size)
00141 {
00142 TCPContext *s = h->priv_data;
00143 int len, fd_max, ret;
00144 fd_set rfds;
00145 struct timeval tv;
00146
00147 for (;;) {
00148 if (url_interrupt_cb())
00149 return AVERROR(EINTR);
00150 fd_max = s->fd;
00151 FD_ZERO(&rfds);
00152 FD_SET(s->fd, &rfds);
00153 tv.tv_sec = 0;
00154 tv.tv_usec = 100 * 1000;
00155 ret = select(fd_max + 1, &rfds, NULL, NULL, &tv);
00156 if (ret > 0 && FD_ISSET(s->fd, &rfds)) {
00157 len = recv(s->fd, buf, size, 0);
00158 if (len < 0) {
00159 if (ff_neterrno() != FF_NETERROR(EINTR) &&
00160 ff_neterrno() != FF_NETERROR(EAGAIN))
00161 return ff_neterrno();
00162 } else return len;
00163 } else if (ret < 0) {
00164 if (ff_neterrno() == FF_NETERROR(EINTR))
00165 continue;
00166 return -1;
00167 }
00168 }
00169 }
00170
00171 static int tcp_write(URLContext *h, const uint8_t *buf, int size)
00172 {
00173 TCPContext *s = h->priv_data;
00174 int ret, size1, fd_max, len;
00175 fd_set wfds;
00176 struct timeval tv;
00177
00178 size1 = size;
00179 while (size > 0) {
00180 if (url_interrupt_cb())
00181 return AVERROR(EINTR);
00182 fd_max = s->fd;
00183 FD_ZERO(&wfds);
00184 FD_SET(s->fd, &wfds);
00185 tv.tv_sec = 0;
00186 tv.tv_usec = 100 * 1000;
00187 ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
00188 if (ret > 0 && FD_ISSET(s->fd, &wfds)) {
00189 len = send(s->fd, buf, size, 0);
00190 if (len < 0) {
00191 if (ff_neterrno() != FF_NETERROR(EINTR) &&
00192 ff_neterrno() != FF_NETERROR(EAGAIN))
00193 return ff_neterrno();
00194 continue;
00195 }
00196 size -= len;
00197 buf += len;
00198 } else if (ret < 0) {
00199 if (ff_neterrno() == FF_NETERROR(EINTR))
00200 continue;
00201 return -1;
00202 }
00203 }
00204 return size1 - size;
00205 }
00206
00207 static int tcp_close(URLContext *h)
00208 {
00209 TCPContext *s = h->priv_data;
00210 closesocket(s->fd);
00211 av_free(s);
00212 return 0;
00213 }
00214
00215 static int tcp_get_file_handle(URLContext *h)
00216 {
00217 TCPContext *s = h->priv_data;
00218 return s->fd;
00219 }
00220
00221 URLProtocol tcp_protocol = {
00222 "tcp",
00223 tcp_open,
00224 tcp_read,
00225 tcp_write,
00226 NULL,
00227 tcp_close,
00228 .url_get_file_handle = tcp_get_file_handle,
00229 };