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