| Line | Branch | Exec | 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 | { | ||
| 213 | #if HAVE_WINSOCK2_H | ||
| 214 | u_long param = enable; | ||
| 215 | return ioctlsocket(socket, FIONBIO, ¶m); | ||
| 216 | #else | ||
| 217 | ✗ | if (enable) | |
| 218 | ✗ | return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK); | |
| 219 | else | ||
| 220 | ✗ | return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK); | |
| 221 | #endif /* HAVE_WINSOCK2_H */ | ||
| 222 | } | ||
| 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 */ | ||
| 302 |