• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • 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 <unistd.h>
00023 #include "internal.h"
00024 #include "network.h"
00025 #include "os_support.h"
00026 #if HAVE_SYS_SELECT_H
00027 #include <sys/select.h>
00028 #endif
00029 #include <sys/time.h>
00030 
00031 typedef struct TCPContext {
00032     int fd;
00033 } TCPContext;
00034 
00035 /* return non zero if error */
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     fd_set wfds;
00042     int fd_max, ret;
00043     struct timeval tv;
00044     socklen_t optlen;
00045     char hostname[1024],proto[1024],path[1024];
00046     char portstr[10];
00047 
00048     ff_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
00049         &port, path, sizeof(path), uri);
00050     if (strcmp(proto,"tcp") || port <= 0 || port >= 65536)
00051         return AVERROR(EINVAL);
00052 
00053     memset(&hints, 0, sizeof(hints));
00054     hints.ai_family = AF_UNSPEC;
00055     hints.ai_socktype = SOCK_STREAM;
00056     snprintf(portstr, sizeof(portstr), "%d", port);
00057     if (getaddrinfo(hostname, portstr, &hints, &ai))
00058         return AVERROR(EIO);
00059 
00060     cur_ai = ai;
00061 
00062  restart:
00063     fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol);
00064     if (fd < 0)
00065         goto fail;
00066     ff_socket_nonblock(fd, 1);
00067 
00068  redo:
00069     ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
00070     if (ret < 0) {
00071         if (ff_neterrno() == FF_NETERROR(EINTR))
00072             goto redo;
00073         if (ff_neterrno() != FF_NETERROR(EINPROGRESS) &&
00074             ff_neterrno() != FF_NETERROR(EAGAIN))
00075             goto fail;
00076 
00077         /* wait until we are connected or until abort */
00078         for(;;) {
00079             if (url_interrupt_cb()) {
00080                 ret = AVERROR(EINTR);
00081                 goto fail1;
00082             }
00083             fd_max = fd;
00084             FD_ZERO(&wfds);
00085             FD_SET(fd, &wfds);
00086             tv.tv_sec = 0;
00087             tv.tv_usec = 100 * 1000;
00088             ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
00089             if (ret > 0 && FD_ISSET(fd, &wfds))
00090                 break;
00091         }
00092 
00093         /* test error */
00094         optlen = sizeof(ret);
00095         getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
00096         if (ret != 0)
00097             goto fail;
00098     }
00099     s = av_malloc(sizeof(TCPContext));
00100     if (!s) {
00101         freeaddrinfo(ai);
00102         return AVERROR(ENOMEM);
00103     }
00104     h->priv_data = s;
00105     h->is_streamed = 1;
00106     s->fd = fd;
00107     freeaddrinfo(ai);
00108     return 0;
00109 
00110  fail:
00111     if (cur_ai->ai_next) {
00112         /* Retry with the next sockaddr */
00113         cur_ai = cur_ai->ai_next;
00114         if (fd >= 0)
00115             closesocket(fd);
00116         goto restart;
00117     }
00118     ret = AVERROR(EIO);
00119  fail1:
00120     if (fd >= 0)
00121         closesocket(fd);
00122     freeaddrinfo(ai);
00123     return ret;
00124 }
00125 
00126 static int tcp_read(URLContext *h, uint8_t *buf, int size)
00127 {
00128     TCPContext *s = h->priv_data;
00129     int len, fd_max, ret;
00130     fd_set rfds;
00131     struct timeval tv;
00132 
00133     for (;;) {
00134         if (url_interrupt_cb())
00135             return AVERROR(EINTR);
00136         fd_max = s->fd;
00137         FD_ZERO(&rfds);
00138         FD_SET(s->fd, &rfds);
00139         tv.tv_sec = 0;
00140         tv.tv_usec = 100 * 1000;
00141         ret = select(fd_max + 1, &rfds, NULL, NULL, &tv);
00142         if (ret > 0 && FD_ISSET(s->fd, &rfds)) {
00143             len = recv(s->fd, buf, size, 0);
00144             if (len < 0) {
00145                 if (ff_neterrno() != FF_NETERROR(EINTR) &&
00146                     ff_neterrno() != FF_NETERROR(EAGAIN))
00147                     return AVERROR(ff_neterrno());
00148             } else return len;
00149         } else if (ret < 0) {
00150             if (ff_neterrno() == FF_NETERROR(EINTR))
00151                 continue;
00152             return -1;
00153         }
00154     }
00155 }
00156 
00157 static int tcp_write(URLContext *h, uint8_t *buf, int size)
00158 {
00159     TCPContext *s = h->priv_data;
00160     int ret, size1, fd_max, len;
00161     fd_set wfds;
00162     struct timeval tv;
00163 
00164     size1 = size;
00165     while (size > 0) {
00166         if (url_interrupt_cb())
00167             return AVERROR(EINTR);
00168         fd_max = s->fd;
00169         FD_ZERO(&wfds);
00170         FD_SET(s->fd, &wfds);
00171         tv.tv_sec = 0;
00172         tv.tv_usec = 100 * 1000;
00173         ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
00174         if (ret > 0 && FD_ISSET(s->fd, &wfds)) {
00175             len = send(s->fd, buf, size, 0);
00176             if (len < 0) {
00177                 if (ff_neterrno() != FF_NETERROR(EINTR) &&
00178                     ff_neterrno() != FF_NETERROR(EAGAIN))
00179                     return AVERROR(ff_neterrno());
00180                 continue;
00181             }
00182             size -= len;
00183             buf += len;
00184         } else if (ret < 0) {
00185             if (ff_neterrno() == FF_NETERROR(EINTR))
00186                 continue;
00187             return -1;
00188         }
00189     }
00190     return size1 - size;
00191 }
00192 
00193 static int tcp_close(URLContext *h)
00194 {
00195     TCPContext *s = h->priv_data;
00196     closesocket(s->fd);
00197     av_free(s);
00198     return 0;
00199 }
00200 
00201 static int tcp_get_file_handle(URLContext *h)
00202 {
00203     TCPContext *s = h->priv_data;
00204     return s->fd;
00205 }
00206 
00207 URLProtocol tcp_protocol = {
00208     "tcp",
00209     tcp_open,
00210     tcp_read,
00211     tcp_write,
00212     NULL, /* seek */
00213     tcp_close,
00214     .url_get_file_handle = tcp_get_file_handle,
00215 };

Generated on Fri Sep 16 2011 17:17:51 for FFmpeg by  doxygen 1.7.1