| 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 "avformat.h" |
| 29 | #include "os_support.h" |
| 30 | |
| 31 | #if CONFIG_NETWORK |
| 32 | #include <fcntl.h> |
| 33 | #if !HAVE_POLL_H |
| 34 | #if HAVE_SYS_TIME_H |
| 35 | #include <sys/time.h> |
| 36 | #endif /* HAVE_SYS_TIME_H */ |
| 37 | #if HAVE_WINSOCK2_H |
| 38 | #include <winsock2.h> |
| 39 | #elif HAVE_SYS_SELECT_H |
| 40 | #include <sys/select.h> |
| 41 | #endif /* HAVE_WINSOCK2_H */ |
| 42 | #endif /* !HAVE_POLL_H */ |
| 43 | |
| 44 | #include "network.h" |
| 45 | |
| 46 | #if !HAVE_INET_ATON |
| 47 | #include <stdlib.h> |
| 48 | |
| 49 | int ff_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 | #else |
| 64 | int ff_inet_aton(const char *str, struct in_addr *add) |
| 65 | { |
| 66 | return inet_aton(str, add); |
| 67 | } |
| 68 | #endif /* !HAVE_INET_ATON */ |
| 69 | |
| 70 | #if !HAVE_GETADDRINFO |
| 71 | int ff_getaddrinfo(const char *node, const char *service, |
| 72 | const struct addrinfo *hints, struct addrinfo **res) |
| 73 | { |
| 74 | struct hostent *h = NULL; |
| 75 | struct addrinfo *ai; |
| 76 | struct sockaddr_in *sin; |
| 77 | |
| 78 | #if HAVE_WINSOCK2_H |
| 79 | int (WSAAPI *win_getaddrinfo)(const char *node, const char *service, |
| 80 | const struct addrinfo *hints, |
| 81 | struct addrinfo **res); |
| 82 | HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); |
| 83 | win_getaddrinfo = GetProcAddress(ws2mod, "getaddrinfo"); |
| 84 | if (win_getaddrinfo) |
| 85 | return win_getaddrinfo(node, service, hints, res); |
| 86 | #endif /* HAVE_WINSOCK2_H */ |
| 87 | |
| 88 | *res = NULL; |
| 89 | sin = av_mallocz(sizeof(struct sockaddr_in)); |
| 90 | if (!sin) |
| 91 | return EAI_FAIL; |
| 92 | sin->sin_family = AF_INET; |
| 93 | |
| 94 | if (node) { |
| 95 | if (!ff_inet_aton(node, &sin->sin_addr)) { |
| 96 | if (hints && (hints->ai_flags & AI_NUMERICHOST)) { |
| 97 | av_free(sin); |
| 98 | return EAI_FAIL; |
| 99 | } |
| 100 | h = gethostbyname(node); |
| 101 | if (!h) { |
| 102 | av_free(sin); |
| 103 | return EAI_FAIL; |
| 104 | } |
| 105 | memcpy(&sin->sin_addr, h->h_addr_list[0], sizeof(struct in_addr)); |
| 106 | } |
| 107 | } else { |
| 108 | if (hints && (hints->ai_flags & AI_PASSIVE)) |
| 109 | sin->sin_addr.s_addr = INADDR_ANY; |
| 110 | else |
| 111 | sin->sin_addr.s_addr = INADDR_LOOPBACK; |
| 112 | } |
| 113 | |
| 114 | /* Note: getaddrinfo allows service to be a string, which |
| 115 | * should be looked up using getservbyname. */ |
| 116 | if (service) |
| 117 | sin->sin_port = htons(atoi(service)); |
| 118 | |
| 119 | ai = av_mallocz(sizeof(struct addrinfo)); |
| 120 | if (!ai) { |
| 121 | av_free(sin); |
| 122 | return EAI_FAIL; |
| 123 | } |
| 124 | |
| 125 | *res = ai; |
| 126 | ai->ai_family = AF_INET; |
| 127 | ai->ai_socktype = hints ? hints->ai_socktype : 0; |
| 128 | switch (ai->ai_socktype) { |
| 129 | case SOCK_STREAM: |
| 130 | ai->ai_protocol = IPPROTO_TCP; |
| 131 | break; |
| 132 | case SOCK_DGRAM: |
| 133 | ai->ai_protocol = IPPROTO_UDP; |
| 134 | break; |
| 135 | default: |
| 136 | ai->ai_protocol = 0; |
| 137 | break; |
| 138 | } |
| 139 | |
| 140 | ai->ai_addr = (struct sockaddr *)sin; |
| 141 | ai->ai_addrlen = sizeof(struct sockaddr_in); |
| 142 | if (hints && (hints->ai_flags & AI_CANONNAME)) |
| 143 | ai->ai_canonname = h ? av_strdup(h->h_name) : NULL; |
| 144 | |
| 145 | ai->ai_next = NULL; |
| 146 | return 0; |
| 147 | } |
| 148 | |
| 149 | void ff_freeaddrinfo(struct addrinfo *res) |
| 150 | { |
| 151 | #if HAVE_WINSOCK2_H |
| 152 | void (WSAAPI *win_freeaddrinfo)(struct addrinfo *res); |
| 153 | HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); |
| 154 | win_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *res)) |
| 155 | GetProcAddress(ws2mod, "freeaddrinfo"); |
| 156 | if (win_freeaddrinfo) { |
| 157 | win_freeaddrinfo(res); |
| 158 | return; |
| 159 | } |
| 160 | #endif /* HAVE_WINSOCK2_H */ |
| 161 | |
| 162 | av_free(res->ai_canonname); |
| 163 | av_free(res->ai_addr); |
| 164 | av_free(res); |
| 165 | } |
| 166 | |
| 167 | int ff_getnameinfo(const struct sockaddr *sa, int salen, |
| 168 | char *host, int hostlen, |
| 169 | char *serv, int servlen, int flags) |
| 170 | { |
| 171 | const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; |
| 172 | |
| 173 | #if HAVE_WINSOCK2_H |
| 174 | int (WSAAPI *win_getnameinfo)(const struct sockaddr *sa, socklen_t salen, |
| 175 | char *host, DWORD hostlen, |
| 176 | char *serv, DWORD servlen, int flags); |
| 177 | HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); |
| 178 | win_getnameinfo = GetProcAddress(ws2mod, "getnameinfo"); |
| 179 | if (win_getnameinfo) |
| 180 | return win_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); |
| 181 | #endif /* HAVE_WINSOCK2_H */ |
| 182 | |
| 183 | if (sa->sa_family != AF_INET) |
| 184 | return EAI_FAMILY; |
| 185 | if (!host && !serv) |
| 186 | return EAI_NONAME; |
| 187 | |
| 188 | if (host && hostlen > 0) { |
| 189 | struct hostent *ent = NULL; |
| 190 | uint32_t a; |
| 191 | if (!(flags & NI_NUMERICHOST)) |
| 192 | ent = gethostbyaddr((const char *)&sin->sin_addr, |
| 193 | sizeof(sin->sin_addr), AF_INET); |
| 194 | |
| 195 | if (ent) { |
| 196 | snprintf(host, hostlen, "%s", ent->h_name); |
| 197 | } else if (flags & NI_NAMERQD) { |
| 198 | return EAI_NONAME; |
| 199 | } else { |
| 200 | a = ntohl(sin->sin_addr.s_addr); |
| 201 | snprintf(host, hostlen, "%d.%d.%d.%d", |
| 202 | ((a >> 24) & 0xff), ((a >> 16) & 0xff), |
| 203 | ((a >> 8) & 0xff), (a & 0xff)); |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | if (serv && servlen > 0) { |
| 208 | struct servent *ent = NULL; |
| 209 | #if HAVE_GETSERVBYPORT |
| 210 | if (!(flags & NI_NUMERICSERV)) |
| 211 | ent = getservbyport(sin->sin_port, flags & NI_DGRAM ? "udp" : "tcp"); |
| 212 | #endif /* HAVE_GETSERVBYPORT */ |
| 213 | |
| 214 | if (ent) |
| 215 | snprintf(serv, servlen, "%s", ent->s_name); |
| 216 | else |
| 217 | snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); |
| 218 | } |
| 219 | |
| 220 | return 0; |
| 221 | } |
| 222 | #endif /* !HAVE_GETADDRINFO */ |
| 223 | |
| 224 | #if !HAVE_GETADDRINFO || HAVE_WINSOCK2_H |
| 225 | const char *ff_gai_strerror(int ecode) |
| 226 | { |
| 227 | switch (ecode) { |
| 228 | case EAI_AGAIN: |
| 229 | return "Temporary failure in name resolution"; |
| 230 | case EAI_BADFLAGS: |
| 231 | return "Invalid flags for ai_flags"; |
| 232 | case EAI_FAIL: |
| 233 | return "A non-recoverable error occurred"; |
| 234 | case EAI_FAMILY: |
| 235 | return "The address family was not recognized or the address " |
| 236 | "length was invalid for the specified family"; |
| 237 | case EAI_MEMORY: |
| 238 | return "Memory allocation failure"; |
| 239 | #if EAI_NODATA != EAI_NONAME |
| 240 | case EAI_NODATA: |
| 241 | return "No address associated with hostname"; |
| 242 | #endif /* EAI_NODATA != EAI_NONAME */ |
| 243 | case EAI_NONAME: |
| 244 | return "The name does not resolve for the supplied parameters"; |
| 245 | case EAI_SERVICE: |
| 246 | return "servname not supported for ai_socktype"; |
| 247 | case EAI_SOCKTYPE: |
| 248 | return "ai_socktype not supported"; |
| 249 | } |
| 250 | |
| 251 | return "Unknown error"; |
| 252 | } |
| 253 | #endif /* !HAVE_GETADDRINFO || HAVE_WINSOCK2_H */ |
| 254 | |
| 255 | int ff_socket_nonblock(int socket, int enable) |
| 256 | { |
| 257 | #if HAVE_WINSOCK2_H |
| 258 | u_long param = enable; |
| 259 | return ioctlsocket(socket, FIONBIO, ¶m); |
| 260 | #else |
| 261 | if (enable) |
| 262 | return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK); |
| 263 | else |
| 264 | return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK); |
| 265 | #endif /* HAVE_WINSOCK2_H */ |
| 266 | } |
| 267 | |
| 268 | #if !HAVE_POLL_H |
| 269 | int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout) |
| 270 | { |
| 271 | fd_set read_set; |
| 272 | fd_set write_set; |
| 273 | fd_set exception_set; |
| 274 | nfds_t i; |
| 275 | int n; |
| 276 | int rc; |
| 277 | |
| 278 | #if HAVE_WINSOCK2_H |
| 279 | if (numfds >= FD_SETSIZE) { |
| 280 | errno = EINVAL; |
| 281 | return -1; |
| 282 | } |
| 283 | #endif /* HAVE_WINSOCK2_H */ |
| 284 | |
| 285 | FD_ZERO(&read_set); |
| 286 | FD_ZERO(&write_set); |
| 287 | FD_ZERO(&exception_set); |
| 288 | |
| 289 | n = 0; |
| 290 | for (i = 0; i < numfds; i++) { |
| 291 | if (fds[i].fd < 0) |
| 292 | continue; |
| 293 | #if !HAVE_WINSOCK2_H |
| 294 | if (fds[i].fd >= FD_SETSIZE) { |
| 295 | errno = EINVAL; |
| 296 | return -1; |
| 297 | } |
| 298 | #endif /* !HAVE_WINSOCK2_H */ |
| 299 | |
| 300 | if (fds[i].events & POLLIN) |
| 301 | FD_SET(fds[i].fd, &read_set); |
| 302 | if (fds[i].events & POLLOUT) |
| 303 | FD_SET(fds[i].fd, &write_set); |
| 304 | if (fds[i].events & POLLERR) |
| 305 | FD_SET(fds[i].fd, &exception_set); |
| 306 | |
| 307 | if (fds[i].fd >= n) |
| 308 | n = fds[i].fd + 1; |
| 309 | } |
| 310 | |
| 311 | if (n == 0) |
| 312 | /* Hey!? Nothing to poll, in fact!!! */ |
| 313 | return 0; |
| 314 | |
| 315 | if (timeout < 0) { |
| 316 | rc = select(n, &read_set, &write_set, &exception_set, NULL); |
| 317 | } else { |
| 318 | struct timeval tv; |
| 319 | tv.tv_sec = timeout / 1000; |
| 320 | tv.tv_usec = 1000 * (timeout % 1000); |
| 321 | rc = select(n, &read_set, &write_set, &exception_set, &tv); |
| 322 | } |
| 323 | |
| 324 | if (rc < 0) |
| 325 | return rc; |
| 326 | |
| 327 | for (i = 0; i < numfds; i++) { |
| 328 | fds[i].revents = 0; |
| 329 | |
| 330 | if (FD_ISSET(fds[i].fd, &read_set)) |
| 331 | fds[i].revents |= POLLIN; |
| 332 | if (FD_ISSET(fds[i].fd, &write_set)) |
| 333 | fds[i].revents |= POLLOUT; |
| 334 | if (FD_ISSET(fds[i].fd, &exception_set)) |
| 335 | fds[i].revents |= POLLERR; |
| 336 | } |
| 337 | |
| 338 | return rc; |
| 339 | } |
| 340 | #endif /* !HAVE_POLL_H */ |
| 341 | |
| 342 | #endif /* CONFIG_NETWORK */ |