libavformat/tcp.c

Go to the documentation of this file.
00001 /*
00002  * TCP protocol
00003  * Copyright (c) 2002 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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 /* return non zero if error */
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 /* wait until we are connected or until abort */
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 /* test error */
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 /* Retry with the next sockaddr */
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 .flags = URL_PROTOCOL_FLAG_NETWORK,
00208 };

Generated on Fri Oct 26 02:46:05 2012 for FFmpeg by doxygen 1.5.8

AltStyle によって変換されたページ (->オリジナル) /