1 /**
2 * Copyright © 2014-2015 VideoLabs SAS
3 *
4 * Author: Jonathan Calmels <jbjcalmels@gmail.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <assert.h>
24 #include <errno.h>
25 #include <string.h>
26
27 #include "compat.h"
28 #include "utils.h"
29
30 #if defined (__unix__) || defined (__APPLE__)
31 struct timeval os_deadline = {
32 .tv_sec = 0,
33 .tv_usec = 100000,
34 };
35 #endif // __unix__ || (__APPLE__)
36
37 #if defined (_WIN32)
38 uint32_t os_deadline = 1000;
39 #include <winapifamily.h>
40 #endif // _WIN32
41
42 int
os_strerror(int errnum,char * buf,size_t buflen)43 os_strerror(int errnum, char *buf, size_t buflen)
44 {
45 int r = 0;
46 if (buflen == 0)
47 return -1;
48
49 buf[0] = '\0';
50
51 switch (errnum) {
52 #if defined (_WIN32)
53 case MDNS_NETERR:
54 errno = WSAGetLastError();
55 // fallthrough
56 case MDNS_STDERR:
57 {
58 wchar_t* wbuff = malloc(sizeof(*wbuff) * buflen);
59 if (wbuff == NULL)
60 return (-1);
61 DWORD nbChar = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
62 NULL, errno, 0, wbuff, buflen, NULL);
63 if (!nbChar)
64 {
65 snprintf(buf, buflen, "Error %d\n", errno);
66 r = -1;
67 }
68 else
69 nbChar = WideCharToMultiByte(CP_UTF8, 0, wbuff, nbChar,
70 buf, buflen, NULL, NULL);
71 free(wbuff);
72 break;
73 }
74 #if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) || _WIN32_WINNT >= 0x0A00
75 case MDNS_LKPERR:
76 {
77 // Win32 gai_strerror returns a static buffer, but as a non-const char*
78 WCHAR *s = gai_strerror(errno);
79 if (!WideCharToMultiByte(CP_UTF8, 0, s, -1, buf, buflen, NULL, NULL))
80 return (-1);
81 break;
82 }
83 #endif
84 #else
85 case MDNS_STDERR:
86 case MDNS_NETERR:
87 if (strerror_r(errno, buf, buflen) != 0)
88 return (-1);
89 break;
90
91 case MDNS_LKPERR: {
92 const char *s;
93 s = gai_strerror(errno);
94 if ( s == NULL )
95 return (-1);
96 strncpy(buf, s, buflen);
97 buf[buflen - 1] = '\0';
98 break;
99 }
100 #endif
101 default:
102 r = -1;
103 }
104 return (r);
105 }
106
107 int
os_mcast_join(sock_t s,const struct sockaddr_storage * ss,uint32_t intf_idx,const struct sockaddr_storage * intf_addr)108 os_mcast_join(sock_t s, const struct sockaddr_storage *ss, uint32_t intf_idx,
109 const struct sockaddr_storage* intf_addr)
110 {
111 #ifdef MCAST_JOIN_GROUP
112 (void)intf_addr;
113 struct group_req mgroup;
114
115 memset(&mgroup, 0, sizeof(mgroup));
116 mgroup.gr_interface = intf_idx;
117 memcpy(&mgroup.gr_group, ss, ss_len(ss));
118 if (setsockopt(s, ss_level(ss), MCAST_JOIN_GROUP,
119 (const void *) &mgroup, sizeof(mgroup)) < 0)
120 return (-1);
121 #else
122 union {
123 struct sockaddr_storage ss;
124 struct sockaddr_in sin;
125 struct sockaddr_in6 sin6;
126 } u;
127
128 memcpy(&u, ss, sizeof(*ss));
129 switch (ss_family(ss)) {
130 case AF_INET: {
131 struct ip_mreq mreq;
132 const struct sockaddr_in* sin = (const struct sockaddr_in*)intf_addr;
133
134 memcpy(&mreq.imr_multiaddr.s_addr, &u.sin.sin_addr, sizeof(struct in_addr));
135 memcpy(&mreq.imr_interface, &sin->sin_addr, sizeof(sin->sin_addr));
136 if (setsockopt(s, ss_level(ss), IP_ADD_MEMBERSHIP,
137 (const void *) &mreq, sizeof(mreq)) < 0)
138 return (-1);
139 break;
140 }
141 case AF_INET6: {
142 struct ipv6_mreq mreq6;
143
144 memcpy(&mreq6.ipv6mr_multiaddr, &u.sin6.sin6_addr, sizeof(struct in6_addr));
145 memcpy(&mreq6.ipv6mr_interface, &intf_idx, sizeof(intf_idx));
146 if (setsockopt(s, ss_level(ss), IPV6_JOIN_GROUP,
147 (const void *) &mreq6, sizeof(mreq6)) < 0)
148 return (-1);
149 break;
150 }
151 default:
152 assert(1);
153 }
154 #endif
155 return (0);
156 }
157