• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

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 Libav.
00006  *
00007  * Libav 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  * Libav 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 Libav; 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 = 100;
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 Sat Mar 17 2012 12:57:55 for Libav by doxygen 1.7.1