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