1 /**********
2 This library is free software; you can redistribute it and/or modify it under
3 the terms of the GNU Lesser General Public License as published by the
4 Free Software Foundation; either version 3 of the License, or (at your
5 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6 
7 This library is distributed in the hope that it will be useful, but WITHOUT
8 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
10 more details.
11 
12 You should have received a copy of the GNU Lesser General Public License
13 along with this library; if not, write to the Free Software Foundation, Inc.,
14 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
15 **********/
16 // "mTunnel" multicast access service
17 // Copyright (c) 1996-2020 Live Networks, Inc.  All rights reserved.
18 // Helper routines to implement 'group sockets'
19 // Implementation
20 
21 #include "GroupsockHelper.hh"
22 
23 #if (defined(__WIN32__) || defined(_WIN32)) && !defined(__MINGW32__)
24 #include <time.h>
25 extern "C" int initializeWinsockIfNecessary();
26 #else
27 #include <stdarg.h>
28 #include <time.h>
29 #include <sys/time.h>
30 #if !defined(_WIN32)
31 #include <netinet/tcp.h>
32 #ifdef __ANDROID_NDK__
33 #include <android/ndk-version.h>
34 #define ANDROID_OLD_NDK __NDK_MAJOR__ < 17
35 #endif
36 #endif
37 #include <fcntl.h>
38 #define initializeWinsockIfNecessary() 1
39 #endif
40 #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4)
41 #else
42 #include <signal.h>
43 #define USE_SIGNALS 1
44 #endif
45 #include <stdio.h>
46 
47 // By default, use INADDR_ANY for the sending and receiving interfaces:
48 netAddressBits SendingInterfaceAddr = INADDR_ANY;
49 netAddressBits ReceivingInterfaceAddr = INADDR_ANY;
50 
socketErr(UsageEnvironment & env,char const * errorMsg)51 static void socketErr(UsageEnvironment& env, char const* errorMsg) {
52   env.setResultErrMsg(errorMsg);
53 }
54 
NoReuse(UsageEnvironment & env)55 NoReuse::NoReuse(UsageEnvironment& env)
56   : fEnv(env) {
57   groupsockPriv(fEnv)->reuseFlag = 0;
58 }
59 
~NoReuse()60 NoReuse::~NoReuse() {
61   groupsockPriv(fEnv)->reuseFlag = 1;
62   reclaimGroupsockPriv(fEnv);
63 }
64 
65 
groupsockPriv(UsageEnvironment & env)66 _groupsockPriv* groupsockPriv(UsageEnvironment& env) {
67   if (env.groupsockPriv == NULL) { // We need to create it
68     _groupsockPriv* result = new _groupsockPriv;
69     result->socketTable = NULL;
70     result->reuseFlag = 1; // default value => allow reuse of socket numbers
71     env.groupsockPriv = result;
72   }
73   return (_groupsockPriv*)(env.groupsockPriv);
74 }
75 
reclaimGroupsockPriv(UsageEnvironment & env)76 void reclaimGroupsockPriv(UsageEnvironment& env) {
77   _groupsockPriv* priv = (_groupsockPriv*)(env.groupsockPriv);
78   if (priv->socketTable == NULL && priv->reuseFlag == 1/*default value*/) {
79     // We can delete the structure (to save space); it will get created again, if needed:
80     delete priv;
81     env.groupsockPriv = NULL;
82   }
83 }
84 
createSocket(int type)85 static int createSocket(int type) {
86   // Call "socket()" to create a (IPv4) socket of the specified type.
87   // But also set it to have the 'close on exec' property (if we can)
88   int sock;
89 
90 #ifdef SOCK_CLOEXEC
91   sock = socket(AF_INET, type|SOCK_CLOEXEC, 0);
92   if (sock != -1 || errno != EINVAL) return sock;
93   // An "errno" of EINVAL likely means that the system wasn't happy with the SOCK_CLOEXEC; fall through and try again without it:
94 #endif
95 
96   sock = socket(AF_INET, type, 0);
97 #ifdef FD_CLOEXEC
98   if (sock != -1) fcntl(sock, F_SETFD, FD_CLOEXEC);
99 #endif
100   return sock;
101 }
102 
setupDatagramSocket(UsageEnvironment & env,Port port)103 int setupDatagramSocket(UsageEnvironment& env, Port port) {
104   if (!initializeWinsockIfNecessary()) {
105     socketErr(env, "Failed to initialize 'winsock': ");
106     return -1;
107   }
108 
109   int newSocket = createSocket(SOCK_DGRAM);
110   if (newSocket < 0) {
111     socketErr(env, "unable to create datagram socket: ");
112     return newSocket;
113   }
114 
115   int reuseFlag = groupsockPriv(env)->reuseFlag;
116   reclaimGroupsockPriv(env);
117   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
118 		 (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
119     socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
120     closeSocket(newSocket);
121     return -1;
122   }
123 
124 #if defined(__WIN32__) || defined(_WIN32)
125   // Windoze doesn't properly handle SO_REUSEPORT or IP_MULTICAST_LOOP
126 #else
127 #ifdef SO_REUSEPORT
128   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
129 		 (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
130     socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
131     closeSocket(newSocket);
132     return -1;
133   }
134 #endif
135 
136 #ifdef IP_MULTICAST_LOOP
137   const u_int8_t loop = 1;
138   if (setsockopt(newSocket, IPPROTO_IP, IP_MULTICAST_LOOP,
139 		 (const char*)&loop, sizeof loop) < 0) {
140     socketErr(env, "setsockopt(IP_MULTICAST_LOOP) error: ");
141     closeSocket(newSocket);
142     return -1;
143   }
144 #endif
145 #endif
146 
147   // Note: Windoze requires binding, even if the port number is 0
148   netAddressBits addr = INADDR_ANY;
149 #if defined(__WIN32__) || defined(_WIN32)
150 #else
151   if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
152 #endif
153     if (port.num() == 0) addr = ReceivingInterfaceAddr;
154     MAKE_SOCKADDR_IN(name, addr, port.num());
155     if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
156       char tmpBuffer[100];
157       sprintf(tmpBuffer, "bind() error (port number: %d): ",
158 	      ntohs(port.num()));
159       socketErr(env, tmpBuffer);
160       closeSocket(newSocket);
161       return -1;
162     }
163 #if defined(__WIN32__) || defined(_WIN32)
164 #else
165   }
166 #endif
167 
168   // Set the sending interface for multicasts, if it's not the default:
169   if (SendingInterfaceAddr != INADDR_ANY) {
170     struct in_addr addr;
171     addr.s_addr = SendingInterfaceAddr;
172 
173     if (setsockopt(newSocket, IPPROTO_IP, IP_MULTICAST_IF,
174 		   (const char*)&addr, sizeof addr) < 0) {
175       socketErr(env, "error setting outgoing multicast interface: ");
176       closeSocket(newSocket);
177       return -1;
178     }
179   }
180 
181   return newSocket;
182 }
183 
makeSocketNonBlocking(int sock)184 Boolean makeSocketNonBlocking(int sock) {
185 #if defined(__WIN32__) || defined(_WIN32)
186   unsigned long arg = 1;
187   return ioctlsocket(sock, FIONBIO, &arg) == 0;
188 #elif defined(VXWORKS)
189   int arg = 1;
190   return ioctl(sock, FIONBIO, (int)&arg) == 0;
191 #else
192   int curFlags = fcntl(sock, F_GETFL, 0);
193   return fcntl(sock, F_SETFL, curFlags|O_NONBLOCK) >= 0;
194 #endif
195 }
196 
makeSocketBlocking(int sock,unsigned writeTimeoutInMilliseconds)197 Boolean makeSocketBlocking(int sock, unsigned writeTimeoutInMilliseconds) {
198   Boolean result;
199 #if defined(__WIN32__) || defined(_WIN32)
200   unsigned long arg = 0;
201   result = ioctlsocket(sock, FIONBIO, &arg) == 0;
202 #elif defined(VXWORKS)
203   int arg = 0;
204   result = ioctl(sock, FIONBIO, (int)&arg) == 0;
205 #else
206   int curFlags = fcntl(sock, F_GETFL, 0);
207   result = fcntl(sock, F_SETFL, curFlags&(~O_NONBLOCK)) >= 0;
208 #endif
209 
210   if (writeTimeoutInMilliseconds > 0) {
211 #ifdef SO_SNDTIMEO
212 #if defined(__WIN32__) || defined(_WIN32)
213     DWORD msto = (DWORD)writeTimeoutInMilliseconds;
214     setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&msto, sizeof(msto) );
215 #else
216     struct timeval tv;
217     tv.tv_sec = writeTimeoutInMilliseconds/1000;
218     tv.tv_usec = (writeTimeoutInMilliseconds%1000)*1000;
219     setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof tv);
220 #endif
221 #endif
222   }
223 
224   return result;
225 }
226 
setSocketKeepAlive(int sock)227 Boolean setSocketKeepAlive(int sock) {
228 #if defined(__WIN32__) || defined(_WIN32)
229   // How do we do this in Windows?  For now, just make this a no-op in Windows:
230 #else
231   int const keepalive_enabled = 1;
232   if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepalive_enabled, sizeof keepalive_enabled) < 0) {
233     return False;
234   }
235 
236 #ifdef TCP_KEEPIDLE
237   int const keepalive_time = 180;
238   if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&keepalive_time, sizeof keepalive_time) < 0) {
239     return False;
240   }
241 #endif
242 
243 #ifdef TCP_KEEPCNT
244   int const keepalive_count = 5;
245   if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (void*)&keepalive_count, sizeof keepalive_count) < 0) {
246     return False;
247   }
248 #endif
249 
250 #ifdef TCP_KEEPINTVL
251   int const keepalive_interval = 20;
252   if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (void*)&keepalive_interval, sizeof keepalive_interval) < 0) {
253     return False;
254   }
255 #endif
256 #endif
257 
258   return True;
259 }
260 
setupStreamSocket(UsageEnvironment & env,Port port,Boolean makeNonBlocking,Boolean setKeepAlive)261 int setupStreamSocket(UsageEnvironment& env,
262                       Port port, Boolean makeNonBlocking, Boolean setKeepAlive) {
263   if (!initializeWinsockIfNecessary()) {
264     socketErr(env, "Failed to initialize 'winsock': ");
265     return -1;
266   }
267 
268   int newSocket = createSocket(SOCK_STREAM);
269   if (newSocket < 0) {
270     socketErr(env, "unable to create stream socket: ");
271     return newSocket;
272   }
273 
274   int reuseFlag = groupsockPriv(env)->reuseFlag;
275   reclaimGroupsockPriv(env);
276   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
277 		 (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
278     socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
279     closeSocket(newSocket);
280     return -1;
281   }
282 
283   // SO_REUSEPORT doesn't really make sense for TCP sockets, so we
284   // normally don't set them.  However, if you really want to do this
285   // #define REUSE_FOR_TCP
286 #ifdef REUSE_FOR_TCP
287 #if defined(__WIN32__) || defined(_WIN32)
288   // Windoze doesn't properly handle SO_REUSEPORT
289 #else
290 #ifdef SO_REUSEPORT
291   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
292 		 (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
293     socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
294     closeSocket(newSocket);
295     return -1;
296   }
297 #endif
298 #endif
299 #endif
300 
301   // Note: Windoze requires binding, even if the port number is 0
302 #if defined(__WIN32__) || defined(_WIN32)
303 #else
304   if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
305 #endif
306     MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num());
307     if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
308       char tmpBuffer[100];
309       sprintf(tmpBuffer, "bind() error (port number: %d): ",
310 	      ntohs(port.num()));
311       socketErr(env, tmpBuffer);
312       closeSocket(newSocket);
313       return -1;
314     }
315 #if defined(__WIN32__) || defined(_WIN32)
316 #else
317   }
318 #endif
319 
320   if (makeNonBlocking) {
321     if (!makeSocketNonBlocking(newSocket)) {
322       socketErr(env, "failed to make non-blocking: ");
323       closeSocket(newSocket);
324       return -1;
325     }
326   }
327 
328   // Set the keep alive mechanism for the TCP socket, to avoid "ghost sockets"
329   //    that remain after an interrupted communication.
330   if (setKeepAlive) {
331     if (!setSocketKeepAlive(newSocket)) {
332       socketErr(env, "failed to set keep alive: ");
333       closeSocket(newSocket);
334       return -1;
335     }
336   }
337 
338   return newSocket;
339 }
340 
readSocket(UsageEnvironment & env,int socket,unsigned char * buffer,unsigned bufferSize,struct sockaddr_storage & fromAddress)341 int readSocket(UsageEnvironment& env,
342 	       int socket, unsigned char* buffer, unsigned bufferSize,
343 	       struct sockaddr_storage& fromAddress) {
344   SOCKLEN_T addressSize = sizeof fromAddress;
345   int bytesRead = recvfrom(socket, (char*)buffer, bufferSize, 0,
346 			   (struct sockaddr*)&fromAddress,
347 			   &addressSize);
348   if (bytesRead < 0) {
349     //##### HACK to work around bugs in Linux and Windows:
350     int err = env.getErrno();
351     if (err == 111 /*ECONNREFUSED (Linux)*/
352 #if defined(__WIN32__) || defined(_WIN32)
353 	// What a piece of crap Windows is.  Sometimes
354 	// recvfrom() returns -1, but with an 'errno' of 0.
355 	// This appears not to be a real error; just treat
356 	// it as if it were a read of zero bytes, and hope
357 	// we don't have to do anything else to 'reset'
358 	// this alleged error:
359 	|| err == 0 || err == EWOULDBLOCK
360 #else
361 	|| err == EAGAIN
362 #endif
363 	|| err == 113 /*EHOSTUNREACH (Linux)*/) { // Why does Linux return this for datagram sock?
364       switch (fromAddress.ss_family) {
365 	case AF_INET: {
366 	  ((sockaddr_in*)&fromAddress)->sin_addr.s_addr = 0;
367 	  break;
368 	}
369         case AF_INET6: {
370 	  ((sockaddr_in6*)&fromAddress)->sin6_addr.__u6_addr.__u6_addr32[0] = 0;
371 	  ((sockaddr_in6*)&fromAddress)->sin6_addr.__u6_addr.__u6_addr32[1] = 0;
372 	  ((sockaddr_in6*)&fromAddress)->sin6_addr.__u6_addr.__u6_addr32[2] = 0;
373 	  ((sockaddr_in6*)&fromAddress)->sin6_addr.__u6_addr.__u6_addr32[3] = 0;
374 	  break;
375 	}
376       }
377       return 0;
378     }
379     //##### END HACK
380     socketErr(env, "recvfrom() error: ");
381   } else if (bytesRead == 0) {
382     // "recvfrom()" on a stream socket can return 0 if the remote end has closed the connection.  Treat this as an error:
383     return -1;
384   }
385 
386   return bytesRead;
387 }
388 
writeSocket(UsageEnvironment & env,int socket,struct in_addr address,portNumBits portNum,u_int8_t ttlArg,unsigned char * buffer,unsigned bufferSize)389 Boolean writeSocket(UsageEnvironment& env,
390 		    int socket, struct in_addr address, portNumBits portNum,
391 		    u_int8_t ttlArg,
392 		    unsigned char* buffer, unsigned bufferSize) {
393   // Before sending, set the socket's TTL:
394 #if defined(__WIN32__) || defined(_WIN32)
395 #define TTL_TYPE int
396 #else
397 #define TTL_TYPE u_int8_t
398 #endif
399   TTL_TYPE ttl = (TTL_TYPE)ttlArg;
400   if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL,
401 		 (const char*)&ttl, sizeof ttl) < 0) {
402     socketErr(env, "setsockopt(IP_MULTICAST_TTL) error: ");
403     return False;
404   }
405 
406   return writeSocket(env, socket, address, portNum, buffer, bufferSize);
407 }
408 
writeSocket(UsageEnvironment & env,int socket,struct in_addr address,portNumBits portNum,unsigned char * buffer,unsigned bufferSize)409 Boolean writeSocket(UsageEnvironment& env,
410 		    int socket, struct in_addr address, portNumBits portNum,
411 		    unsigned char* buffer, unsigned bufferSize) {
412   do {
413     MAKE_SOCKADDR_IN(dest, address.s_addr, portNum);
414     int bytesSent = sendto(socket, (char*)buffer, bufferSize, 0,
415 			   (struct sockaddr*)&dest, sizeof dest);
416     if (bytesSent != (int)bufferSize) {
417       char tmpBuf[100];
418       sprintf(tmpBuf, "writeSocket(%d), sendTo() error: wrote %d bytes instead of %u: ", socket, bytesSent, bufferSize);
419       socketErr(env, tmpBuf);
420       break;
421     }
422 
423     return True;
424   } while (0);
425 
426   return False;
427 }
428 
ignoreSigPipeOnSocket(int socketNum)429 void ignoreSigPipeOnSocket(int socketNum) {
430   #ifdef USE_SIGNALS
431   #ifdef SO_NOSIGPIPE
432   int set_option = 1;
433   setsockopt(socketNum, SOL_SOCKET, SO_NOSIGPIPE, &set_option, sizeof set_option);
434   #else
435   signal(SIGPIPE, SIG_IGN);
436   #endif
437   #endif
438 }
439 
getBufferSize(UsageEnvironment & env,int bufOptName,int socket)440 static unsigned getBufferSize(UsageEnvironment& env, int bufOptName,
441 			      int socket) {
442   unsigned curSize;
443   SOCKLEN_T sizeSize = sizeof curSize;
444   if (getsockopt(socket, SOL_SOCKET, bufOptName,
445 		 (char*)&curSize, &sizeSize) < 0) {
446     socketErr(env, "getBufferSize() error: ");
447     return 0;
448   }
449 
450   return curSize;
451 }
getSendBufferSize(UsageEnvironment & env,int socket)452 unsigned getSendBufferSize(UsageEnvironment& env, int socket) {
453   return getBufferSize(env, SO_SNDBUF, socket);
454 }
getReceiveBufferSize(UsageEnvironment & env,int socket)455 unsigned getReceiveBufferSize(UsageEnvironment& env, int socket) {
456   return getBufferSize(env, SO_RCVBUF, socket);
457 }
458 
setBufferTo(UsageEnvironment & env,int bufOptName,int socket,unsigned requestedSize)459 static unsigned setBufferTo(UsageEnvironment& env, int bufOptName,
460 			    int socket, unsigned requestedSize) {
461   SOCKLEN_T sizeSize = sizeof requestedSize;
462   setsockopt(socket, SOL_SOCKET, bufOptName, (char*)&requestedSize, sizeSize);
463 
464   // Get and return the actual, resulting buffer size:
465   return getBufferSize(env, bufOptName, socket);
466 }
setSendBufferTo(UsageEnvironment & env,int socket,unsigned requestedSize)467 unsigned setSendBufferTo(UsageEnvironment& env,
468 			 int socket, unsigned requestedSize) {
469 	return setBufferTo(env, SO_SNDBUF, socket, requestedSize);
470 }
setReceiveBufferTo(UsageEnvironment & env,int socket,unsigned requestedSize)471 unsigned setReceiveBufferTo(UsageEnvironment& env,
472 			    int socket, unsigned requestedSize) {
473 	return setBufferTo(env, SO_RCVBUF, socket, requestedSize);
474 }
475 
increaseBufferTo(UsageEnvironment & env,int bufOptName,int socket,unsigned requestedSize)476 static unsigned increaseBufferTo(UsageEnvironment& env, int bufOptName,
477 				 int socket, unsigned requestedSize) {
478   // First, get the current buffer size.  If it's already at least
479   // as big as what we're requesting, do nothing.
480   unsigned curSize = getBufferSize(env, bufOptName, socket);
481 
482   // Next, try to increase the buffer to the requested size,
483   // or to some smaller size, if that's not possible:
484   while (requestedSize > curSize) {
485     SOCKLEN_T sizeSize = sizeof requestedSize;
486     if (setsockopt(socket, SOL_SOCKET, bufOptName,
487 		   (char*)&requestedSize, sizeSize) >= 0) {
488       // success
489       return requestedSize;
490     }
491     requestedSize = (requestedSize+curSize)/2;
492   }
493 
494   return getBufferSize(env, bufOptName, socket);
495 }
increaseSendBufferTo(UsageEnvironment & env,int socket,unsigned requestedSize)496 unsigned increaseSendBufferTo(UsageEnvironment& env,
497 			      int socket, unsigned requestedSize) {
498   return increaseBufferTo(env, SO_SNDBUF, socket, requestedSize);
499 }
increaseReceiveBufferTo(UsageEnvironment & env,int socket,unsigned requestedSize)500 unsigned increaseReceiveBufferTo(UsageEnvironment& env,
501 				 int socket, unsigned requestedSize) {
502   return increaseBufferTo(env, SO_RCVBUF, socket, requestedSize);
503 }
504 
clearMulticastAllSocketOption(int socket)505 static void clearMulticastAllSocketOption(int socket) {
506 #ifdef IP_MULTICAST_ALL
507   // This option is defined in modern versions of Linux to overcome a bug in the Linux kernel's default behavior.
508   // When set to 0, it ensures that we receive only packets that were sent to the specified IP multicast address,
509   // even if some other process on the same system has joined a different multicast group with the same port number.
510   int multicastAll = 0;
511   (void)setsockopt(socket, IPPROTO_IP, IP_MULTICAST_ALL, (void*)&multicastAll, sizeof multicastAll);
512   // Ignore the call's result.  Should it fail, we'll still receive packets (just perhaps more than intended)
513 #endif
514 }
515 
socketJoinGroup(UsageEnvironment & env,int socket,netAddressBits groupAddress)516 Boolean socketJoinGroup(UsageEnvironment& env, int socket,
517 			netAddressBits groupAddress){
518   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
519 
520   struct ip_mreq imr;
521   imr.imr_multiaddr.s_addr = groupAddress;
522   imr.imr_interface.s_addr = ReceivingInterfaceAddr;
523   if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
524 		 (const char*)&imr, sizeof (struct ip_mreq)) < 0) {
525 #if defined(__WIN32__) || defined(_WIN32)
526     if (env.getErrno() != 0) {
527       // That piece-of-shit toy operating system (Windows) sometimes lies
528       // about setsockopt() failing!
529 #endif
530       socketErr(env, "setsockopt(IP_ADD_MEMBERSHIP) error: ");
531       return False;
532 #if defined(__WIN32__) || defined(_WIN32)
533     }
534 #endif
535   }
536 
537   clearMulticastAllSocketOption(socket);
538 
539   return True;
540 }
541 
socketLeaveGroup(UsageEnvironment &,int socket,netAddressBits groupAddress)542 Boolean socketLeaveGroup(UsageEnvironment&, int socket,
543 			 netAddressBits groupAddress) {
544   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
545 
546   struct ip_mreq imr;
547   imr.imr_multiaddr.s_addr = groupAddress;
548   imr.imr_interface.s_addr = ReceivingInterfaceAddr;
549   if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
550 		 (const char*)&imr, sizeof (struct ip_mreq)) < 0) {
551     return False;
552   }
553 
554   return True;
555 }
556 
557 // The source-specific join/leave operations require special setsockopt()
558 // commands, and a special structure (ip_mreq_source).  If the include files
559 // didn't define these, we do so here:
560 #if !defined(IP_ADD_SOURCE_MEMBERSHIP)
561 struct ip_mreq_source {
562   struct  in_addr imr_multiaddr;  /* IP multicast address of group */
563   struct  in_addr imr_sourceaddr; /* IP address of source */
564   struct  in_addr imr_interface;  /* local IP address of interface */
565 };
566 #endif
567 
568 #ifndef IP_ADD_SOURCE_MEMBERSHIP
569 
570 #ifdef LINUX
571 #define IP_ADD_SOURCE_MEMBERSHIP   39
572 #define IP_DROP_SOURCE_MEMBERSHIP 40
573 #else
574 #define IP_ADD_SOURCE_MEMBERSHIP   25
575 #define IP_DROP_SOURCE_MEMBERSHIP 26
576 #endif
577 
578 #endif
579 
socketJoinGroupSSM(UsageEnvironment & env,int socket,netAddressBits groupAddress,netAddressBits sourceFilterAddr)580 Boolean socketJoinGroupSSM(UsageEnvironment& env, int socket,
581 			   netAddressBits groupAddress,
582 			   netAddressBits sourceFilterAddr) {
583   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
584 
585   struct ip_mreq_source imr;
586 #if ANDROID_OLD_NDK
587     imr.imr_multiaddr = groupAddress;
588     imr.imr_sourceaddr = sourceFilterAddr;
589     imr.imr_interface = ReceivingInterfaceAddr;
590 #else
591     imr.imr_multiaddr.s_addr = groupAddress;
592     imr.imr_sourceaddr.s_addr = sourceFilterAddr;
593     imr.imr_interface.s_addr = ReceivingInterfaceAddr;
594 #endif
595   if (setsockopt(socket, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
596 		 (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) {
597     socketErr(env, "setsockopt(IP_ADD_SOURCE_MEMBERSHIP) error: ");
598     return False;
599   }
600 
601   clearMulticastAllSocketOption(socket);
602 
603   return True;
604 }
605 
socketLeaveGroupSSM(UsageEnvironment &,int socket,netAddressBits groupAddress,netAddressBits sourceFilterAddr)606 Boolean socketLeaveGroupSSM(UsageEnvironment& /*env*/, int socket,
607 			    netAddressBits groupAddress,
608 			    netAddressBits sourceFilterAddr) {
609   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
610 
611   struct ip_mreq_source imr;
612 #if ANDROID_OLD_NDK
613     imr.imr_multiaddr = groupAddress;
614     imr.imr_sourceaddr = sourceFilterAddr;
615     imr.imr_interface = ReceivingInterfaceAddr;
616 #else
617     imr.imr_multiaddr.s_addr = groupAddress;
618     imr.imr_sourceaddr.s_addr = sourceFilterAddr;
619     imr.imr_interface.s_addr = ReceivingInterfaceAddr;
620 #endif
621   if (setsockopt(socket, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP,
622 		 (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) {
623     return False;
624   }
625 
626   return True;
627 }
628 
getSourcePort0(int socket,portNumBits & resultPortNum)629 static Boolean getSourcePort0(int socket, portNumBits& resultPortNum/*host order*/) {
630   sockaddr_storage test;
631   switch (test.ss_family) {
632     case AF_INET: {
633       ((sockaddr_in*)&test)->sin_port = 0;
634       break;
635     }
636     case AF_INET6: {
637       ((sockaddr_in6*)&test)->sin6_port = 0;
638     }
639   }
640 
641   SOCKLEN_T len = sizeof test;
642   if (getsockname(socket, (struct sockaddr*)&test, &len) < 0) return False;
643 
644   resultPortNum = ntohs(portNum(test));
645   return True;
646 }
647 
getSourcePort(UsageEnvironment & env,int socket,Port & port)648 Boolean getSourcePort(UsageEnvironment& env, int socket, Port& port) {
649   portNumBits portNum = 0;
650   if (!getSourcePort0(socket, portNum) || portNum == 0) {
651     // Hack - call bind(), then try again:
652     MAKE_SOCKADDR_IN(name, INADDR_ANY, 0);
653     bind(socket, (struct sockaddr*)&name, sizeof name);
654 
655     if (!getSourcePort0(socket, portNum) || portNum == 0) {
656       socketErr(env, "getsockname() error: ");
657       return False;
658     }
659   }
660 
661   port = Port(portNum);
662   return True;
663 }
664 
badAddressForUs(ipv4AddressBits addr)665 static Boolean badAddressForUs(ipv4AddressBits addr) {
666   // Check for some possible erroneous addresses:
667   ipv4AddressBits nAddr = htonl(addr);
668   return (nAddr == 0x7F000001 /* 127.0.0.1 */
669 	  || nAddr == 0
670 	  || nAddr == (netAddressBits)(~0));
671 }
672 
badAddressForUs(struct sockaddr_storage const & addr)673 static Boolean badAddressForUs(struct sockaddr_storage const& addr) {
674   if (addr.ss_family != AF_INET) return True; // fix later for IPv6
675 
676   return badAddressForUs(((sockaddr_in*)&addr)->sin_addr.s_addr);
677 }
678 
679 Boolean loopbackWorks = 1;
680 
ourIPAddress(UsageEnvironment & env)681 netAddressBits ourIPAddress(UsageEnvironment& env) {
682   static netAddressBits ourAddress = 0;
683   int sock = -1;
684   struct in_addr testAddr;
685 
686   if (ReceivingInterfaceAddr != INADDR_ANY) {
687     // Hack: If we were told to receive on a specific interface address, then
688     // define this to be our ip address:
689     ourAddress = ReceivingInterfaceAddr;
690   }
691 
692   if (ourAddress == 0) {
693     // We need to find our source address
694     struct sockaddr_storage fromAddr;
695     fromAddr.ss_family = AF_INET;
696     ((sockaddr_in*)&fromAddr)->sin_addr.s_addr = 0;
697 
698     // Get our address by sending a (0-TTL) multicast packet,
699     // receiving it, and looking at the source address used.
700     // (This is kinda bogus, but it provides the best guarantee
701     // that other nodes will think our address is the same as we do.)
702     do {
703       loopbackWorks = 0; // until we learn otherwise
704 
705 #ifndef DISABLE_LOOPBACK_IP_ADDRESS_CHECK
706       if (inet_pton(AF_INET, "228.67.43.91", &testAddr.s_addr) != 1) break;
707           // The multicast address here was arbitrary
708       Port testPort(15947); // ditto
709 
710       sock = setupDatagramSocket(env, testPort);
711       if (sock < 0) break;
712 
713       if (!socketJoinGroup(env, sock, testAddr.s_addr)) break;
714 
715       unsigned char testString[] = "hostIdTest";
716       unsigned testStringLength = sizeof testString;
717 
718       if (!writeSocket(env, sock, testAddr, testPort.num(), 0,
719 		       testString, testStringLength)) break;
720 
721       // Block until the socket is readable (with a 5-second timeout):
722       fd_set rd_set;
723       FD_ZERO(&rd_set);
724       FD_SET((unsigned)sock, &rd_set);
725       const unsigned numFds = sock+1;
726       struct timeval timeout;
727       timeout.tv_sec = 5;
728       timeout.tv_usec = 0;
729       int result = select(numFds, &rd_set, NULL, NULL, &timeout);
730       if (result <= 0) break;
731 
732       unsigned char readBuffer[20];
733       int bytesRead = readSocket(env, sock,
734 				 readBuffer, sizeof readBuffer,
735 				 fromAddr);
736       if (bytesRead != (int)testStringLength
737 	  || strncmp((char*)readBuffer, (char*)testString, testStringLength) != 0) {
738 	break;
739       }
740 
741       // We use this packet's source address, if it's good:
742       loopbackWorks = !badAddressForUs(fromAddr);
743 #endif
744     } while (0);
745 
746     if (sock >= 0) {
747       socketLeaveGroup(env, sock, testAddr.s_addr);
748       closeSocket(sock);
749     }
750 
751     if (!loopbackWorks) do {
752       // We couldn't find our address using multicast loopback,
753       // so try instead to look it up directly - by first getting our host name, and then resolving this host name
754       char hostname[100];
755       hostname[0] = '\0';
756       int result = gethostname(hostname, sizeof hostname);
757       if (result != 0 || hostname[0] == '\0') {
758 	env.setResultErrMsg("initial gethostname() failed");
759 	break;
760       }
761 
762       // Try to resolve "hostname" to an IP address:
763       NetAddressList addresses(hostname);
764       NetAddressList::Iterator iter(addresses);
765       NetAddress const* address;
766 
767       // Take the first address that's not bad:
768       netAddressBits addr = 0;
769       while ((address = iter.nextAddress()) != NULL) {
770 	netAddressBits a = *(netAddressBits*)(address->data());
771 	if (!badAddressForUs(a)) {
772 	  addr = a;
773 	  break;
774 	}
775       }
776 
777       // Assign the address that we found to "fromAddr" (as if the 'loopback' method had worked), to simplify the code below:
778       fromAddr.ss_family = AF_INET;
779       ((sockaddr_in*)&fromAddr)->sin_addr.s_addr = addr;
780     } while (0);
781 
782     // Make sure we have a good address:
783     if (badAddressForUs(fromAddr)) {
784       char tmp[100];
785       sprintf(tmp, "This computer has an invalid IP address: %s", AddressString(fromAddr).val());
786       env.setResultMsg(tmp);
787       fromAddr.ss_family = AF_INET;
788       ((sockaddr_in*)&fromAddr)->sin_addr.s_addr = 0;
789     }
790 
791     ourAddress = fromAddr.ss_family == AF_INET ? ((sockaddr_in*)&fromAddr)->sin_addr.s_addr : 0;
792 
793     // Use our newly-discovered IP address, and the current time,
794     // to initialize the random number generator's seed:
795     struct timeval timeNow;
796     gettimeofday(&timeNow, NULL);
797     unsigned seed = ourAddress^timeNow.tv_sec^timeNow.tv_usec;
798     our_srandom(seed);
799   }
800   return ourAddress;
801 }
802 
chooseRandomIPv4SSMAddress(UsageEnvironment & env)803 netAddressBits chooseRandomIPv4SSMAddress(UsageEnvironment& env) {
804   // First, a hack to ensure that our random number generator is seeded:
805   (void) ourIPAddress(env);
806 
807   // Choose a random address in the range [232.0.1.0, 232.255.255.255)
808   // i.e., [0xE8000100, 0xE8FFFFFF)
809   netAddressBits const first = 0xE8000100, lastPlus1 = 0xE8FFFFFF;
810   netAddressBits const range = lastPlus1 - first;
811 
812   return ntohl(first + ((netAddressBits)our_random())%range);
813 }
814 
timestampString()815 char const* timestampString() {
816   struct timeval tvNow;
817   gettimeofday(&tvNow, NULL);
818 
819 #if !defined(_WIN32_WCE)
820   static char timeString[9]; // holds hh:mm:ss plus trailing '\0'
821 
822   time_t tvNow_t = tvNow.tv_sec;
823   char const* ctimeResult = ctime(&tvNow_t);
824   if (ctimeResult == NULL) {
825     sprintf(timeString, "??:??:??");
826   } else {
827     char const* from = &ctimeResult[11];
828     int i;
829     for (i = 0; i < 8; ++i) {
830       timeString[i] = from[i];
831     }
832     timeString[i] = '\0';
833   }
834 #else
835   // WinCE apparently doesn't have "ctime()", so instead, construct
836   // a timestamp string just using the integer and fractional parts
837   // of "tvNow":
838   static char timeString[50];
839   sprintf(timeString, "%lu.%06ld", tvNow.tv_sec, tvNow.tv_usec);
840 #endif
841 
842   return (char const*)&timeString;
843 }
844 
845 #if (defined(__WIN32__) || defined(_WIN32)) && !defined(__MINGW32__)
846 // For Windoze, we need to implement our own gettimeofday()
847 
848 // used to make sure that static variables in gettimeofday() aren't initialized simultaneously by multiple threads
849 static LONG initializeLock_gettimeofday = 0;
850 
851 #if !defined(_WIN32_WCE)
852 #include <sys/timeb.h>
853 #endif
854 
gettimeofday(struct timeval * tp,int *)855 int gettimeofday(struct timeval* tp, int* /*tz*/) {
856   static LARGE_INTEGER tickFrequency, epochOffset;
857 
858   static Boolean isInitialized = False;
859 
860   LARGE_INTEGER tickNow;
861 
862 #if !defined(_WIN32_WCE)
863   QueryPerformanceCounter(&tickNow);
864 #else
865   tickNow.QuadPart = GetTickCount();
866 #endif
867 
868   if (!isInitialized) {
869     if(1 == InterlockedIncrement(&initializeLock_gettimeofday)) {
870 #if !defined(_WIN32_WCE)
871       // For our first call, use "ftime()", so that we get a time with a proper epoch.
872       // For subsequent calls, use "QueryPerformanceCount()", because it's more fine-grain.
873       struct timeb tb;
874       ftime(&tb);
875       tp->tv_sec = tb.time;
876       tp->tv_usec = 1000*tb.millitm;
877 
878       // Also get our counter frequency:
879       QueryPerformanceFrequency(&tickFrequency);
880 #else
881       /* FILETIME of Jan 1 1970 00:00:00. */
882       const LONGLONG epoch = 116444736000000000LL;
883       FILETIME fileTime;
884       LARGE_INTEGER time;
885       GetSystemTimeAsFileTime(&fileTime);
886 
887       time.HighPart = fileTime.dwHighDateTime;
888       time.LowPart = fileTime.dwLowDateTime;
889 
890       // convert to from 100ns time to unix timestamp in seconds, 1000*1000*10
891       tp->tv_sec = (long)((time.QuadPart - epoch) / 10000000L);
892 
893       /*
894         GetSystemTimeAsFileTime has just a seconds resolution,
895         thats why wince-version of gettimeofday is not 100% accurate, usec accuracy would be calculated like this:
896         // convert 100 nanoseconds to usec
897         tp->tv_usec= (long)((time.QuadPart - epoch)%10000000L) / 10L;
898       */
899       tp->tv_usec = 0;
900 
901       // resolution of GetTickCounter() is always milliseconds
902       tickFrequency.QuadPart = 1000;
903 #endif
904       // compute an offset to add to subsequent counter times, so we get a proper epoch:
905       epochOffset.QuadPart
906           = tp->tv_sec * tickFrequency.QuadPart + (tp->tv_usec * tickFrequency.QuadPart) / 1000000L - tickNow.QuadPart;
907 
908       // next caller can use ticks for time calculation
909       isInitialized = True;
910       return 0;
911     } else {
912         InterlockedDecrement(&initializeLock_gettimeofday);
913         // wait until first caller has initialized static values
914         while(!isInitialized){
915           Sleep(1);
916         }
917     }
918   }
919 
920   // adjust our tick count so that we get a proper epoch:
921   tickNow.QuadPart += epochOffset.QuadPart;
922 
923   tp->tv_sec =  (long)(tickNow.QuadPart / tickFrequency.QuadPart);
924   tp->tv_usec = (long)(((tickNow.QuadPart % tickFrequency.QuadPart) * 1000000L) / tickFrequency.QuadPart);
925 
926   return 0;
927 }
928 #endif
929 #undef ANDROID_OLD_NDK
930