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_POLL_H
00027 #include <poll.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 int ret;
00042 socklen_t optlen;
00043 char hostname[1024],proto[1024],path[1024];
00044 char portstr[10];
00045
00046 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
00047 &port, path, sizeof(path), uri);
00048 if (strcmp(proto,"tcp") || port <= 0 || port >= 65536)
00049 return AVERROR(EINVAL);
00050
00051 memset(&hints, 0, sizeof(hints));
00052 hints.ai_family = AF_UNSPEC;
00053 hints.ai_socktype = SOCK_STREAM;
00054 snprintf(portstr, sizeof(portstr), "%d", port);
00055 ret = getaddrinfo(hostname, portstr, &hints, &ai);
00056 if (ret) {
00057 av_log(NULL, AV_LOG_ERROR,
00058 "Failed to resolve hostname %s: %s\n",
00059 hostname, gai_strerror(ret));
00060 return AVERROR(EIO);
00061 }
00062
00063 cur_ai = ai;
00064
00065 restart:
00066 fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
00067 if (fd < 0)
00068 goto fail;
00069 ff_socket_nonblock(fd, 1);
00070
00071 redo:
00072 ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
00073 if (ret < 0) {
00074 struct pollfd p = {fd, POLLOUT, 0};
00075 if (ff_neterrno() == AVERROR(EINTR)) {
00076 if (url_interrupt_cb())
00077 goto fail1;
00078 goto redo;
00079 }
00080 if (ff_neterrno() != AVERROR(EINPROGRESS) &&
00081 ff_neterrno() != AVERROR(EAGAIN))
00082 goto fail;
00083
00084
00085 for(;;) {
00086 if (url_interrupt_cb()) {
00087 ret = AVERROR(EINTR);
00088 goto fail1;
00089 }
00090 ret = poll(&p, 1, 100);
00091 if (ret > 0)
00092 break;
00093 }
00094
00095
00096 optlen = sizeof(ret);
00097 getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
00098 if (ret != 0) {
00099 av_log(NULL, AV_LOG_ERROR,
00100 "TCP connection to %s:%d failed: %s\n",
00101 hostname, port, strerror(ret));
00102 goto fail;
00103 }
00104 }
00105 s = av_malloc(sizeof(TCPContext));
00106 if (!s) {
00107 freeaddrinfo(ai);
00108 return AVERROR(ENOMEM);
00109 }
00110 h->priv_data = s;
00111 h->is_streamed = 1;
00112 s->fd = fd;
00113 freeaddrinfo(ai);
00114 return 0;
00115
00116 fail:
00117 if (cur_ai->ai_next) {
00118
00119 cur_ai = cur_ai->ai_next;
00120 if (fd >= 0)
00121 closesocket(fd);
00122 goto restart;
00123 }
00124 ret = AVERROR(EIO);
00125 fail1:
00126 if (fd >= 0)
00127 closesocket(fd);
00128 freeaddrinfo(ai);
00129 return ret;
00130 }
00131
00132 static int tcp_wait_fd(int fd, int write)
00133 {
00134 int ev = write ? POLLOUT : POLLIN;
00135 struct pollfd p = { .fd = fd, .events = ev, .revents = 0 };
00136 int ret;
00137
00138 ret = poll(&p, 1, 100);
00139 return ret < 0 ? ff_neterrno() : p.revents & ev ? 0 : AVERROR(EAGAIN);
00140 }
00141
00142 static int tcp_read(URLContext *h, uint8_t *buf, int size)
00143 {
00144 TCPContext *s = h->priv_data;
00145 int ret;
00146
00147 if (!(h->flags & URL_FLAG_NONBLOCK)) {
00148 ret = tcp_wait_fd(s->fd, 0);
00149 if (ret < 0)
00150 return ret;
00151 }
00152 ret = recv(s->fd, buf, size, 0);
00153 return ret < 0 ? ff_neterrno() : ret;
00154 }
00155
00156 static int tcp_write(URLContext *h, const uint8_t *buf, int size)
00157 {
00158 TCPContext *s = h->priv_data;
00159 int ret;
00160
00161 if (!(h->flags & URL_FLAG_NONBLOCK)) {
00162 ret = tcp_wait_fd(s->fd, 1);
00163 if (ret < 0)
00164 return ret;
00165 }
00166 ret = send(s->fd, buf, size, 0);
00167 return ret < 0 ? ff_neterrno() : ret;
00168 }
00169
00170 static int tcp_close(URLContext *h)
00171 {
00172 TCPContext *s = h->priv_data;
00173 closesocket(s->fd);
00174 av_free(s);
00175 return 0;
00176 }
00177
00178 static int tcp_get_file_handle(URLContext *h)
00179 {
00180 TCPContext *s = h->priv_data;
00181 return s->fd;
00182 }
00183
00184 URLProtocol ff_tcp_protocol = {
00185 "tcp",
00186 tcp_open,
00187 tcp_read,
00188 tcp_write,
00189 NULL,
00190 tcp_close,
00191 .url_get_file_handle = tcp_get_file_handle,
00192 };