/** * Copyright © 2014-2015 VideoLabs SAS * * Author: Jonathan Calmels * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "compat.h" #include "utils.h" #if defined (__unix__) || defined (__APPLE__) struct timeval os_deadline = { .tv_sec = 0, .tv_usec = 100000, }; #endif // __unix__ || (__APPLE__) #if defined (_WIN32) uint32_t os_deadline = 1000; #include #endif // _WIN32 int os_strerror(int errnum, char *buf, size_t buflen) { int r = 0; if (buflen == 0) return -1; buf[0] = '\0'; switch (errnum) { #if defined (_WIN32) case MDNS_NETERR: errno = WSAGetLastError(); // fallthrough case MDNS_STDERR: { wchar_t* wbuff = malloc(sizeof(*wbuff) * buflen); if (wbuff == NULL) return (-1); DWORD nbChar = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errno, 0, wbuff, buflen, NULL); if (!nbChar) { snprintf(buf, buflen, "Error %d\n", errno); r = -1; } else nbChar = WideCharToMultiByte(CP_UTF8, 0, wbuff, nbChar, buf, buflen, NULL, NULL); free(wbuff); break; } #if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) || _WIN32_WINNT >= 0x0A00 case MDNS_LKPERR: { // Win32 gai_strerror returns a static buffer, but as a non-const char* WCHAR *s = gai_strerror(errno); if (!WideCharToMultiByte(CP_UTF8, 0, s, -1, buf, buflen, NULL, NULL)) return (-1); break; } #endif #else case MDNS_STDERR: case MDNS_NETERR: if (strerror_r(errno, buf, buflen) != 0) return (-1); break; case MDNS_LKPERR: { const char *s; s = gai_strerror(errno); if ( s == NULL ) return (-1); strncpy(buf, s, buflen); buf[buflen - 1] = '\0'; break; } #endif default: r = -1; } return (r); } int os_mcast_join(sock_t s, const struct sockaddr_storage *ss, uint32_t intf_idx, const struct sockaddr_storage* intf_addr) { #ifdef MCAST_JOIN_GROUP (void)intf_addr; struct group_req mgroup; memset(&mgroup, 0, sizeof(mgroup)); mgroup.gr_interface = intf_idx; memcpy(&mgroup.gr_group, ss, ss_len(ss)); if (setsockopt(s, ss_level(ss), MCAST_JOIN_GROUP, (const void *) &mgroup, sizeof(mgroup)) < 0) return (-1); #else union { struct sockaddr_storage ss; struct sockaddr_in sin; struct sockaddr_in6 sin6; } u; memcpy(&u, ss, sizeof(*ss)); switch (ss_family(ss)) { case AF_INET: { struct ip_mreq mreq; const struct sockaddr_in* sin = (const struct sockaddr_in*)intf_addr; memcpy(&mreq.imr_multiaddr.s_addr, &u.sin.sin_addr, sizeof(struct in_addr)); memcpy(&mreq.imr_interface, &sin->sin_addr, sizeof(sin->sin_addr)); if (setsockopt(s, ss_level(ss), IP_ADD_MEMBERSHIP, (const void *) &mreq, sizeof(mreq)) < 0) return (-1); break; } case AF_INET6: { struct ipv6_mreq mreq6; memcpy(&mreq6.ipv6mr_multiaddr, &u.sin6.sin6_addr, sizeof(struct in6_addr)); memcpy(&mreq6.ipv6mr_interface, &intf_idx, sizeof(intf_idx)); if (setsockopt(s, ss_level(ss), IPV6_JOIN_GROUP, (const void *) &mreq6, sizeof(mreq6)) < 0) return (-1); break; } default: assert(1); } #endif return (0); }