yading@11: /* yading@11: * various OS-feature replacement utilities yading@11: * Copyright (c) 2000, 2001, 2002 Fabrice Bellard yading@11: * copyright (c) 2002 Francois Revol yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: /* needed by inet_aton() */ yading@11: #define _SVID_SOURCE yading@11: yading@11: #include "config.h" yading@11: #include "avformat.h" yading@11: #include "os_support.h" yading@11: yading@11: #if defined(_WIN32) && !defined(__MINGW32CE__) yading@11: #undef open yading@11: #undef lseek yading@11: #undef stat yading@11: #undef fstat yading@11: #include yading@11: #include yading@11: #include yading@11: #include yading@11: #include yading@11: yading@11: int ff_win32_open(const char *filename_utf8, int oflag, int pmode) yading@11: { yading@11: int fd; yading@11: int num_chars; yading@11: wchar_t *filename_w; yading@11: yading@11: /* convert UTF-8 to wide chars */ yading@11: num_chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename_utf8, -1, NULL, 0); yading@11: if (num_chars <= 0) yading@11: goto fallback; yading@11: filename_w = av_mallocz(sizeof(wchar_t) * num_chars); yading@11: if (!filename_w) { yading@11: errno = ENOMEM; yading@11: return -1; yading@11: } yading@11: MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, filename_w, num_chars); yading@11: yading@11: fd = _wsopen(filename_w, oflag, SH_DENYNO, pmode); yading@11: av_freep(&filename_w); yading@11: yading@11: if (fd != -1 || (oflag & O_CREAT)) yading@11: return fd; yading@11: yading@11: fallback: yading@11: /* filename may be be in CP_ACP */ yading@11: return _sopen(filename_utf8, oflag, SH_DENYNO, pmode); yading@11: } yading@11: #endif yading@11: yading@11: #if CONFIG_NETWORK yading@11: #include yading@11: #if !HAVE_POLL_H yading@11: #if HAVE_SYS_TIME_H yading@11: #include yading@11: #endif yading@11: #if HAVE_WINSOCK2_H yading@11: #include yading@11: #elif HAVE_SYS_SELECT_H yading@11: #include yading@11: #endif yading@11: #endif yading@11: yading@11: #include "network.h" yading@11: yading@11: #if !HAVE_INET_ATON yading@11: #include yading@11: yading@11: int ff_inet_aton(const char *str, struct in_addr *add) yading@11: { yading@11: unsigned int add1 = 0, add2 = 0, add3 = 0, add4 = 0; yading@11: yading@11: if (sscanf(str, "%d.%d.%d.%d", &add1, &add2, &add3, &add4) != 4) yading@11: return 0; yading@11: yading@11: if (!add1 || (add1 | add2 | add3 | add4) > 255) yading@11: return 0; yading@11: yading@11: add->s_addr = htonl((add1 << 24) + (add2 << 16) + (add3 << 8) + add4); yading@11: yading@11: return 1; yading@11: } yading@11: #else yading@11: int ff_inet_aton(const char *str, struct in_addr *add) yading@11: { yading@11: return inet_aton(str, add); yading@11: } yading@11: #endif /* !HAVE_INET_ATON */ yading@11: yading@11: #if !HAVE_GETADDRINFO yading@11: int ff_getaddrinfo(const char *node, const char *service, yading@11: const struct addrinfo *hints, struct addrinfo **res) yading@11: { yading@11: struct hostent *h = NULL; yading@11: struct addrinfo *ai; yading@11: struct sockaddr_in *sin; yading@11: yading@11: #if HAVE_WINSOCK2_H yading@11: int (WSAAPI *win_getaddrinfo)(const char *node, const char *service, yading@11: const struct addrinfo *hints, yading@11: struct addrinfo **res); yading@11: HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); yading@11: win_getaddrinfo = GetProcAddress(ws2mod, "getaddrinfo"); yading@11: if (win_getaddrinfo) yading@11: return win_getaddrinfo(node, service, hints, res); yading@11: #endif yading@11: yading@11: *res = NULL; yading@11: sin = av_mallocz(sizeof(struct sockaddr_in)); yading@11: if (!sin) yading@11: return EAI_FAIL; yading@11: sin->sin_family = AF_INET; yading@11: yading@11: if (node) { yading@11: if (!ff_inet_aton(node, &sin->sin_addr)) { yading@11: if (hints && (hints->ai_flags & AI_NUMERICHOST)) { yading@11: av_free(sin); yading@11: return EAI_FAIL; yading@11: } yading@11: h = gethostbyname(node); yading@11: if (!h) { yading@11: av_free(sin); yading@11: return EAI_FAIL; yading@11: } yading@11: memcpy(&sin->sin_addr, h->h_addr_list[0], sizeof(struct in_addr)); yading@11: } yading@11: } else { yading@11: if (hints && (hints->ai_flags & AI_PASSIVE)) yading@11: sin->sin_addr.s_addr = INADDR_ANY; yading@11: else yading@11: sin->sin_addr.s_addr = INADDR_LOOPBACK; yading@11: } yading@11: yading@11: /* Note: getaddrinfo allows service to be a string, which yading@11: * should be looked up using getservbyname. */ yading@11: if (service) yading@11: sin->sin_port = htons(atoi(service)); yading@11: yading@11: ai = av_mallocz(sizeof(struct addrinfo)); yading@11: if (!ai) { yading@11: av_free(sin); yading@11: return EAI_FAIL; yading@11: } yading@11: yading@11: *res = ai; yading@11: ai->ai_family = AF_INET; yading@11: ai->ai_socktype = hints ? hints->ai_socktype : 0; yading@11: switch (ai->ai_socktype) { yading@11: case SOCK_STREAM: yading@11: ai->ai_protocol = IPPROTO_TCP; yading@11: break; yading@11: case SOCK_DGRAM: yading@11: ai->ai_protocol = IPPROTO_UDP; yading@11: break; yading@11: default: yading@11: ai->ai_protocol = 0; yading@11: break; yading@11: } yading@11: yading@11: ai->ai_addr = (struct sockaddr *)sin; yading@11: ai->ai_addrlen = sizeof(struct sockaddr_in); yading@11: if (hints && (hints->ai_flags & AI_CANONNAME)) yading@11: ai->ai_canonname = h ? av_strdup(h->h_name) : NULL; yading@11: yading@11: ai->ai_next = NULL; yading@11: return 0; yading@11: } yading@11: yading@11: void ff_freeaddrinfo(struct addrinfo *res) yading@11: { yading@11: #if HAVE_WINSOCK2_H yading@11: void (WSAAPI *win_freeaddrinfo)(struct addrinfo *res); yading@11: HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); yading@11: win_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *res)) yading@11: GetProcAddress(ws2mod, "freeaddrinfo"); yading@11: if (win_freeaddrinfo) { yading@11: win_freeaddrinfo(res); yading@11: return; yading@11: } yading@11: #endif yading@11: yading@11: av_free(res->ai_canonname); yading@11: av_free(res->ai_addr); yading@11: av_free(res); yading@11: } yading@11: yading@11: int ff_getnameinfo(const struct sockaddr *sa, int salen, yading@11: char *host, int hostlen, yading@11: char *serv, int servlen, int flags) yading@11: { yading@11: const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; yading@11: yading@11: #if HAVE_WINSOCK2_H yading@11: int (WSAAPI *win_getnameinfo)(const struct sockaddr *sa, socklen_t salen, yading@11: char *host, DWORD hostlen, yading@11: char *serv, DWORD servlen, int flags); yading@11: HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); yading@11: win_getnameinfo = GetProcAddress(ws2mod, "getnameinfo"); yading@11: if (win_getnameinfo) yading@11: return win_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); yading@11: #endif yading@11: yading@11: if (sa->sa_family != AF_INET) yading@11: return EAI_FAMILY; yading@11: if (!host && !serv) yading@11: return EAI_NONAME; yading@11: yading@11: if (host && hostlen > 0) { yading@11: struct hostent *ent = NULL; yading@11: uint32_t a; yading@11: if (!(flags & NI_NUMERICHOST)) yading@11: ent = gethostbyaddr((const char *)&sin->sin_addr, yading@11: sizeof(sin->sin_addr), AF_INET); yading@11: yading@11: if (ent) { yading@11: snprintf(host, hostlen, "%s", ent->h_name); yading@11: } else if (flags & NI_NAMERQD) { yading@11: return EAI_NONAME; yading@11: } else { yading@11: a = ntohl(sin->sin_addr.s_addr); yading@11: snprintf(host, hostlen, "%d.%d.%d.%d", yading@11: ((a >> 24) & 0xff), ((a >> 16) & 0xff), yading@11: ((a >> 8) & 0xff), (a & 0xff)); yading@11: } yading@11: } yading@11: yading@11: if (serv && servlen > 0) { yading@11: struct servent *ent = NULL; yading@11: #if HAVE_GETSERVBYPORT yading@11: if (!(flags & NI_NUMERICSERV)) yading@11: ent = getservbyport(sin->sin_port, flags & NI_DGRAM ? "udp" : "tcp"); yading@11: #endif yading@11: yading@11: if (ent) yading@11: snprintf(serv, servlen, "%s", ent->s_name); yading@11: else yading@11: snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); yading@11: } yading@11: yading@11: return 0; yading@11: } yading@11: #endif /* !HAVE_GETADDRINFO */ yading@11: yading@11: #if !HAVE_GETADDRINFO || HAVE_WINSOCK2_H yading@11: const char *ff_gai_strerror(int ecode) yading@11: { yading@11: switch (ecode) { yading@11: case EAI_AGAIN: yading@11: return "Temporary failure in name resolution"; yading@11: case EAI_BADFLAGS: yading@11: return "Invalid flags for ai_flags"; yading@11: case EAI_FAIL: yading@11: return "A non-recoverable error occurred"; yading@11: case EAI_FAMILY: yading@11: return "The address family was not recognized or the address " yading@11: "length was invalid for the specified family"; yading@11: case EAI_MEMORY: yading@11: return "Memory allocation failure"; yading@11: #if EAI_NODATA != EAI_NONAME yading@11: case EAI_NODATA: yading@11: return "No address associated with hostname"; yading@11: #endif yading@11: case EAI_NONAME: yading@11: return "The name does not resolve for the supplied parameters"; yading@11: case EAI_SERVICE: yading@11: return "servname not supported for ai_socktype"; yading@11: case EAI_SOCKTYPE: yading@11: return "ai_socktype not supported"; yading@11: } yading@11: yading@11: return "Unknown error"; yading@11: } yading@11: #endif /* !HAVE_GETADDRINFO || HAVE_WINSOCK2_H */ yading@11: yading@11: int ff_socket_nonblock(int socket, int enable) yading@11: { yading@11: #if HAVE_WINSOCK2_H yading@11: u_long param = enable; yading@11: return ioctlsocket(socket, FIONBIO, ¶m); yading@11: #else yading@11: if (enable) yading@11: return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK); yading@11: else yading@11: return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK); yading@11: #endif yading@11: } yading@11: yading@11: #if !HAVE_POLL_H yading@11: int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout) yading@11: { yading@11: fd_set read_set; yading@11: fd_set write_set; yading@11: fd_set exception_set; yading@11: nfds_t i; yading@11: int n; yading@11: int rc; yading@11: yading@11: #if HAVE_WINSOCK2_H yading@11: if (numfds >= FD_SETSIZE) { yading@11: errno = EINVAL; yading@11: return -1; yading@11: } yading@11: #endif yading@11: yading@11: FD_ZERO(&read_set); yading@11: FD_ZERO(&write_set); yading@11: FD_ZERO(&exception_set); yading@11: yading@11: n = 0; yading@11: for (i = 0; i < numfds; i++) { yading@11: if (fds[i].fd < 0) yading@11: continue; yading@11: #if !HAVE_WINSOCK2_H yading@11: if (fds[i].fd >= FD_SETSIZE) { yading@11: errno = EINVAL; yading@11: return -1; yading@11: } yading@11: #endif yading@11: yading@11: if (fds[i].events & POLLIN) yading@11: FD_SET(fds[i].fd, &read_set); yading@11: if (fds[i].events & POLLOUT) yading@11: FD_SET(fds[i].fd, &write_set); yading@11: if (fds[i].events & POLLERR) yading@11: FD_SET(fds[i].fd, &exception_set); yading@11: yading@11: if (fds[i].fd >= n) yading@11: n = fds[i].fd + 1; yading@11: } yading@11: yading@11: if (n == 0) yading@11: /* Hey!? Nothing to poll, in fact!!! */ yading@11: return 0; yading@11: yading@11: if (timeout < 0) { yading@11: rc = select(n, &read_set, &write_set, &exception_set, NULL); yading@11: } else { yading@11: struct timeval tv; yading@11: tv.tv_sec = timeout / 1000; yading@11: tv.tv_usec = 1000 * (timeout % 1000); yading@11: rc = select(n, &read_set, &write_set, &exception_set, &tv); yading@11: } yading@11: yading@11: if (rc < 0) yading@11: return rc; yading@11: yading@11: for (i = 0; i < numfds; i++) { yading@11: fds[i].revents = 0; yading@11: yading@11: if (FD_ISSET(fds[i].fd, &read_set)) yading@11: fds[i].revents |= POLLIN; yading@11: if (FD_ISSET(fds[i].fd, &write_set)) yading@11: fds[i].revents |= POLLOUT; yading@11: if (FD_ISSET(fds[i].fd, &exception_set)) yading@11: fds[i].revents |= POLLERR; yading@11: } yading@11: yading@11: return rc; yading@11: } yading@11: #endif /* HAVE_POLL_H */ yading@11: #endif /* CONFIG_NETWORK */