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 };