• 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 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 = NULL;
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(NULL, 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 (url_interrupt_cb()) {
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 (url_interrupt_cb()) {
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(NULL, 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     s = av_malloc(sizeof(TCPContext));
00139     if (!s) {
00140         freeaddrinfo(ai);
00141         return AVERROR(ENOMEM);
00142     }
00143     h->priv_data = s;
00144     h->is_streamed = 1;
00145     s->fd = fd;
00146     freeaddrinfo(ai);
00147     return 0;
00148 
00149  fail:
00150     if (cur_ai->ai_next) {
00151         /* Retry with the next sockaddr */
00152         cur_ai = cur_ai->ai_next;
00153         if (fd >= 0)
00154             closesocket(fd);
00155         goto restart;
00156     }
00157  fail1:
00158     if (fd >= 0)
00159         closesocket(fd);
00160     freeaddrinfo(ai);
00161     return ret;
00162 }
00163 
00164 static int tcp_read(URLContext *h, uint8_t *buf, int size)
00165 {
00166     TCPContext *s = h->priv_data;
00167     int ret;
00168 
00169     if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
00170         ret = ff_network_wait_fd(s->fd, 0);
00171         if (ret < 0)
00172             return ret;
00173     }
00174     ret = recv(s->fd, buf, size, 0);
00175     return ret < 0 ? ff_neterrno() : ret;
00176 }
00177 
00178 static int tcp_write(URLContext *h, const uint8_t *buf, int size)
00179 {
00180     TCPContext *s = h->priv_data;
00181     int ret;
00182 
00183     if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
00184         ret = ff_network_wait_fd(s->fd, 1);
00185         if (ret < 0)
00186             return ret;
00187     }
00188     ret = send(s->fd, buf, size, 0);
00189     return ret < 0 ? ff_neterrno() : ret;
00190 }
00191 
00192 static int tcp_close(URLContext *h)
00193 {
00194     TCPContext *s = h->priv_data;
00195     closesocket(s->fd);
00196     av_free(s);
00197     return 0;
00198 }
00199 
00200 static int tcp_get_file_handle(URLContext *h)
00201 {
00202     TCPContext *s = h->priv_data;
00203     return s->fd;
00204 }
00205 
00206 URLProtocol ff_tcp_protocol = {
00207     .name                = "tcp",
00208     .url_open            = tcp_open,
00209     .url_read            = tcp_read,
00210     .url_write           = tcp_write,
00211     .url_close           = tcp_close,
00212     .url_get_file_handle = tcp_get_file_handle,
00213 };

Generated on Fri Feb 22 2013 07:24:32 for FFmpeg by  doxygen 1.7.1