groupsock/GroupsockHelper.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "mTunnel" multicast access service
00017 // Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
00018 // Helper routines to implement 'group sockets'
00019 // Implementation
00020 
00021 #include "GroupsockHelper.hh"
00022 
00023 #if defined(__WIN32__) || defined(_WIN32)
00024 #include <time.h>
00025 extern "C" int initializeWinsockIfNecessary();
00026 #else
00027 #include <stdarg.h>
00028 #include <time.h>
00029 #include <fcntl.h>
00030 #define initializeWinsockIfNecessary() 1
00031 #endif
00032 #include <stdio.h>
00033 
00034 // By default, use INADDR_ANY for the sending and receiving interfaces:
00035 netAddressBits SendingInterfaceAddr = INADDR_ANY;
00036 netAddressBits ReceivingInterfaceAddr = INADDR_ANY;
00037 
00038 static void socketErr(UsageEnvironment& env, char const* errorMsg) {
00039   env.setResultErrMsg(errorMsg);
00040 }
00041 
00042 NoReuse::NoReuse(UsageEnvironment& env)
00043   : fEnv(env) {
00044   groupsockPriv(fEnv)->reuseFlag = 0;
00045 }
00046 
00047 NoReuse::~NoReuse() {
00048   groupsockPriv(fEnv)->reuseFlag = 1;
00049   reclaimGroupsockPriv(fEnv);
00050 }
00051 
00052 
00053 _groupsockPriv* groupsockPriv(UsageEnvironment& env) {
00054   if (env.groupsockPriv == NULL) { // We need to create it
00055     _groupsockPriv* result = new _groupsockPriv;
00056     result->socketTable = NULL;
00057     result->reuseFlag = 1; // default value => allow reuse of socket numbers
00058     env.groupsockPriv = result;
00059   }
00060   return (_groupsockPriv*)(env.groupsockPriv);
00061 }
00062 
00063 void reclaimGroupsockPriv(UsageEnvironment& env) {
00064   _groupsockPriv* priv = (_groupsockPriv*)(env.groupsockPriv);
00065   if (priv->socketTable == NULL && priv->reuseFlag == 1/*default value*/) {
00066     // We can delete the structure (to save space); it will get created again, if needed:
00067     delete priv;
00068     env.groupsockPriv = NULL;
00069   }
00070 }
00071 
00072 static int createSocket(int type) {
00073   // Call "socket()" to create a (IPv4) socket of the specified type.
00074   // But also set it to have the 'close on exec' property (if we can)
00075   int sock;
00076 
00077 #ifdef SOCK_CLOEXEC
00078   sock = socket(AF_INET, type|SOCK_CLOEXEC, 0);
00079   if (sock != -1 || errno != EINVAL) return sock;
00080   // An "errno" of EINVAL likely means that the system wasn't happy with the SOCK_CLOEXEC; fall through and try again without it:
00081 #endif
00082 
00083   sock = socket(AF_INET, type, 0);
00084 #ifdef FD_CLOEXEC
00085   if (sock != -1) fcntl(sock, F_SETFD, FD_CLOEXEC);
00086 #endif
00087   return sock;
00088 }
00089 
00090 int setupDatagramSocket(UsageEnvironment& env, Port port) {
00091   if (!initializeWinsockIfNecessary()) {
00092     socketErr(env, "Failed to initialize 'winsock': ");
00093     return -1;
00094   }
00095 
00096   int newSocket = createSocket(SOCK_DGRAM);
00097   if (newSocket < 0) {
00098     socketErr(env, "unable to create datagram socket: ");
00099     return newSocket;
00100   }
00101 
00102   int reuseFlag = groupsockPriv(env)->reuseFlag;
00103   reclaimGroupsockPriv(env);
00104   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
00105                  (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
00106     socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
00107     closeSocket(newSocket);
00108     return -1;
00109   }
00110 
00111 #if defined(__WIN32__) || defined(_WIN32)
00112   // Windoze doesn't properly handle SO_REUSEPORT or IP_MULTICAST_LOOP
00113 #else
00114 #ifdef SO_REUSEPORT
00115   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
00116                  (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
00117     socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
00118     closeSocket(newSocket);
00119     return -1;
00120   }
00121 #endif
00122 
00123 #ifdef IP_MULTICAST_LOOP
00124   const u_int8_t loop = 1;
00125   if (setsockopt(newSocket, IPPROTO_IP, IP_MULTICAST_LOOP,
00126                  (const char*)&loop, sizeof loop) < 0) {
00127     socketErr(env, "setsockopt(IP_MULTICAST_LOOP) error: ");
00128     closeSocket(newSocket);
00129     return -1;
00130   }
00131 #endif
00132 #endif
00133 
00134   // Note: Windoze requires binding, even if the port number is 0
00135   netAddressBits addr = INADDR_ANY;
00136 #if defined(__WIN32__) || defined(_WIN32)
00137 #else
00138   if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
00139 #endif
00140     if (port.num() == 0) addr = ReceivingInterfaceAddr;
00141     MAKE_SOCKADDR_IN(name, addr, port.num());
00142     if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
00143       char tmpBuffer[100];
00144       sprintf(tmpBuffer, "bind() error (port number: %d): ",
00145               ntohs(port.num()));
00146       socketErr(env, tmpBuffer);
00147       closeSocket(newSocket);
00148       return -1;
00149     }
00150 #if defined(__WIN32__) || defined(_WIN32)
00151 #else
00152   }
00153 #endif
00154 
00155   // Set the sending interface for multicasts, if it's not the default:
00156   if (SendingInterfaceAddr != INADDR_ANY) {
00157     struct in_addr addr;
00158     addr.s_addr = SendingInterfaceAddr;
00159 
00160     if (setsockopt(newSocket, IPPROTO_IP, IP_MULTICAST_IF,
00161                    (const char*)&addr, sizeof addr) < 0) {
00162       socketErr(env, "error setting outgoing multicast interface: ");
00163       closeSocket(newSocket);
00164       return -1;
00165     }
00166   }
00167 
00168   return newSocket;
00169 }
00170 
00171 Boolean makeSocketNonBlocking(int sock) {
00172 #if defined(__WIN32__) || defined(_WIN32)
00173   unsigned long arg = 1;
00174   return ioctlsocket(sock, FIONBIO, &arg) == 0;
00175 #elif defined(VXWORKS)
00176   int arg = 1;
00177   return ioctl(sock, FIONBIO, (int)&arg) == 0;
00178 #else
00179   int curFlags = fcntl(sock, F_GETFL, 0);
00180   return fcntl(sock, F_SETFL, curFlags|O_NONBLOCK) >= 0;
00181 #endif
00182 }
00183 
00184 Boolean makeSocketBlocking(int sock) {
00185 #if defined(__WIN32__) || defined(_WIN32)
00186   unsigned long arg = 0;
00187   return ioctlsocket(sock, FIONBIO, &arg) == 0;
00188 #elif defined(VXWORKS)
00189   int arg = 0;
00190   return ioctl(sock, FIONBIO, (int)&arg) == 0;
00191 #else
00192   int curFlags = fcntl(sock, F_GETFL, 0);
00193   return fcntl(sock, F_SETFL, curFlags&(~O_NONBLOCK)) >= 0;
00194 #endif
00195 }
00196 
00197 int setupStreamSocket(UsageEnvironment& env,
00198                       Port port, Boolean makeNonBlocking) {
00199   if (!initializeWinsockIfNecessary()) {
00200     socketErr(env, "Failed to initialize 'winsock': ");
00201     return -1;
00202   }
00203 
00204   int newSocket = createSocket(SOCK_STREAM);
00205   if (newSocket < 0) {
00206     socketErr(env, "unable to create stream socket: ");
00207     return newSocket;
00208   }
00209 
00210   int reuseFlag = groupsockPriv(env)->reuseFlag;
00211   reclaimGroupsockPriv(env);
00212   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
00213                  (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
00214     socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
00215     closeSocket(newSocket);
00216     return -1;
00217   }
00218 
00219   // SO_REUSEPORT doesn't really make sense for TCP sockets, so we
00220   // normally don't set them.  However, if you really want to do this
00221   // #define REUSE_FOR_TCP
00222 #ifdef REUSE_FOR_TCP
00223 #if defined(__WIN32__) || defined(_WIN32)
00224   // Windoze doesn't properly handle SO_REUSEPORT
00225 #else
00226 #ifdef SO_REUSEPORT
00227   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
00228                  (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
00229     socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
00230     closeSocket(newSocket);
00231     return -1;
00232   }
00233 #endif
00234 #endif
00235 #endif
00236 
00237   // Note: Windoze requires binding, even if the port number is 0
00238 #if defined(__WIN32__) || defined(_WIN32)
00239 #else
00240   if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
00241 #endif
00242     MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num());
00243     if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
00244       char tmpBuffer[100];
00245       sprintf(tmpBuffer, "bind() error (port number: %d): ",
00246               ntohs(port.num()));
00247       socketErr(env, tmpBuffer);
00248       closeSocket(newSocket);
00249       return -1;
00250     }
00251 #if defined(__WIN32__) || defined(_WIN32)
00252 #else
00253   }
00254 #endif
00255 
00256   if (makeNonBlocking) {
00257     if (!makeSocketNonBlocking(newSocket)) {
00258       socketErr(env, "failed to make non-blocking: ");
00259       closeSocket(newSocket);
00260       return -1;
00261     }
00262   }
00263 
00264   return newSocket;
00265 }
00266 
00267 int readSocket(UsageEnvironment& env,
00268                int socket, unsigned char* buffer, unsigned bufferSize,
00269                struct sockaddr_in& fromAddress) {
00270   SOCKLEN_T addressSize = sizeof fromAddress;
00271   int bytesRead = recvfrom(socket, (char*)buffer, bufferSize, 0,
00272                            (struct sockaddr*)&fromAddress,
00273                            &addressSize);
00274   if (bytesRead < 0) {
00275     //##### HACK to work around bugs in Linux and Windows:
00276     int err = env.getErrno();
00277     if (err == 111 /*ECONNREFUSED (Linux)*/
00278 #if defined(__WIN32__) || defined(_WIN32)
00279         // What a piece of crap Windows is.  Sometimes
00280         // recvfrom() returns -1, but with an 'errno' of 0.
00281         // This appears not to be a real error; just treat
00282         // it as if it were a read of zero bytes, and hope
00283         // we don't have to do anything else to 'reset'
00284         // this alleged error:
00285         || err == 0 || err == EWOULDBLOCK
00286 #else
00287         || err == EAGAIN
00288 #endif
00289         || err == 113 /*EHOSTUNREACH (Linux)*/) { // Why does Linux return this for datagram sock?
00290       fromAddress.sin_addr.s_addr = 0;
00291       return 0;
00292     }
00293     //##### END HACK
00294     socketErr(env, "recvfrom() error: ");
00295   } else if (bytesRead == 0) {
00296     // "recvfrom()" on a stream socket can return 0 if the remote end has closed the connection.  Treat this as an error:
00297     return -1;
00298   }
00299 
00300   return bytesRead;
00301 }
00302 
00303 Boolean writeSocket(UsageEnvironment& env,
00304                     int socket, struct in_addr address, Port port,
00305                     u_int8_t ttlArg,
00306                     unsigned char* buffer, unsigned bufferSize) {
00307         do {
00308                 if (ttlArg != 0) {
00309                         // Before sending, set the socket's TTL:
00310 #if defined(__WIN32__) || defined(_WIN32)
00311 #define TTL_TYPE int
00312 #else
00313 #define TTL_TYPE u_int8_t
00314 #endif
00315                         TTL_TYPE ttl = (TTL_TYPE)ttlArg;
00316                         if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL,
00317                                        (const char*)&ttl, sizeof ttl) < 0) {
00318                                 socketErr(env, "setsockopt(IP_MULTICAST_TTL) error: ");
00319                                 break;
00320                         }
00321                 }
00322 
00323                 MAKE_SOCKADDR_IN(dest, address.s_addr, port.num());
00324                 int bytesSent = sendto(socket, (char*)buffer, bufferSize, 0,
00325                                        (struct sockaddr*)&dest, sizeof dest);
00326                 if (bytesSent != (int)bufferSize) {
00327                         char tmpBuf[100];
00328                         sprintf(tmpBuf, "writeSocket(%d), sendTo() error: wrote %d bytes instead of %u: ", socket, bytesSent, bufferSize);
00329                         socketErr(env, tmpBuf);
00330                         break;
00331                 }
00332 
00333                 return True;
00334         } while (0);
00335 
00336         return False;
00337 }
00338 
00339 static unsigned getBufferSize(UsageEnvironment& env, int bufOptName,
00340                               int socket) {
00341   unsigned curSize;
00342   SOCKLEN_T sizeSize = sizeof curSize;
00343   if (getsockopt(socket, SOL_SOCKET, bufOptName,
00344                  (char*)&curSize, &sizeSize) < 0) {
00345     socketErr(env, "getBufferSize() error: ");
00346     return 0;
00347   }
00348 
00349   return curSize;
00350 }
00351 unsigned getSendBufferSize(UsageEnvironment& env, int socket) {
00352   return getBufferSize(env, SO_SNDBUF, socket);
00353 }
00354 unsigned getReceiveBufferSize(UsageEnvironment& env, int socket) {
00355   return getBufferSize(env, SO_RCVBUF, socket);
00356 }
00357 
00358 static unsigned setBufferTo(UsageEnvironment& env, int bufOptName,
00359                             int socket, unsigned requestedSize) {
00360   SOCKLEN_T sizeSize = sizeof requestedSize;
00361   setsockopt(socket, SOL_SOCKET, bufOptName, (char*)&requestedSize, sizeSize);
00362 
00363   // Get and return the actual, resulting buffer size:
00364   return getBufferSize(env, bufOptName, socket);
00365 }
00366 unsigned setSendBufferTo(UsageEnvironment& env,
00367                          int socket, unsigned requestedSize) {
00368         return setBufferTo(env, SO_SNDBUF, socket, requestedSize);
00369 }
00370 unsigned setReceiveBufferTo(UsageEnvironment& env,
00371                             int socket, unsigned requestedSize) {
00372         return setBufferTo(env, SO_RCVBUF, socket, requestedSize);
00373 }
00374 
00375 static unsigned increaseBufferTo(UsageEnvironment& env, int bufOptName,
00376                                  int socket, unsigned requestedSize) {
00377   // First, get the current buffer size.  If it's already at least
00378   // as big as what we're requesting, do nothing.
00379   unsigned curSize = getBufferSize(env, bufOptName, socket);
00380 
00381   // Next, try to increase the buffer to the requested size,
00382   // or to some smaller size, if that's not possible:
00383   while (requestedSize > curSize) {
00384     SOCKLEN_T sizeSize = sizeof requestedSize;
00385     if (setsockopt(socket, SOL_SOCKET, bufOptName,
00386                    (char*)&requestedSize, sizeSize) >= 0) {
00387       // success
00388       return requestedSize;
00389     }
00390     requestedSize = (requestedSize+curSize)/2;
00391   }
00392 
00393   return getBufferSize(env, bufOptName, socket);
00394 }
00395 unsigned increaseSendBufferTo(UsageEnvironment& env,
00396                               int socket, unsigned requestedSize) {
00397   return increaseBufferTo(env, SO_SNDBUF, socket, requestedSize);
00398 }
00399 unsigned increaseReceiveBufferTo(UsageEnvironment& env,
00400                                  int socket, unsigned requestedSize) {
00401   return increaseBufferTo(env, SO_RCVBUF, socket, requestedSize);
00402 }
00403 
00404 Boolean socketJoinGroup(UsageEnvironment& env, int socket,
00405                         netAddressBits groupAddress){
00406   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
00407 
00408   struct ip_mreq imr;
00409   imr.imr_multiaddr.s_addr = groupAddress;
00410   imr.imr_interface.s_addr = ReceivingInterfaceAddr;
00411   if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
00412                  (const char*)&imr, sizeof (struct ip_mreq)) < 0) {
00413 #if defined(__WIN32__) || defined(_WIN32)
00414     if (env.getErrno() != 0) {
00415       // That piece-of-shit toy operating system (Windows) sometimes lies
00416       // about setsockopt() failing!
00417 #endif
00418       socketErr(env, "setsockopt(IP_ADD_MEMBERSHIP) error: ");
00419       return False;
00420 #if defined(__WIN32__) || defined(_WIN32)
00421     }
00422 #endif
00423   }
00424 
00425   return True;
00426 }
00427 
00428 Boolean socketLeaveGroup(UsageEnvironment&, int socket,
00429                          netAddressBits groupAddress) {
00430   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
00431 
00432   struct ip_mreq imr;
00433   imr.imr_multiaddr.s_addr = groupAddress;
00434   imr.imr_interface.s_addr = ReceivingInterfaceAddr;
00435   if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
00436                  (const char*)&imr, sizeof (struct ip_mreq)) < 0) {
00437     return False;
00438   }
00439 
00440   return True;
00441 }
00442 
00443 // The source-specific join/leave operations require special setsockopt()
00444 // commands, and a special structure (ip_mreq_source).  If the include files
00445 // didn't define these, we do so here:
00446 #if !defined(IP_ADD_SOURCE_MEMBERSHIP)
00447 struct ip_mreq_source {
00448   struct  in_addr imr_multiaddr;  /* IP multicast address of group */
00449   struct  in_addr imr_sourceaddr; /* IP address of source */
00450   struct  in_addr imr_interface;  /* local IP address of interface */
00451 };
00452 #endif
00453 
00454 #ifndef IP_ADD_SOURCE_MEMBERSHIP
00455 
00456 #ifdef LINUX
00457 #define IP_ADD_SOURCE_MEMBERSHIP   39
00458 #define IP_DROP_SOURCE_MEMBERSHIP 40
00459 #else
00460 #define IP_ADD_SOURCE_MEMBERSHIP   25
00461 #define IP_DROP_SOURCE_MEMBERSHIP 26
00462 #endif
00463 
00464 #endif
00465 
00466 Boolean socketJoinGroupSSM(UsageEnvironment& env, int socket,
00467                            netAddressBits groupAddress,
00468                            netAddressBits sourceFilterAddr) {
00469   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
00470 
00471   struct ip_mreq_source imr;
00472 #ifdef ANDROID
00473     imr.imr_multiaddr = groupAddress;
00474     imr.imr_sourceaddr = sourceFilterAddr;
00475     imr.imr_interface = ReceivingInterfaceAddr;
00476 #else
00477     imr.imr_multiaddr.s_addr = groupAddress;
00478     imr.imr_sourceaddr.s_addr = sourceFilterAddr;
00479     imr.imr_interface.s_addr = ReceivingInterfaceAddr;
00480 #endif
00481   if (setsockopt(socket, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
00482                  (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) {
00483     socketErr(env, "setsockopt(IP_ADD_SOURCE_MEMBERSHIP) error: ");
00484     return False;
00485   }
00486 
00487   return True;
00488 }
00489 
00490 Boolean socketLeaveGroupSSM(UsageEnvironment& /*env*/, int socket,
00491                             netAddressBits groupAddress,
00492                             netAddressBits sourceFilterAddr) {
00493   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
00494 
00495   struct ip_mreq_source imr;
00496 #ifdef ANDROID
00497     imr.imr_multiaddr = groupAddress;
00498     imr.imr_sourceaddr = sourceFilterAddr;
00499     imr.imr_interface = ReceivingInterfaceAddr;
00500 #else
00501     imr.imr_multiaddr.s_addr = groupAddress;
00502     imr.imr_sourceaddr.s_addr = sourceFilterAddr;
00503     imr.imr_interface.s_addr = ReceivingInterfaceAddr;
00504 #endif
00505   if (setsockopt(socket, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP,
00506                  (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) {
00507     return False;
00508   }
00509 
00510   return True;
00511 }
00512 
00513 static Boolean getSourcePort0(int socket, portNumBits& resultPortNum/*host order*/) {
00514   sockaddr_in test; test.sin_port = 0;
00515   SOCKLEN_T len = sizeof test;
00516   if (getsockname(socket, (struct sockaddr*)&test, &len) < 0) return False;
00517 
00518   resultPortNum = ntohs(test.sin_port);
00519   return True;
00520 }
00521 
00522 Boolean getSourcePort(UsageEnvironment& env, int socket, Port& port) {
00523   portNumBits portNum = 0;
00524   if (!getSourcePort0(socket, portNum) || portNum == 0) {
00525     // Hack - call bind(), then try again:
00526     MAKE_SOCKADDR_IN(name, INADDR_ANY, 0);
00527     bind(socket, (struct sockaddr*)&name, sizeof name);
00528 
00529     if (!getSourcePort0(socket, portNum) || portNum == 0) {
00530       socketErr(env, "getsockname() error: ");
00531       return False;
00532     }
00533   }
00534 
00535   port = Port(portNum);
00536   return True;
00537 }
00538 
00539 static Boolean badAddressForUs(netAddressBits addr) {
00540   // Check for some possible erroneous addresses:
00541   netAddressBits nAddr = htonl(addr);
00542   return (nAddr == 0x7F000001 /* 127.0.0.1 */
00543           || nAddr == 0
00544           || nAddr == (netAddressBits)(~0));
00545 }
00546 
00547 Boolean loopbackWorks = 1;
00548 
00549 netAddressBits ourIPAddress(UsageEnvironment& env) {
00550   static netAddressBits ourAddress = 0;
00551   int sock = -1;
00552   struct in_addr testAddr;
00553 
00554   if (ourAddress == 0) {
00555     // We need to find our source address
00556     struct sockaddr_in fromAddr;
00557     fromAddr.sin_addr.s_addr = 0;
00558 
00559     // Get our address by sending a (0-TTL) multicast packet,
00560     // receiving it, and looking at the source address used.
00561     // (This is kinda bogus, but it provides the best guarantee
00562     // that other nodes will think our address is the same as we do.)
00563     do {
00564       loopbackWorks = 0; // until we learn otherwise
00565 
00566       testAddr.s_addr = our_inet_addr("228.67.43.91"); // arbitrary
00567       Port testPort(15947); // ditto
00568 
00569       sock = setupDatagramSocket(env, testPort);
00570       if (sock < 0) break;
00571 
00572       if (!socketJoinGroup(env, sock, testAddr.s_addr)) break;
00573 
00574       unsigned char testString[] = "hostIdTest";
00575       unsigned testStringLength = sizeof testString;
00576 
00577       if (!writeSocket(env, sock, testAddr, testPort, 0,
00578                        testString, testStringLength)) break;
00579 
00580       // Block until the socket is readable (with a 5-second timeout):
00581       fd_set rd_set;
00582       FD_ZERO(&rd_set);
00583       FD_SET((unsigned)sock, &rd_set);
00584       const unsigned numFds = sock+1;
00585       struct timeval timeout;
00586       timeout.tv_sec = 5;
00587       timeout.tv_usec = 0;
00588       int result = select(numFds, &rd_set, NULL, NULL, &timeout);
00589       if (result <= 0) break;
00590 
00591       unsigned char readBuffer[20];
00592       int bytesRead = readSocket(env, sock,
00593                                  readBuffer, sizeof readBuffer,
00594                                  fromAddr);
00595       if (bytesRead != (int)testStringLength
00596           || strncmp((char*)readBuffer, (char*)testString, testStringLength) != 0) {
00597         break;
00598       }
00599 
00600       // We use this packet's source address, if it's good:
00601       loopbackWorks = !badAddressForUs(fromAddr.sin_addr.s_addr);
00602     } while (0);
00603 
00604     if (sock >= 0) {
00605       socketLeaveGroup(env, sock, testAddr.s_addr);
00606       closeSocket(sock);
00607     }
00608 
00609     if (!loopbackWorks) do {
00610       // We couldn't find our address using multicast loopback,
00611       // so try instead to look it up directly - by first getting our host name, and then resolving this host name
00612       char hostname[100];
00613       hostname[0] = '\0';
00614       int result = gethostname(hostname, sizeof hostname);
00615       if (result != 0 || hostname[0] == '\0') {
00616         env.setResultErrMsg("initial gethostname() failed");
00617         break;
00618       }
00619 
00620       // Try to resolve "hostname" to an IP address:
00621       NetAddressList addresses(hostname);
00622       NetAddressList::Iterator iter(addresses);
00623       NetAddress const* address;
00624 
00625       // Take the first address that's not bad:
00626       netAddressBits addr = 0;
00627       while ((address = iter.nextAddress()) != NULL) {
00628         netAddressBits a = *(netAddressBits*)(address->data());
00629         if (!badAddressForUs(a)) {
00630           addr = a;
00631           break;
00632         }
00633       }
00634 
00635       // Assign the address that we found to "fromAddr" (as if the 'loopback' method had worked), to simplify the code below: 
00636       fromAddr.sin_addr.s_addr = addr;
00637     } while (0);
00638 
00639     // Make sure we have a good address:
00640     netAddressBits from = fromAddr.sin_addr.s_addr;
00641     if (badAddressForUs(from)) {
00642       char tmp[100];
00643       sprintf(tmp, "This computer has an invalid IP address: %s", AddressString(from).val());
00644       env.setResultMsg(tmp);
00645       from = 0;
00646     }
00647 
00648     ourAddress = from;
00649 
00650     // Use our newly-discovered IP address, and the current time,
00651     // to initialize the random number generator's seed:
00652     struct timeval timeNow;
00653     gettimeofday(&timeNow, NULL);
00654     unsigned seed = ourAddress^timeNow.tv_sec^timeNow.tv_usec;
00655     our_srandom(seed);
00656   }
00657   return ourAddress;
00658 }
00659 
00660 netAddressBits chooseRandomIPv4SSMAddress(UsageEnvironment& env) {
00661   // First, a hack to ensure that our random number generator is seeded:
00662   (void) ourIPAddress(env);
00663 
00664   // Choose a random address in the range [232.0.1.0, 232.255.255.255)
00665   // i.e., [0xE8000100, 0xE8FFFFFF)
00666   netAddressBits const first = 0xE8000100, lastPlus1 = 0xE8FFFFFF;
00667   netAddressBits const range = lastPlus1 - first;
00668 
00669   return ntohl(first + ((netAddressBits)our_random())%range);
00670 }
00671 
00672 char const* timestampString() {
00673   struct timeval tvNow;
00674   gettimeofday(&tvNow, NULL);
00675 
00676 #if !defined(_WIN32_WCE)
00677   static char timeString[9]; // holds hh:mm:ss plus trailing '\0'
00678   char const* ctimeResult = ctime((time_t*)&tvNow.tv_sec);
00679   if (ctimeResult == NULL) {
00680     sprintf(timeString, "??:??:??");
00681   } else {
00682     char const* from = &ctimeResult[11];
00683     int i;
00684     for (i = 0; i < 8; ++i) {
00685       timeString[i] = from[i];
00686     }
00687     timeString[i] = '\0';
00688   }
00689 #else
00690   // WinCE apparently doesn't have "ctime()", so instead, construct
00691   // a timestamp string just using the integer and fractional parts
00692   // of "tvNow":
00693   static char timeString[50];
00694   sprintf(timeString, "%lu.%06ld", tvNow.tv_sec, tvNow.tv_usec);
00695 #endif
00696 
00697   return (char const*)&timeString;
00698 }
00699 
00700 #if defined(__WIN32__) || defined(_WIN32)
00701 // For Windoze, we need to implement our own gettimeofday()
00702 
00703 // used to make sure that static variables in gettimeofday() aren't initialized simultaneously by multiple threads
00704 static LONG initializeLock_gettimeofday = 0;  
00705 
00706 #if !defined(_WIN32_WCE)
00707 #include <sys/timeb.h>
00708 #endif
00709 
00710 int gettimeofday(struct timeval* tp, int* /*tz*/) {
00711   static LARGE_INTEGER tickFrequency, epochOffset;
00712 
00713   static Boolean isInitialized = False;
00714 
00715   LARGE_INTEGER tickNow;
00716 
00717 #if !defined(_WIN32_WCE)
00718   QueryPerformanceCounter(&tickNow);
00719 #else
00720   tickNow.QuadPart = GetTickCount();
00721 #endif
00722  
00723   if (!isInitialized) {
00724     if(1 == InterlockedIncrement(&initializeLock_gettimeofday)) {
00725 #if !defined(_WIN32_WCE)
00726       // For our first call, use "ftime()", so that we get a time with a proper epoch.
00727       // For subsequent calls, use "QueryPerformanceCount()", because it's more fine-grain.
00728       struct timeb tb;
00729       ftime(&tb);
00730       tp->tv_sec = tb.time;
00731       tp->tv_usec = 1000*tb.millitm;
00732 
00733       // Also get our counter frequency:
00734       QueryPerformanceFrequency(&tickFrequency);
00735 #else
00736       /* FILETIME of Jan 1 1970 00:00:00. */
00737       const LONGLONG epoch = 116444736000000000LL;
00738       FILETIME fileTime;
00739       LARGE_INTEGER time;
00740       GetSystemTimeAsFileTime(&fileTime);
00741 
00742       time.HighPart = fileTime.dwHighDateTime;
00743       time.LowPart = fileTime.dwLowDateTime;
00744 
00745       // convert to from 100ns time to unix timestamp in seconds, 1000*1000*10
00746       tp->tv_sec = (long)((time.QuadPart - epoch) / 10000000L);
00747 
00748       /*
00749         GetSystemTimeAsFileTime has just a seconds resolution,
00750         thats why wince-version of gettimeofday is not 100% accurate, usec accuracy would be calculated like this:
00751         // convert 100 nanoseconds to usec
00752         tp->tv_usec= (long)((time.QuadPart - epoch)%10000000L) / 10L;
00753       */
00754       tp->tv_usec = 0;
00755 
00756       // resolution of GetTickCounter() is always milliseconds
00757       tickFrequency.QuadPart = 1000;
00758 #endif     
00759       // compute an offset to add to subsequent counter times, so we get a proper epoch:
00760       epochOffset.QuadPart
00761           = tp->tv_sec * tickFrequency.QuadPart + (tp->tv_usec * tickFrequency.QuadPart) / 1000000L - tickNow.QuadPart;
00762       
00763       // next caller can use ticks for time calculation
00764       isInitialized = True; 
00765       return 0;
00766     } else {
00767         InterlockedDecrement(&initializeLock_gettimeofday);
00768         // wait until first caller has initialized static values
00769         while(!isInitialized){
00770           Sleep(1);
00771         }
00772     }
00773   }
00774 
00775   // adjust our tick count so that we get a proper epoch:
00776   tickNow.QuadPart += epochOffset.QuadPart;
00777 
00778   tp->tv_sec =  (long)(tickNow.QuadPart / tickFrequency.QuadPart);
00779   tp->tv_usec = (long)(((tickNow.QuadPart % tickFrequency.QuadPart) * 1000000L) / tickFrequency.QuadPart);
00780 
00781   return 0;
00782 }
00783 #endif

Generated on Mon Apr 29 13:28:00 2013 for live by  doxygen 1.5.2