d4b81c88e99310d3ac97434d742b26d46724b5f0
[libav.git] / libavformat / tcp.c
1 /*
2 * TCP protocol
3 * Copyright (c) 2002 Fabrice Bellard.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include "avformat.h"
20 #include <unistd.h>
21 #include <ctype.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #ifndef __BEOS__
26 # include <arpa/inet.h>
27 #else
28 # include "barpainet.h"
29 #endif
30 #include <netdb.h>
31 #include <sys/time.h>
32 #include <fcntl.h>
33
34 typedef struct TCPContext {
35 int fd;
36 } TCPContext;
37
38 /* resolve host with also IP address parsing */
39 int resolve_host(struct in_addr *sin_addr, const char *hostname)
40 {
41 struct hostent *hp;
42
43 if ((inet_aton(hostname, sin_addr)) == 0) {
44 hp = gethostbyname(hostname);
45 if (!hp)
46 return -1;
47 memcpy (sin_addr, hp->h_addr, sizeof(struct in_addr));
48 }
49 return 0;
50 }
51
52 /* return non zero if error */
53 static int tcp_open(URLContext *h, const char *uri, int flags)
54 {
55 struct sockaddr_in dest_addr;
56 char hostname[1024], *q;
57 int port, fd = -1;
58 TCPContext *s;
59 const char *p;
60 fd_set wfds;
61 int fd_max, ret;
62 struct timeval tv;
63 socklen_t optlen;
64
65 s = av_malloc(sizeof(TCPContext));
66 if (!s)
67 return -ENOMEM;
68 h->priv_data = s;
69 p = uri;
70 if (!strstart(p, "tcp://", &p))
71 goto fail;
72 q = hostname;
73 while (*p != ':' && *p != '/' && *p != '\0') {
74 if ((q - hostname) < sizeof(hostname) - 1)
75 *q++ = *p;
76 p++;
77 }
78 *q = '\0';
79 if (*p != ':')
80 goto fail;
81 p++;
82 port = strtoul(p, (char **)&p, 10);
83 if (port <= 0 || port >= 65536)
84 goto fail;
85
86 dest_addr.sin_family = AF_INET;
87 dest_addr.sin_port = htons(port);
88 if (resolve_host(&dest_addr.sin_addr, hostname) < 0)
89 goto fail;
90
91 fd = socket(PF_INET, SOCK_STREAM, 0);
92 if (fd < 0)
93 goto fail;
94 fcntl(fd, F_SETFL, O_NONBLOCK);
95
96 redo:
97 ret = connect(fd, (struct sockaddr *)&dest_addr,
98 sizeof(dest_addr));
99 if (ret < 0) {
100 if (errno == EINTR)
101 goto redo;
102 if (errno != EINPROGRESS)
103 goto fail;
104
105 /* wait until we are connected or until abort */
106 for(;;) {
107 if (url_interrupt_cb()) {
108 ret = -EINTR;
109 goto fail1;
110 }
111 fd_max = fd;
112 FD_ZERO(&wfds);
113 FD_SET(fd, &wfds);
114 tv.tv_sec = 0;
115 tv.tv_usec = 100 * 1000;
116 ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
117 if (ret > 0 && FD_ISSET(fd, &wfds))
118 break;
119 }
120
121 /* test error */
122 optlen = sizeof(ret);
123 getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
124 if (ret != 0)
125 goto fail;
126 }
127 s->fd = fd;
128 return 0;
129
130 fail:
131 ret = -EIO;
132 fail1:
133 if (fd >= 0)
134 close(fd);
135 av_free(s);
136 return ret;
137 }
138
139 static int tcp_read(URLContext *h, uint8_t *buf, int size)
140 {
141 TCPContext *s = h->priv_data;
142 int size1, len, fd_max;
143 fd_set rfds;
144 struct timeval tv;
145
146 size1 = size;
147 while (size > 0) {
148 if (url_interrupt_cb())
149 return -EINTR;
150 fd_max = s->fd;
151 FD_ZERO(&rfds);
152 FD_SET(s->fd, &rfds);
153 tv.tv_sec = 0;
154 tv.tv_usec = 100 * 1000;
155 select(fd_max + 1, &rfds, NULL, NULL, &tv);
156 #ifdef __BEOS__
157 len = recv(s->fd, buf, size, 0);
158 #else
159 len = read(s->fd, buf, size);
160 #endif
161 if (len < 0) {
162 if (errno != EINTR && errno != EAGAIN)
163 #ifdef __BEOS__
164 return errno;
165 #else
166 return -errno;
167 #endif
168 else
169 continue;
170 } else if (len == 0) {
171 break;
172 }
173 size -= len;
174 buf += len;
175 }
176 return size1 - size;
177 }
178
179 static int tcp_write(URLContext *h, uint8_t *buf, int size)
180 {
181 TCPContext *s = h->priv_data;
182 int ret, size1, fd_max;
183 fd_set wfds;
184 struct timeval tv;
185
186 size1 = size;
187 while (size > 0) {
188 if (url_interrupt_cb())
189 return -EINTR;
190 fd_max = s->fd;
191 FD_ZERO(&wfds);
192 FD_SET(s->fd, &wfds);
193 tv.tv_sec = 0;
194 tv.tv_usec = 100 * 1000;
195 select(fd_max + 1, NULL, &wfds, NULL, &tv);
196 #ifdef __BEOS__
197 ret = send(s->fd, buf, size, 0);
198 #else
199 ret = write(s->fd, buf, size);
200 #endif
201 if (ret < 0 && errno != EINTR && errno != EAGAIN)
202 #ifdef __BEOS__
203 return errno;
204 #else
205 return -errno;
206 #endif
207 size -= ret;
208 buf += ret;
209 }
210 return size1 - size;
211 }
212
213 static int tcp_close(URLContext *h)
214 {
215 TCPContext *s = h->priv_data;
216 #ifdef CONFIG_BEOS_NETSERVER
217 closesocket(s->fd);
218 #else
219 close(s->fd);
220 #endif
221 av_free(s);
222 return 0;
223 }
224
225 URLProtocol tcp_protocol = {
226 "tcp",
227 tcp_open,
228 tcp_read,
229 tcp_write,
230 NULL, /* seek */
231 tcp_close,
232 };