| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * TCP protocol | 
					
						
							|  |  |  |  * Copyright (c) 2002 Fabrice Bellard. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * This file is part of FFmpeg. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * FFmpeg is free software; you can redistribute it and/or | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * FFmpeg is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General Public | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * License along with FFmpeg; if not, write to the Free Software | 
					
						
							| 
									
										
										
										
											2006-01-12 22:43:26 +00:00
										 |  |  |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | #include "avformat.h"
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2007-02-04 17:05:44 +00:00
										 |  |  | #include "network.h"
 | 
					
						
							| 
									
										
										
										
											2007-11-21 16:33:06 +00:00
										 |  |  | #include "os_support.h"
 | 
					
						
							| 
									
										
										
										
											2008-09-24 22:11:53 +00:00
										 |  |  | #include <sys/select.h>
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  | #include <sys/time.h>
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef struct TCPContext { | 
					
						
							|  |  |  |     int fd; | 
					
						
							|  |  |  | } TCPContext; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* return non zero if error */ | 
					
						
							|  |  |  | static int tcp_open(URLContext *h, const char *uri, int flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct sockaddr_in dest_addr; | 
					
						
							|  |  |  |     int port, fd = -1; | 
					
						
							| 
									
										
										
										
											2005-02-24 19:08:50 +00:00
										 |  |  |     TCPContext *s = NULL; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |     fd_set wfds; | 
					
						
							|  |  |  |     int fd_max, ret; | 
					
						
							|  |  |  |     struct timeval tv; | 
					
						
							|  |  |  |     socklen_t optlen; | 
					
						
							| 
									
										
										
										
											2008-08-24 16:22:40 +00:00
										 |  |  |     char hostname[1024],proto[1024],path[1024]; | 
					
						
							| 
									
										
										
										
											2004-08-12 00:09:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-23 17:39:56 +00:00
										 |  |  |     if(!ff_network_init()) | 
					
						
							|  |  |  |         return AVERROR(EIO); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-08-12 00:09:32 +00:00
										 |  |  |     url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), | 
					
						
							| 
									
										
										
										
											2008-08-23 18:52:26 +00:00
										 |  |  |         &port, path, sizeof(path), uri); | 
					
						
							|  |  |  |     if (strcmp(proto,"tcp") || port <= 0 || port >= 65536) | 
					
						
							| 
									
										
										
										
											2008-08-23 18:49:16 +00:00
										 |  |  |         return AVERROR(EINVAL); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     dest_addr.sin_family = AF_INET; | 
					
						
							|  |  |  |     dest_addr.sin_port = htons(port); | 
					
						
							|  |  |  |     if (resolve_host(&dest_addr.sin_addr, hostname) < 0) | 
					
						
							| 
									
										
										
										
											2008-08-23 18:49:16 +00:00
										 |  |  |         return AVERROR(EIO); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-22 13:34:36 +00:00
										 |  |  |     fd = socket(AF_INET, SOCK_STREAM, 0); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     if (fd < 0) | 
					
						
							| 
									
										
										
										
											2008-08-23 18:49:16 +00:00
										 |  |  |         return AVERROR(EIO); | 
					
						
							| 
									
										
										
										
											2007-04-27 00:41:50 +00:00
										 |  |  |     ff_socket_nonblock(fd, 1); | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |  redo: | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  |     ret = connect(fd, (struct sockaddr *)&dest_addr, | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |                   sizeof(dest_addr)); | 
					
						
							|  |  |  |     if (ret < 0) { | 
					
						
							| 
									
										
										
										
											2007-04-27 00:35:54 +00:00
										 |  |  |         if (ff_neterrno() == FF_NETERROR(EINTR)) | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |             goto redo; | 
					
						
							| 
									
										
										
										
											2007-08-08 12:08:16 +00:00
										 |  |  |         if (ff_neterrno() != FF_NETERROR(EINPROGRESS) && | 
					
						
							|  |  |  |             ff_neterrno() != FF_NETERROR(EAGAIN)) | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |             goto fail; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |         /* wait until we are connected or until abort */ | 
					
						
							|  |  |  |         for(;;) { | 
					
						
							|  |  |  |             if (url_interrupt_cb()) { | 
					
						
							| 
									
										
										
										
											2007-02-13 18:26:14 +00:00
										 |  |  |                 ret = AVERROR(EINTR); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |                 goto fail1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             fd_max = fd; | 
					
						
							|  |  |  |             FD_ZERO(&wfds); | 
					
						
							|  |  |  |             FD_SET(fd, &wfds); | 
					
						
							|  |  |  |             tv.tv_sec = 0; | 
					
						
							|  |  |  |             tv.tv_usec = 100 * 1000; | 
					
						
							|  |  |  |             ret = select(fd_max + 1, NULL, &wfds, NULL, &tv); | 
					
						
							|  |  |  |             if (ret > 0 && FD_ISSET(fd, &wfds)) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |         /* test error */ | 
					
						
							|  |  |  |         optlen = sizeof(ret); | 
					
						
							|  |  |  |         getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen); | 
					
						
							|  |  |  |         if (ret != 0) | 
					
						
							|  |  |  |             goto fail; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-08-23 18:46:30 +00:00
										 |  |  |     s = av_malloc(sizeof(TCPContext)); | 
					
						
							|  |  |  |     if (!s) | 
					
						
							|  |  |  |         return AVERROR(ENOMEM); | 
					
						
							|  |  |  |     h->priv_data = s; | 
					
						
							|  |  |  |     h->is_streamed = 1; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     s->fd = fd; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  fail: | 
					
						
							| 
									
										
										
										
											2007-07-19 15:23:32 +00:00
										 |  |  |     ret = AVERROR(EIO); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |  fail1: | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     if (fd >= 0) | 
					
						
							| 
									
										
										
										
											2007-01-18 17:22:30 +00:00
										 |  |  |         closesocket(fd); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  | static int tcp_read(URLContext *h, uint8_t *buf, int size) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     TCPContext *s = h->priv_data; | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |     int len, fd_max, ret; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |     fd_set rfds; | 
					
						
							|  |  |  |     struct timeval tv; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-14 02:59:33 +00:00
										 |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |         if (url_interrupt_cb()) | 
					
						
							| 
									
										
										
										
											2007-02-13 18:26:14 +00:00
										 |  |  |             return AVERROR(EINTR); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |         fd_max = s->fd; | 
					
						
							|  |  |  |         FD_ZERO(&rfds); | 
					
						
							|  |  |  |         FD_SET(s->fd, &rfds); | 
					
						
							|  |  |  |         tv.tv_sec = 0; | 
					
						
							|  |  |  |         tv.tv_usec = 100 * 1000; | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |         ret = select(fd_max + 1, &rfds, NULL, NULL, &tv); | 
					
						
							|  |  |  |         if (ret > 0 && FD_ISSET(s->fd, &rfds)) { | 
					
						
							|  |  |  |             len = recv(s->fd, buf, size, 0); | 
					
						
							|  |  |  |             if (len < 0) { | 
					
						
							| 
									
										
										
										
											2007-04-27 00:35:54 +00:00
										 |  |  |                 if (ff_neterrno() != FF_NETERROR(EINTR) && | 
					
						
							|  |  |  |                     ff_neterrno() != FF_NETERROR(EAGAIN)) | 
					
						
							| 
									
										
										
										
											2007-02-13 18:26:14 +00:00
										 |  |  |                     return AVERROR(errno); | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |             } else return len; | 
					
						
							|  |  |  |         } else if (ret < 0) { | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-11 16:35:48 +00:00
										 |  |  | static int tcp_write(URLContext *h, uint8_t *buf, int size) | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     TCPContext *s = h->priv_data; | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |     int ret, size1, fd_max, len; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |     fd_set wfds; | 
					
						
							|  |  |  |     struct timeval tv; | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     size1 = size; | 
					
						
							|  |  |  |     while (size > 0) { | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |         if (url_interrupt_cb()) | 
					
						
							| 
									
										
										
										
											2007-02-13 18:26:14 +00:00
										 |  |  |             return AVERROR(EINTR); | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |         fd_max = s->fd; | 
					
						
							|  |  |  |         FD_ZERO(&wfds); | 
					
						
							|  |  |  |         FD_SET(s->fd, &wfds); | 
					
						
							|  |  |  |         tv.tv_sec = 0; | 
					
						
							|  |  |  |         tv.tv_usec = 100 * 1000; | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |         ret = select(fd_max + 1, NULL, &wfds, NULL, &tv); | 
					
						
							|  |  |  |         if (ret > 0 && FD_ISSET(s->fd, &wfds)) { | 
					
						
							|  |  |  |             len = send(s->fd, buf, size, 0); | 
					
						
							|  |  |  |             if (len < 0) { | 
					
						
							| 
									
										
										
										
											2007-04-27 00:35:54 +00:00
										 |  |  |                 if (ff_neterrno() != FF_NETERROR(EINTR) && | 
					
						
							|  |  |  |                     ff_neterrno() != FF_NETERROR(EAGAIN)) | 
					
						
							| 
									
										
										
										
											2007-02-13 18:26:14 +00:00
										 |  |  |                     return AVERROR(errno); | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |                 continue; | 
					
						
							| 
									
										
										
										
											2003-09-29 01:41:30 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |             size -= len; | 
					
						
							|  |  |  |             buf += len; | 
					
						
							|  |  |  |         } else if (ret < 0) { | 
					
						
							|  |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2003-09-29 01:41:30 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     return size1 - size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int tcp_close(URLContext *h) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     TCPContext *s = h->priv_data; | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  |     closesocket(s->fd); | 
					
						
							| 
									
										
										
										
											2007-08-09 23:39:05 +00:00
										 |  |  |     ff_network_close(); | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     av_free(s); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | URLProtocol tcp_protocol = { | 
					
						
							|  |  |  |     "tcp", | 
					
						
							|  |  |  |     tcp_open, | 
					
						
							|  |  |  |     tcp_read, | 
					
						
							|  |  |  |     tcp_write, | 
					
						
							|  |  |  |     NULL, /* seek */ | 
					
						
							|  |  |  |     tcp_close, | 
					
						
							|  |  |  | }; |