| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * TCP protocol | 
					
						
							|  |  |  |  * Copyright (c) 2002 Fabrice Bellard. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							|  |  |  |  * version 2 of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * 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 | 
					
						
							|  |  |  |  * License along with this library; if not, write to the Free Software | 
					
						
							|  |  |  |  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #include "avformat.h"
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <sys/types.h>
 | 
					
						
							| 
									
										
										
										
											2002-11-10 11:46:59 +00:00
										 |  |  | #include <sys/socket.h>
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | #include <netinet/in.h>
 | 
					
						
							| 
									
										
										
										
											2005-05-09 10:48:12 +00:00
										 |  |  | #if defined(__BEOS__)
 | 
					
						
							| 
									
										
										
										
											2003-07-24 13:30:27 +00:00
										 |  |  | typedef int socklen_t; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #ifndef __BEOS__
 | 
					
						
							|  |  |  | # include <arpa/inet.h>
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | # include "barpainet.h"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | #include <netdb.h>
 | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  | #include <sys/time.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef struct TCPContext { | 
					
						
							|  |  |  |     int fd; | 
					
						
							|  |  |  | } TCPContext; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* resolve host with also IP address parsing */ | 
					
						
							|  |  |  | int resolve_host(struct in_addr *sin_addr, const char *hostname) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct hostent *hp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((inet_aton(hostname, sin_addr)) == 0) { | 
					
						
							|  |  |  |         hp = gethostbyname(hostname); | 
					
						
							|  |  |  |         if (!hp) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         memcpy (sin_addr, hp->h_addr, sizeof(struct in_addr)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* return non zero if error */ | 
					
						
							|  |  |  | static int tcp_open(URLContext *h, const char *uri, int flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct sockaddr_in dest_addr; | 
					
						
							|  |  |  |     char hostname[1024], *q; | 
					
						
							|  |  |  |     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; | 
					
						
							| 
									
										
										
										
											2004-08-12 00:09:32 +00:00
										 |  |  |     char proto[1024],path[1024],tmp[1024];  // PETR: protocol and path strings
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), | 
					
						
							|  |  |  |       &port, path, sizeof(path), uri);  // PETR: use url_split
 | 
					
						
							|  |  |  |     if (strcmp(proto,"tcp")) goto fail; // PETR: check protocol
 | 
					
						
							|  |  |  |     if ((q = strchr(hostname,'@'))) { strcpy(tmp,q+1); strcpy(hostname,tmp); } // PETR: take only the part after '@' for tcp protocol
 | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     s = av_malloc(sizeof(TCPContext)); | 
					
						
							|  |  |  |     if (!s) | 
					
						
							|  |  |  |         return -ENOMEM; | 
					
						
							|  |  |  |     h->priv_data = s; | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     if (port <= 0 || port >= 65536) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = socket(PF_INET, SOCK_STREAM, 0); | 
					
						
							|  |  |  |     if (fd < 0) | 
					
						
							|  |  |  |         goto fail; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |     fcntl(fd, F_SETFL, O_NONBLOCK); | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  |         if (errno == EINTR) | 
					
						
							|  |  |  |             goto redo; | 
					
						
							|  |  |  |         if (errno != EINPROGRESS) | 
					
						
							|  |  |  |             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()) { | 
					
						
							|  |  |  |                 ret = -EINTR; | 
					
						
							|  |  |  |                 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; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     s->fd = fd; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  fail: | 
					
						
							| 
									
										
										
										
											2004-06-19 03:59:34 +00:00
										 |  |  |     ret = AVERROR_IO; | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  |  fail1: | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     if (fd >= 0) | 
					
						
							|  |  |  |         close(fd); | 
					
						
							|  |  |  |     av_free(s); | 
					
						
							| 
									
										
										
										
											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()) | 
					
						
							|  |  |  |             return -EINTR; | 
					
						
							|  |  |  |         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)) { | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  | #ifdef __BEOS__
 | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |             len = recv(s->fd, buf, size, 0); | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |             len = read(s->fd, buf, size); | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |             if (len < 0) { | 
					
						
							|  |  |  |                 if (errno != EINTR && errno != EAGAIN) | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #ifdef __BEOS__
 | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |                     return errno; | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |                     return -errno; | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											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()) | 
					
						
							|  |  |  |             return -EINTR; | 
					
						
							|  |  |  |         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)) { | 
					
						
							| 
									
										
										
										
											2003-07-17 10:28:27 +00:00
										 |  |  | #ifdef __BEOS__
 | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |             len = send(s->fd, buf, size, 0); | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |             len = write(s->fd, buf, size); | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |             if (len < 0) { | 
					
						
							|  |  |  |                 if (errno != EINTR && errno != EAGAIN) { | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #ifdef __BEOS__
 | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |                     return errno; | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2004-03-14 19:40:43 +00:00
										 |  |  |                     return -errno; | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | #ifdef CONFIG_BEOS_NETSERVER
 | 
					
						
							|  |  |  |     closesocket(s->fd); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2002-07-04 10:35:45 +00:00
										 |  |  |     close(s->fd); | 
					
						
							| 
									
										
										
										
											2002-11-02 10:35:07 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							|  |  |  | }; |