yading@11
|
1 /*
|
yading@11
|
2 * various OS-feature replacement utilities
|
yading@11
|
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
|
yading@11
|
4 * copyright (c) 2002 Francois Revol
|
yading@11
|
5 *
|
yading@11
|
6 * This file is part of FFmpeg.
|
yading@11
|
7 *
|
yading@11
|
8 * FFmpeg is free software; you can redistribute it and/or
|
yading@11
|
9 * modify it under the terms of the GNU Lesser General Public
|
yading@11
|
10 * License as published by the Free Software Foundation; either
|
yading@11
|
11 * version 2.1 of the License, or (at your option) any later version.
|
yading@11
|
12 *
|
yading@11
|
13 * FFmpeg is distributed in the hope that it will be useful,
|
yading@11
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@11
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@11
|
16 * Lesser General Public License for more details.
|
yading@11
|
17 *
|
yading@11
|
18 * You should have received a copy of the GNU Lesser General Public
|
yading@11
|
19 * License along with FFmpeg; if not, write to the Free Software
|
yading@11
|
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@11
|
21 */
|
yading@11
|
22
|
yading@11
|
23 /* needed by inet_aton() */
|
yading@11
|
24 #define _SVID_SOURCE
|
yading@11
|
25
|
yading@11
|
26 #include "config.h"
|
yading@11
|
27 #include "avformat.h"
|
yading@11
|
28 #include "os_support.h"
|
yading@11
|
29
|
yading@11
|
30 #if defined(_WIN32) && !defined(__MINGW32CE__)
|
yading@11
|
31 #undef open
|
yading@11
|
32 #undef lseek
|
yading@11
|
33 #undef stat
|
yading@11
|
34 #undef fstat
|
yading@11
|
35 #include <fcntl.h>
|
yading@11
|
36 #include <io.h>
|
yading@11
|
37 #include <windows.h>
|
yading@11
|
38 #include <share.h>
|
yading@11
|
39 #include <errno.h>
|
yading@11
|
40
|
yading@11
|
41 int ff_win32_open(const char *filename_utf8, int oflag, int pmode)
|
yading@11
|
42 {
|
yading@11
|
43 int fd;
|
yading@11
|
44 int num_chars;
|
yading@11
|
45 wchar_t *filename_w;
|
yading@11
|
46
|
yading@11
|
47 /* convert UTF-8 to wide chars */
|
yading@11
|
48 num_chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename_utf8, -1, NULL, 0);
|
yading@11
|
49 if (num_chars <= 0)
|
yading@11
|
50 goto fallback;
|
yading@11
|
51 filename_w = av_mallocz(sizeof(wchar_t) * num_chars);
|
yading@11
|
52 if (!filename_w) {
|
yading@11
|
53 errno = ENOMEM;
|
yading@11
|
54 return -1;
|
yading@11
|
55 }
|
yading@11
|
56 MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, filename_w, num_chars);
|
yading@11
|
57
|
yading@11
|
58 fd = _wsopen(filename_w, oflag, SH_DENYNO, pmode);
|
yading@11
|
59 av_freep(&filename_w);
|
yading@11
|
60
|
yading@11
|
61 if (fd != -1 || (oflag & O_CREAT))
|
yading@11
|
62 return fd;
|
yading@11
|
63
|
yading@11
|
64 fallback:
|
yading@11
|
65 /* filename may be be in CP_ACP */
|
yading@11
|
66 return _sopen(filename_utf8, oflag, SH_DENYNO, pmode);
|
yading@11
|
67 }
|
yading@11
|
68 #endif
|
yading@11
|
69
|
yading@11
|
70 #if CONFIG_NETWORK
|
yading@11
|
71 #include <fcntl.h>
|
yading@11
|
72 #if !HAVE_POLL_H
|
yading@11
|
73 #if HAVE_SYS_TIME_H
|
yading@11
|
74 #include <sys/time.h>
|
yading@11
|
75 #endif
|
yading@11
|
76 #if HAVE_WINSOCK2_H
|
yading@11
|
77 #include <winsock2.h>
|
yading@11
|
78 #elif HAVE_SYS_SELECT_H
|
yading@11
|
79 #include <sys/select.h>
|
yading@11
|
80 #endif
|
yading@11
|
81 #endif
|
yading@11
|
82
|
yading@11
|
83 #include "network.h"
|
yading@11
|
84
|
yading@11
|
85 #if !HAVE_INET_ATON
|
yading@11
|
86 #include <stdlib.h>
|
yading@11
|
87
|
yading@11
|
88 int ff_inet_aton(const char *str, struct in_addr *add)
|
yading@11
|
89 {
|
yading@11
|
90 unsigned int add1 = 0, add2 = 0, add3 = 0, add4 = 0;
|
yading@11
|
91
|
yading@11
|
92 if (sscanf(str, "%d.%d.%d.%d", &add1, &add2, &add3, &add4) != 4)
|
yading@11
|
93 return 0;
|
yading@11
|
94
|
yading@11
|
95 if (!add1 || (add1 | add2 | add3 | add4) > 255)
|
yading@11
|
96 return 0;
|
yading@11
|
97
|
yading@11
|
98 add->s_addr = htonl((add1 << 24) + (add2 << 16) + (add3 << 8) + add4);
|
yading@11
|
99
|
yading@11
|
100 return 1;
|
yading@11
|
101 }
|
yading@11
|
102 #else
|
yading@11
|
103 int ff_inet_aton(const char *str, struct in_addr *add)
|
yading@11
|
104 {
|
yading@11
|
105 return inet_aton(str, add);
|
yading@11
|
106 }
|
yading@11
|
107 #endif /* !HAVE_INET_ATON */
|
yading@11
|
108
|
yading@11
|
109 #if !HAVE_GETADDRINFO
|
yading@11
|
110 int ff_getaddrinfo(const char *node, const char *service,
|
yading@11
|
111 const struct addrinfo *hints, struct addrinfo **res)
|
yading@11
|
112 {
|
yading@11
|
113 struct hostent *h = NULL;
|
yading@11
|
114 struct addrinfo *ai;
|
yading@11
|
115 struct sockaddr_in *sin;
|
yading@11
|
116
|
yading@11
|
117 #if HAVE_WINSOCK2_H
|
yading@11
|
118 int (WSAAPI *win_getaddrinfo)(const char *node, const char *service,
|
yading@11
|
119 const struct addrinfo *hints,
|
yading@11
|
120 struct addrinfo **res);
|
yading@11
|
121 HMODULE ws2mod = GetModuleHandle("ws2_32.dll");
|
yading@11
|
122 win_getaddrinfo = GetProcAddress(ws2mod, "getaddrinfo");
|
yading@11
|
123 if (win_getaddrinfo)
|
yading@11
|
124 return win_getaddrinfo(node, service, hints, res);
|
yading@11
|
125 #endif
|
yading@11
|
126
|
yading@11
|
127 *res = NULL;
|
yading@11
|
128 sin = av_mallocz(sizeof(struct sockaddr_in));
|
yading@11
|
129 if (!sin)
|
yading@11
|
130 return EAI_FAIL;
|
yading@11
|
131 sin->sin_family = AF_INET;
|
yading@11
|
132
|
yading@11
|
133 if (node) {
|
yading@11
|
134 if (!ff_inet_aton(node, &sin->sin_addr)) {
|
yading@11
|
135 if (hints && (hints->ai_flags & AI_NUMERICHOST)) {
|
yading@11
|
136 av_free(sin);
|
yading@11
|
137 return EAI_FAIL;
|
yading@11
|
138 }
|
yading@11
|
139 h = gethostbyname(node);
|
yading@11
|
140 if (!h) {
|
yading@11
|
141 av_free(sin);
|
yading@11
|
142 return EAI_FAIL;
|
yading@11
|
143 }
|
yading@11
|
144 memcpy(&sin->sin_addr, h->h_addr_list[0], sizeof(struct in_addr));
|
yading@11
|
145 }
|
yading@11
|
146 } else {
|
yading@11
|
147 if (hints && (hints->ai_flags & AI_PASSIVE))
|
yading@11
|
148 sin->sin_addr.s_addr = INADDR_ANY;
|
yading@11
|
149 else
|
yading@11
|
150 sin->sin_addr.s_addr = INADDR_LOOPBACK;
|
yading@11
|
151 }
|
yading@11
|
152
|
yading@11
|
153 /* Note: getaddrinfo allows service to be a string, which
|
yading@11
|
154 * should be looked up using getservbyname. */
|
yading@11
|
155 if (service)
|
yading@11
|
156 sin->sin_port = htons(atoi(service));
|
yading@11
|
157
|
yading@11
|
158 ai = av_mallocz(sizeof(struct addrinfo));
|
yading@11
|
159 if (!ai) {
|
yading@11
|
160 av_free(sin);
|
yading@11
|
161 return EAI_FAIL;
|
yading@11
|
162 }
|
yading@11
|
163
|
yading@11
|
164 *res = ai;
|
yading@11
|
165 ai->ai_family = AF_INET;
|
yading@11
|
166 ai->ai_socktype = hints ? hints->ai_socktype : 0;
|
yading@11
|
167 switch (ai->ai_socktype) {
|
yading@11
|
168 case SOCK_STREAM:
|
yading@11
|
169 ai->ai_protocol = IPPROTO_TCP;
|
yading@11
|
170 break;
|
yading@11
|
171 case SOCK_DGRAM:
|
yading@11
|
172 ai->ai_protocol = IPPROTO_UDP;
|
yading@11
|
173 break;
|
yading@11
|
174 default:
|
yading@11
|
175 ai->ai_protocol = 0;
|
yading@11
|
176 break;
|
yading@11
|
177 }
|
yading@11
|
178
|
yading@11
|
179 ai->ai_addr = (struct sockaddr *)sin;
|
yading@11
|
180 ai->ai_addrlen = sizeof(struct sockaddr_in);
|
yading@11
|
181 if (hints && (hints->ai_flags & AI_CANONNAME))
|
yading@11
|
182 ai->ai_canonname = h ? av_strdup(h->h_name) : NULL;
|
yading@11
|
183
|
yading@11
|
184 ai->ai_next = NULL;
|
yading@11
|
185 return 0;
|
yading@11
|
186 }
|
yading@11
|
187
|
yading@11
|
188 void ff_freeaddrinfo(struct addrinfo *res)
|
yading@11
|
189 {
|
yading@11
|
190 #if HAVE_WINSOCK2_H
|
yading@11
|
191 void (WSAAPI *win_freeaddrinfo)(struct addrinfo *res);
|
yading@11
|
192 HMODULE ws2mod = GetModuleHandle("ws2_32.dll");
|
yading@11
|
193 win_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *res))
|
yading@11
|
194 GetProcAddress(ws2mod, "freeaddrinfo");
|
yading@11
|
195 if (win_freeaddrinfo) {
|
yading@11
|
196 win_freeaddrinfo(res);
|
yading@11
|
197 return;
|
yading@11
|
198 }
|
yading@11
|
199 #endif
|
yading@11
|
200
|
yading@11
|
201 av_free(res->ai_canonname);
|
yading@11
|
202 av_free(res->ai_addr);
|
yading@11
|
203 av_free(res);
|
yading@11
|
204 }
|
yading@11
|
205
|
yading@11
|
206 int ff_getnameinfo(const struct sockaddr *sa, int salen,
|
yading@11
|
207 char *host, int hostlen,
|
yading@11
|
208 char *serv, int servlen, int flags)
|
yading@11
|
209 {
|
yading@11
|
210 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
|
yading@11
|
211
|
yading@11
|
212 #if HAVE_WINSOCK2_H
|
yading@11
|
213 int (WSAAPI *win_getnameinfo)(const struct sockaddr *sa, socklen_t salen,
|
yading@11
|
214 char *host, DWORD hostlen,
|
yading@11
|
215 char *serv, DWORD servlen, int flags);
|
yading@11
|
216 HMODULE ws2mod = GetModuleHandle("ws2_32.dll");
|
yading@11
|
217 win_getnameinfo = GetProcAddress(ws2mod, "getnameinfo");
|
yading@11
|
218 if (win_getnameinfo)
|
yading@11
|
219 return win_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
|
yading@11
|
220 #endif
|
yading@11
|
221
|
yading@11
|
222 if (sa->sa_family != AF_INET)
|
yading@11
|
223 return EAI_FAMILY;
|
yading@11
|
224 if (!host && !serv)
|
yading@11
|
225 return EAI_NONAME;
|
yading@11
|
226
|
yading@11
|
227 if (host && hostlen > 0) {
|
yading@11
|
228 struct hostent *ent = NULL;
|
yading@11
|
229 uint32_t a;
|
yading@11
|
230 if (!(flags & NI_NUMERICHOST))
|
yading@11
|
231 ent = gethostbyaddr((const char *)&sin->sin_addr,
|
yading@11
|
232 sizeof(sin->sin_addr), AF_INET);
|
yading@11
|
233
|
yading@11
|
234 if (ent) {
|
yading@11
|
235 snprintf(host, hostlen, "%s", ent->h_name);
|
yading@11
|
236 } else if (flags & NI_NAMERQD) {
|
yading@11
|
237 return EAI_NONAME;
|
yading@11
|
238 } else {
|
yading@11
|
239 a = ntohl(sin->sin_addr.s_addr);
|
yading@11
|
240 snprintf(host, hostlen, "%d.%d.%d.%d",
|
yading@11
|
241 ((a >> 24) & 0xff), ((a >> 16) & 0xff),
|
yading@11
|
242 ((a >> 8) & 0xff), (a & 0xff));
|
yading@11
|
243 }
|
yading@11
|
244 }
|
yading@11
|
245
|
yading@11
|
246 if (serv && servlen > 0) {
|
yading@11
|
247 struct servent *ent = NULL;
|
yading@11
|
248 #if HAVE_GETSERVBYPORT
|
yading@11
|
249 if (!(flags & NI_NUMERICSERV))
|
yading@11
|
250 ent = getservbyport(sin->sin_port, flags & NI_DGRAM ? "udp" : "tcp");
|
yading@11
|
251 #endif
|
yading@11
|
252
|
yading@11
|
253 if (ent)
|
yading@11
|
254 snprintf(serv, servlen, "%s", ent->s_name);
|
yading@11
|
255 else
|
yading@11
|
256 snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
|
yading@11
|
257 }
|
yading@11
|
258
|
yading@11
|
259 return 0;
|
yading@11
|
260 }
|
yading@11
|
261 #endif /* !HAVE_GETADDRINFO */
|
yading@11
|
262
|
yading@11
|
263 #if !HAVE_GETADDRINFO || HAVE_WINSOCK2_H
|
yading@11
|
264 const char *ff_gai_strerror(int ecode)
|
yading@11
|
265 {
|
yading@11
|
266 switch (ecode) {
|
yading@11
|
267 case EAI_AGAIN:
|
yading@11
|
268 return "Temporary failure in name resolution";
|
yading@11
|
269 case EAI_BADFLAGS:
|
yading@11
|
270 return "Invalid flags for ai_flags";
|
yading@11
|
271 case EAI_FAIL:
|
yading@11
|
272 return "A non-recoverable error occurred";
|
yading@11
|
273 case EAI_FAMILY:
|
yading@11
|
274 return "The address family was not recognized or the address "
|
yading@11
|
275 "length was invalid for the specified family";
|
yading@11
|
276 case EAI_MEMORY:
|
yading@11
|
277 return "Memory allocation failure";
|
yading@11
|
278 #if EAI_NODATA != EAI_NONAME
|
yading@11
|
279 case EAI_NODATA:
|
yading@11
|
280 return "No address associated with hostname";
|
yading@11
|
281 #endif
|
yading@11
|
282 case EAI_NONAME:
|
yading@11
|
283 return "The name does not resolve for the supplied parameters";
|
yading@11
|
284 case EAI_SERVICE:
|
yading@11
|
285 return "servname not supported for ai_socktype";
|
yading@11
|
286 case EAI_SOCKTYPE:
|
yading@11
|
287 return "ai_socktype not supported";
|
yading@11
|
288 }
|
yading@11
|
289
|
yading@11
|
290 return "Unknown error";
|
yading@11
|
291 }
|
yading@11
|
292 #endif /* !HAVE_GETADDRINFO || HAVE_WINSOCK2_H */
|
yading@11
|
293
|
yading@11
|
294 int ff_socket_nonblock(int socket, int enable)
|
yading@11
|
295 {
|
yading@11
|
296 #if HAVE_WINSOCK2_H
|
yading@11
|
297 u_long param = enable;
|
yading@11
|
298 return ioctlsocket(socket, FIONBIO, ¶m);
|
yading@11
|
299 #else
|
yading@11
|
300 if (enable)
|
yading@11
|
301 return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK);
|
yading@11
|
302 else
|
yading@11
|
303 return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK);
|
yading@11
|
304 #endif
|
yading@11
|
305 }
|
yading@11
|
306
|
yading@11
|
307 #if !HAVE_POLL_H
|
yading@11
|
308 int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout)
|
yading@11
|
309 {
|
yading@11
|
310 fd_set read_set;
|
yading@11
|
311 fd_set write_set;
|
yading@11
|
312 fd_set exception_set;
|
yading@11
|
313 nfds_t i;
|
yading@11
|
314 int n;
|
yading@11
|
315 int rc;
|
yading@11
|
316
|
yading@11
|
317 #if HAVE_WINSOCK2_H
|
yading@11
|
318 if (numfds >= FD_SETSIZE) {
|
yading@11
|
319 errno = EINVAL;
|
yading@11
|
320 return -1;
|
yading@11
|
321 }
|
yading@11
|
322 #endif
|
yading@11
|
323
|
yading@11
|
324 FD_ZERO(&read_set);
|
yading@11
|
325 FD_ZERO(&write_set);
|
yading@11
|
326 FD_ZERO(&exception_set);
|
yading@11
|
327
|
yading@11
|
328 n = 0;
|
yading@11
|
329 for (i = 0; i < numfds; i++) {
|
yading@11
|
330 if (fds[i].fd < 0)
|
yading@11
|
331 continue;
|
yading@11
|
332 #if !HAVE_WINSOCK2_H
|
yading@11
|
333 if (fds[i].fd >= FD_SETSIZE) {
|
yading@11
|
334 errno = EINVAL;
|
yading@11
|
335 return -1;
|
yading@11
|
336 }
|
yading@11
|
337 #endif
|
yading@11
|
338
|
yading@11
|
339 if (fds[i].events & POLLIN)
|
yading@11
|
340 FD_SET(fds[i].fd, &read_set);
|
yading@11
|
341 if (fds[i].events & POLLOUT)
|
yading@11
|
342 FD_SET(fds[i].fd, &write_set);
|
yading@11
|
343 if (fds[i].events & POLLERR)
|
yading@11
|
344 FD_SET(fds[i].fd, &exception_set);
|
yading@11
|
345
|
yading@11
|
346 if (fds[i].fd >= n)
|
yading@11
|
347 n = fds[i].fd + 1;
|
yading@11
|
348 }
|
yading@11
|
349
|
yading@11
|
350 if (n == 0)
|
yading@11
|
351 /* Hey!? Nothing to poll, in fact!!! */
|
yading@11
|
352 return 0;
|
yading@11
|
353
|
yading@11
|
354 if (timeout < 0) {
|
yading@11
|
355 rc = select(n, &read_set, &write_set, &exception_set, NULL);
|
yading@11
|
356 } else {
|
yading@11
|
357 struct timeval tv;
|
yading@11
|
358 tv.tv_sec = timeout / 1000;
|
yading@11
|
359 tv.tv_usec = 1000 * (timeout % 1000);
|
yading@11
|
360 rc = select(n, &read_set, &write_set, &exception_set, &tv);
|
yading@11
|
361 }
|
yading@11
|
362
|
yading@11
|
363 if (rc < 0)
|
yading@11
|
364 return rc;
|
yading@11
|
365
|
yading@11
|
366 for (i = 0; i < numfds; i++) {
|
yading@11
|
367 fds[i].revents = 0;
|
yading@11
|
368
|
yading@11
|
369 if (FD_ISSET(fds[i].fd, &read_set))
|
yading@11
|
370 fds[i].revents |= POLLIN;
|
yading@11
|
371 if (FD_ISSET(fds[i].fd, &write_set))
|
yading@11
|
372 fds[i].revents |= POLLOUT;
|
yading@11
|
373 if (FD_ISSET(fds[i].fd, &exception_set))
|
yading@11
|
374 fds[i].revents |= POLLERR;
|
yading@11
|
375 }
|
yading@11
|
376
|
yading@11
|
377 return rc;
|
yading@11
|
378 }
|
yading@11
|
379 #endif /* HAVE_POLL_H */
|
yading@11
|
380 #endif /* CONFIG_NETWORK */
|