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;
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 ff_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 if (getaddrinfo(hostname, portstr, &hints, &ai))
00058 return AVERROR(EIO);
00059
00060 cur_ai = ai;
00061
00062 restart:
00063 fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
00064 if (fd < 0)
00065 goto fail;
00066 ff_socket_nonblock(fd, 1);
00067
00068 redo:
00069 ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
00070 if (ret < 0) {
00071 if (ff_neterrno() == FF_NETERROR(EINTR))
00072 goto redo;
00073 if (ff_neterrno() != FF_NETERROR(EINPROGRESS) &&
00074 ff_neterrno() != FF_NETERROR(EAGAIN))
00075 goto fail;
00076
00077
00078 for(;;) {
00079 if (url_interrupt_cb()) {
00080 ret = AVERROR(EINTR);
00081 goto fail1;
00082 }
00083 fd_max = fd;
00084 FD_ZERO(&wfds);
00085 FD_SET(fd, &wfds);
00086 tv.tv_sec = 0;
00087 tv.tv_usec = 100 * 1000;
00088 ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
00089 if (ret > 0 && FD_ISSET(fd, &wfds))
00090 break;
00091 }
00092
00093
00094 optlen = sizeof(ret);
00095 getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
00096 if (ret != 0)
00097 goto fail;
00098 }
00099 s = av_malloc(sizeof(TCPContext));
00100 if (!s) {
00101 freeaddrinfo(ai);
00102 return AVERROR(ENOMEM);
00103 }
00104 h->priv_data = s;
00105 h->is_streamed = 1;
00106 s->fd = fd;
00107 freeaddrinfo(ai);
00108 return 0;
00109
00110 fail:
00111 if (cur_ai->ai_next) {
00112
00113 cur_ai = cur_ai->ai_next;
00114 if (fd >= 0)
00115 closesocket(fd);
00116 goto restart;
00117 }
00118 ret = AVERROR(EIO);
00119 fail1:
00120 if (fd >= 0)
00121 closesocket(fd);
00122 freeaddrinfo(ai);
00123 return ret;
00124 }
00125
00126 static int tcp_read(URLContext *h, uint8_t *buf, int size)
00127 {
00128 TCPContext *s = h->priv_data;
00129 int len, fd_max, ret;
00130 fd_set rfds;
00131 struct timeval tv;
00132
00133 for (;;) {
00134 if (url_interrupt_cb())
00135 return AVERROR(EINTR);
00136 fd_max = s->fd;
00137 FD_ZERO(&rfds);
00138 FD_SET(s->fd, &rfds);
00139 tv.tv_sec = 0;
00140 tv.tv_usec = 100 * 1000;
00141 ret = select(fd_max + 1, &rfds, NULL, NULL, &tv);
00142 if (ret > 0 && FD_ISSET(s->fd, &rfds)) {
00143 len = recv(s->fd, buf, size, 0);
00144 if (len < 0) {
00145 if (ff_neterrno() != FF_NETERROR(EINTR) &&
00146 ff_neterrno() != FF_NETERROR(EAGAIN))
00147 return AVERROR(ff_neterrno());
00148 } else return len;
00149 } else if (ret < 0) {
00150 if (ff_neterrno() == FF_NETERROR(EINTR))
00151 continue;
00152 return -1;
00153 }
00154 }
00155 }
00156
00157 static int tcp_write(URLContext *h, uint8_t *buf, int size)
00158 {
00159 TCPContext *s = h->priv_data;
00160 int ret, size1, fd_max, len;
00161 fd_set wfds;
00162 struct timeval tv;
00163
00164 size1 = size;
00165 while (size > 0) {
00166 if (url_interrupt_cb())
00167 return AVERROR(EINTR);
00168 fd_max = s->fd;
00169 FD_ZERO(&wfds);
00170 FD_SET(s->fd, &wfds);
00171 tv.tv_sec = 0;
00172 tv.tv_usec = 100 * 1000;
00173 ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
00174 if (ret > 0 && FD_ISSET(s->fd, &wfds)) {
00175 len = send(s->fd, buf, size, 0);
00176 if (len < 0) {
00177 if (ff_neterrno() != FF_NETERROR(EINTR) &&
00178 ff_neterrno() != FF_NETERROR(EAGAIN))
00179 return AVERROR(ff_neterrno());
00180 continue;
00181 }
00182 size -= len;
00183 buf += len;
00184 } else if (ret < 0) {
00185 if (ff_neterrno() == FF_NETERROR(EINTR))
00186 continue;
00187 return -1;
00188 }
00189 }
00190 return size1 - size;
00191 }
00192
00193 static int tcp_close(URLContext *h)
00194 {
00195 TCPContext *s = h->priv_data;
00196 closesocket(s->fd);
00197 av_free(s);
00198 return 0;
00199 }
00200
00201 static int tcp_get_file_handle(URLContext *h)
00202 {
00203 TCPContext *s = h->priv_data;
00204 return s->fd;
00205 }
00206
00207 URLProtocol tcp_protocol = {
00208 "tcp",
00209 tcp_open,
00210 tcp_read,
00211 tcp_write,
00212 NULL,
00213 tcp_close,
00214 .url_get_file_handle = tcp_get_file_handle,
00215 };