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