MythTV  0.26-pre
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 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00015 **********/
00016 // "mTunnel" multicast access service
00017 // Copyright (c) 1996-2005 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 netAddressBits ReceivingSocketAddr = INADDR_ANY;
00038 
00039 static void socketErr(UsageEnvironment& env, char* errorMsg) {
00040         env.setResultErrMsg(errorMsg);
00041 }
00042 
00043 int setupDatagramSocket(UsageEnvironment& env, Port port,
00044 #ifdef IP_MULTICAST_LOOP
00045                         Boolean setLoopback
00046 #else
00047                         Boolean
00048 #endif
00049 ) {
00050   if (!initializeWinsockIfNecessary()) {
00051     socketErr(env, "Failed to initialize 'winsock': ");
00052     return -1;
00053   }
00054   
00055   int newSocket = socket(AF_INET, SOCK_DGRAM, 0);
00056   if (newSocket < 0) {
00057     socketErr(env, "unable to create datagram socket: ");
00058     return newSocket;
00059   }
00060   
00061   const int reuseFlag = 1;
00062   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
00063                  (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
00064     socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
00065     closeSocket(newSocket);
00066     return -1;
00067   }
00068   
00069 #if defined(__WIN32__) || defined(_WIN32)
00070   // Windoze doesn't handle SO_REUSEPORT or IP_MULTICAST_LOOP
00071 #else
00072 #ifdef SO_REUSEPORT
00073   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
00074                  (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
00075     socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
00076     closeSocket(newSocket);
00077     return -1;
00078   }
00079 #endif
00080   
00081 #ifdef IP_MULTICAST_LOOP
00082   const u_int8_t loop = (u_int8_t)setLoopback;
00083   if (setsockopt(newSocket, IPPROTO_IP, IP_MULTICAST_LOOP,
00084                  (const char*)&loop, sizeof loop) < 0) {
00085     socketErr(env, "setsockopt(IP_MULTICAST_LOOP) error: ");
00086     closeSocket(newSocket);
00087     return -1;
00088   }
00089 #endif
00090 #endif
00091   
00092   // Note: Windoze requires binding, even if the port number is 0
00093 #if defined(__WIN32__) || defined(_WIN32)
00094 #else
00095   if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
00096 #endif
00097     MAKE_SOCKADDR_IN(name, ReceivingSocketAddr, port.num());
00098     if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
00099       char tmpBuffer[100];
00100       sprintf(tmpBuffer, "bind() error (port number: %d): ",
00101               ntohs(port.num()));
00102       socketErr(env, tmpBuffer);
00103       closeSocket(newSocket);
00104       return -1;
00105     }
00106 #if defined(__WIN32__) || defined(_WIN32)
00107 #else
00108   }
00109 #endif
00110   
00111   // Set the sending interface for multicasts, if it's not the default:
00112   if (SendingInterfaceAddr != INADDR_ANY) {
00113     struct in_addr addr;
00114     addr.s_addr = SendingInterfaceAddr;
00115     
00116     if (setsockopt(newSocket, IPPROTO_IP, IP_MULTICAST_IF,
00117                    (const char*)&addr, sizeof addr) < 0) {
00118       socketErr(env, "error setting outgoing multicast interface: ");
00119       closeSocket(newSocket);
00120       return -1;
00121     }
00122   }
00123   
00124   return newSocket;
00125 }
00126 
00127 int setupStreamSocket(UsageEnvironment& env,
00128                       Port port, Boolean makeNonBlocking) {
00129   if (!initializeWinsockIfNecessary()) {
00130     socketErr(env, "Failed to initialize 'winsock': ");
00131     return -1;
00132   }
00133   
00134   int newSocket = socket(AF_INET, SOCK_STREAM, 0);
00135   if (newSocket < 0) {
00136     socketErr(env, "unable to create stream socket: ");
00137     return newSocket;
00138   }
00139   
00140   const int reuseFlag = 1;
00141   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
00142                  (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
00143     socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
00144     closeSocket(newSocket);
00145     return -1;
00146   }
00147   
00148   // SO_REUSEPORT doesn't really make sense for TCP sockets, so we
00149   // normally don't set them.  However, if you really want to do this
00150   // #define REUSE_FOR_TCP
00151 #ifdef REUSE_FOR_TCP
00152 #if defined(__WIN32__) || defined(_WIN32)
00153     // Windoze doesn't handle SO_REUSEPORT
00154 #else
00155 #ifdef SO_REUSEPORT
00156   if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
00157                  (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
00158     socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
00159     closeSocket(newSocket);
00160     return -1;
00161   }
00162 #endif
00163 #endif
00164 #endif
00165 
00166   // Note: Windoze requires binding, even if the port number is 0
00167 #if defined(__WIN32__) || defined(_WIN32)
00168 #else
00169   if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
00170 #endif
00171     MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num());
00172     if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
00173       char tmpBuffer[100];
00174       sprintf(tmpBuffer, "bind() error (port number: %d): ",
00175               ntohs(port.num()));
00176       socketErr(env, tmpBuffer);
00177       closeSocket(newSocket);
00178       return -1;
00179     }
00180 #if defined(__WIN32__) || defined(_WIN32)
00181 #else
00182   }
00183 #endif
00184 
00185   if (makeNonBlocking) {
00186     // Make the socket non-blocking:
00187 #if defined(__WIN32__) || defined(_WIN32) || defined(IMN_PIM)
00188     unsigned long arg = 1;
00189     if (ioctlsocket(newSocket, FIONBIO, &arg) != 0) {
00190 
00191 #elif defined(VXWORKS)
00192     int arg = 1;
00193     if (ioctl(newSocket, FIONBIO, (int)&arg) != 0) {
00194 
00195 #else
00196     int curFlags = fcntl(newSocket, F_GETFL, 0);
00197     if (fcntl(newSocket, F_SETFL, curFlags|O_NONBLOCK) < 0) {
00198 #endif
00199       socketErr(env, "failed to make non-blocking: ");
00200       closeSocket(newSocket);
00201       return -1;
00202     }
00203   }
00204 
00205   return newSocket;
00206 }
00207 
00208 #ifndef IMN_PIM
00209 static int blockUntilReadable(UsageEnvironment& env,
00210                               int socket, struct timeval* timeout) {
00211   int result = -1;
00212   do {
00213     fd_set rd_set;
00214     FD_ZERO(&rd_set);
00215     if (socket < 0) break;
00216     FD_SET((unsigned) socket, &rd_set);
00217     const unsigned numFds = socket+1;
00218     
00219     result = select(numFds, &rd_set, NULL, NULL, timeout);
00220     if (timeout != NULL && result == 0) {
00221       break; // this is OK - timeout occurred
00222     } else if (result <= 0) {
00223 #if defined(__WIN32__) || defined(_WIN32)
00224 #else
00225       if (errno == EINTR || errno == EAGAIN) continue;
00226 #endif
00227       socketErr(env, "select() error: ");
00228       break;
00229     }
00230     
00231     if (!FD_ISSET(socket, &rd_set)) {
00232       socketErr(env, "select() error - !FD_ISSET");
00233       break;
00234     }
00235   } while (0);
00236 
00237   return result;
00238 }
00239 #else
00240 extern int blockUntilReadable(UsageEnvironment& env,
00241                               int socket, struct timeval* timeout);
00242 #endif
00243 
00244 int readSocket(UsageEnvironment& env,
00245                int socket, unsigned char* buffer, unsigned bufferSize,
00246                struct sockaddr_in& fromAddress,
00247                struct timeval* timeout) {
00248   int bytesRead = -1;
00249   do {
00250     int result = blockUntilReadable(env, socket, timeout);
00251     if (timeout != NULL && result == 0) {
00252       bytesRead = 0;
00253       break;
00254     } else if (result <= 0) {
00255       break;
00256     }
00257     
00258     SOCKLEN_T addressSize = sizeof fromAddress;
00259     bytesRead = recvfrom(socket, (char*)buffer, bufferSize, 0,
00260                          (struct sockaddr*)&fromAddress,
00261                          &addressSize);
00262     if (bytesRead < 0) {
00263       //##### HACK to work around bugs in Linux and Windows:
00264       int err = env.getErrno();
00265       if (err == 111 /*ECONNREFUSED (Linux)*/
00266 #if defined(__WIN32__) || defined(_WIN32)
00267           // What a piece of crap Windows is.  Sometimes
00268           // recvfrom() returns -1, but with an 'errno' of 0.
00269           // This appears not to be a real error; just treat
00270           // it as if it were a read of zero bytes, and hope
00271           // we don't have to do anything else to 'reset'
00272           // this alleged error:
00273           || err == 0
00274 #else
00275           || err == EAGAIN
00276 #endif
00277           || err == 113 /*EHOSTUNREACH (Linux)*/) {
00278                                 //Why does Linux return this for datagram sock?
00279         fromAddress.sin_addr.s_addr = 0;
00280         return 0;
00281       }
00282       //##### END HACK
00283       socketErr(env, "recvfrom() error: ");
00284       break;
00285     }
00286   } while (0);
00287   
00288   return bytesRead;
00289 }
00290 
00291 
00292 int readSocketExact(UsageEnvironment& env,
00293                     int socket, unsigned char* buffer, unsigned bufferSize,
00294                     struct sockaddr_in& fromAddress,
00295                     struct timeval* timeout) {
00296   /* read EXACTLY bufferSize bytes from the socket into the buffer.
00297      fromaddress is address of last read.
00298      return the number of bytes acually read when an error occurs
00299   */
00300   int bsize = bufferSize;
00301   int bytesRead = 0;
00302   int totBytesRead =0;
00303   do {
00304     bytesRead = readSocket (env, socket, buffer + totBytesRead, bsize,
00305                             fromAddress, timeout);
00306     if (bytesRead <= 0) break;
00307     totBytesRead += bytesRead;
00308     bsize -= bytesRead;
00309   } while (bsize != 0);
00310 
00311   return totBytesRead;
00312 }
00313 
00314 Boolean writeSocket(UsageEnvironment& env,
00315                     int socket, struct in_addr address, Port port,
00316                     u_int8_t ttlArg,
00317                     unsigned char* buffer, unsigned bufferSize) {
00318         do {
00319                 if (ttlArg != 0) {
00320                         // Before sending, set the socket's TTL:
00321 #if defined(__WIN32__) || defined(_WIN32)
00322 #define TTL_TYPE int
00323 #else
00324 #define TTL_TYPE u_int8_t
00325 #endif
00326                         TTL_TYPE ttl = (TTL_TYPE)ttlArg;
00327                         if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL,
00328                                        (const char*)&ttl, sizeof ttl) < 0) {
00329                                 socketErr(env, "setsockopt(IP_MULTICAST_TTL) error: ");
00330                                 break;
00331                         }
00332                 }
00333 
00334                 MAKE_SOCKADDR_IN(dest, address.s_addr, port.num());
00335                 int bytesSent = sendto(socket, (char*)buffer, bufferSize, 0,
00336                                        (struct sockaddr*)&dest, sizeof dest);
00337                 if (bytesSent != (int)bufferSize) {
00338                         char tmpBuf[100];
00339                         sprintf(tmpBuf, "writeSocket(%d), sendTo() error: wrote %d bytes instead of %u: ", socket, bytesSent, bufferSize);
00340                         socketErr(env, tmpBuf);
00341                         break;
00342                 }
00343 
00344                 return True;
00345         } while (0);
00346 
00347         return False;
00348 }
00349 
00350 static unsigned getBufferSize(UsageEnvironment& env, int bufOptName,
00351                               int socket) {
00352   unsigned curSize;
00353   SOCKLEN_T sizeSize = sizeof curSize;
00354   if (getsockopt(socket, SOL_SOCKET, bufOptName,
00355                  (char*)&curSize, &sizeSize) < 0) {
00356     socketErr(env, "getBufferSize() error: ");
00357     return 0;
00358   }
00359 
00360   return curSize;
00361 }
00362 unsigned getSendBufferSize(UsageEnvironment& env, int socket) {
00363   return getBufferSize(env, SO_SNDBUF, socket);
00364 }
00365 unsigned getReceiveBufferSize(UsageEnvironment& env, int socket) {
00366   return getBufferSize(env, SO_RCVBUF, socket);
00367 }
00368 
00369 static unsigned setBufferTo(UsageEnvironment& env, int bufOptName,
00370                             int socket, unsigned requestedSize) {
00371   SOCKLEN_T sizeSize = sizeof requestedSize;
00372   setsockopt(socket, SOL_SOCKET, bufOptName, (char*)&requestedSize, sizeSize);
00373 
00374   // Get and return the actual, resulting buffer size:
00375   return getBufferSize(env, bufOptName, socket);
00376 }
00377 unsigned setSendBufferTo(UsageEnvironment& env,
00378                          int socket, unsigned requestedSize) {
00379         return setBufferTo(env, SO_SNDBUF, socket, requestedSize);
00380 }
00381 unsigned setReceiveBufferTo(UsageEnvironment& env,
00382                             int socket, unsigned requestedSize) {
00383         return setBufferTo(env, SO_RCVBUF, socket, requestedSize);
00384 }
00385 
00386 static unsigned increaseBufferTo(UsageEnvironment& env, int bufOptName,
00387                                  int socket, unsigned requestedSize) {
00388   // First, get the current buffer size.  If it's already at least
00389   // as big as what we're requesting, do nothing.
00390   unsigned curSize = getBufferSize(env, bufOptName, socket);
00391 
00392   // Next, try to increase the buffer to the requested size,
00393   // or to some smaller size, if that's not possible:
00394   while (requestedSize > curSize) {
00395     SOCKLEN_T sizeSize = sizeof requestedSize;
00396     if (setsockopt(socket, SOL_SOCKET, bufOptName,
00397                    (char*)&requestedSize, sizeSize) >= 0) {
00398       // success
00399       return requestedSize;
00400     }
00401     requestedSize = (requestedSize+curSize)/2;
00402   }
00403 
00404   return getBufferSize(env, bufOptName, socket);
00405 }
00406 unsigned increaseSendBufferTo(UsageEnvironment& env,
00407                               int socket, unsigned requestedSize) {
00408   return increaseBufferTo(env, SO_SNDBUF, socket, requestedSize);
00409 }
00410 unsigned increaseReceiveBufferTo(UsageEnvironment& env,
00411                                  int socket, unsigned requestedSize) {
00412   return increaseBufferTo(env, SO_RCVBUF, socket, requestedSize);
00413 }
00414 
00415 Boolean socketJoinGroup(UsageEnvironment& env, int socket,
00416                         netAddressBits groupAddress){
00417   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
00418 
00419   struct ip_mreq imr;
00420   imr.imr_multiaddr.s_addr = groupAddress;
00421   imr.imr_interface.s_addr = ReceivingInterfaceAddr;
00422   if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
00423                  (const char*)&imr, sizeof (struct ip_mreq)) < 0) {
00424 #if defined(__WIN32__) || defined(_WIN32)
00425     if (env.getErrno() != 0) {
00426       // That piece-of-shit toy operating system (Windows) sometimes lies
00427       // about setsockopt() failing!
00428 #endif
00429       socketErr(env, "setsockopt(IP_ADD_MEMBERSHIP) error: ");
00430       return False;
00431 #if defined(__WIN32__) || defined(_WIN32)
00432     }
00433 #endif
00434   }
00435   
00436   return True;
00437 }
00438 
00439 Boolean socketLeaveGroup(UsageEnvironment&, int socket,
00440                          netAddressBits groupAddress) {
00441   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
00442 
00443   struct ip_mreq imr;
00444   imr.imr_multiaddr.s_addr = groupAddress;
00445   imr.imr_interface.s_addr = ReceivingInterfaceAddr;
00446   if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
00447                  (const char*)&imr, sizeof (struct ip_mreq)) < 0) {
00448     return False;
00449   }
00450 
00451   return True;
00452 }
00453 
00454 // The source-specific join/leave operations require special setsockopt()
00455 // commands, and a special structure (ip_mreq_source).  If the include files
00456 // didn't define these, we do so here:
00457 #ifndef IP_ADD_SOURCE_MEMBERSHIP
00458 #ifdef LINUX
00459 #define IP_ADD_SOURCE_MEMBERSHIP   39
00460 #define IP_DROP_SOURCE_MEMBERSHIP 40
00461 #else
00462 #define IP_ADD_SOURCE_MEMBERSHIP   67
00463 #define IP_DROP_SOURCE_MEMBERSHIP 68
00464 #endif
00465 
00466 struct ip_mreq_source {
00467   struct  in_addr imr_multiaddr;  /* IP multicast address of group */
00468   struct  in_addr imr_sourceaddr; /* IP address of source */
00469   struct  in_addr imr_interface;  /* local IP address of interface */
00470 };
00471 #endif
00472 
00473 Boolean socketJoinGroupSSM(UsageEnvironment& env, int socket,
00474                            netAddressBits groupAddress,
00475                            netAddressBits sourceFilterAddr) {
00476   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
00477 
00478   struct ip_mreq_source imr;
00479   imr.imr_multiaddr.s_addr = groupAddress;
00480   imr.imr_sourceaddr.s_addr = sourceFilterAddr;
00481   imr.imr_interface.s_addr = ReceivingInterfaceAddr;
00482   if (setsockopt(socket, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
00483                  (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) {
00484     socketErr(env, "setsockopt(IP_ADD_SOURCE_MEMBERSHIP) error: ");
00485     return False;
00486   }
00487   
00488   return True;
00489 }
00490 
00491 Boolean socketLeaveGroupSSM(UsageEnvironment& /*env*/, int socket,
00492                             netAddressBits groupAddress,
00493                             netAddressBits sourceFilterAddr) {
00494   if (!IsMulticastAddress(groupAddress)) return True; // ignore this case
00495 
00496   struct ip_mreq_source imr;
00497   imr.imr_multiaddr.s_addr = groupAddress;
00498   imr.imr_sourceaddr.s_addr = sourceFilterAddr;
00499   imr.imr_interface.s_addr = ReceivingInterfaceAddr;
00500   if (setsockopt(socket, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP,
00501                  (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) {
00502     return False;
00503   }
00504   
00505   return True;
00506 }
00507 
00508 static Boolean getSourcePort0(int socket, portNumBits& resultPortNum/*host order*/) {
00509   sockaddr_in test; test.sin_port = 0;
00510   SOCKLEN_T len = sizeof test;
00511   if (getsockname(socket, (struct sockaddr*)&test, &len) < 0) return False;
00512   
00513   resultPortNum = ntohs(test.sin_port);
00514   return True;
00515 }
00516 
00517 Boolean getSourcePort(UsageEnvironment& env, int socket, Port& port) {
00518   portNumBits portNum = 0;
00519   if (!getSourcePort0(socket, portNum) || portNum == 0) {
00520     // Hack - call bind(), then try again:
00521     MAKE_SOCKADDR_IN(name, INADDR_ANY, 0);
00522     bind(socket, (struct sockaddr*)&name, sizeof name);
00523 
00524     if (!getSourcePort0(socket, portNum) || portNum == 0) {
00525       socketErr(env, "getsockname() error: ");
00526       return False;
00527     }
00528   }
00529   
00530   port = Port(portNum);
00531   return True;
00532 }
00533 
00534 static Boolean badAddress(netAddressBits addr) {
00535   // Check for some possible erroneous addresses:
00536   netAddressBits hAddr = ntohl(addr);
00537   return (hAddr == 0x7F000001 /* 127.0.0.1 */
00538           || hAddr == 0
00539           || hAddr == (netAddressBits)(~0));
00540 }
00541 
00542 Boolean loopbackWorks = 1;
00543 
00544 netAddressBits ourSourceAddressForMulticast(UsageEnvironment& env) {
00545   static netAddressBits ourAddress = 0;
00546   int sock = -1;
00547   struct in_addr testAddr;
00548   
00549   if (ourAddress == 0) {
00550     // We need to find our source address
00551     struct sockaddr_in fromAddr;
00552     fromAddr.sin_addr.s_addr = 0;
00553     
00554     // Get our address by sending a (0-TTL) multicast packet,
00555     // receiving it, and looking at the source address used.
00556     // (This is kinda bogus, but it provides the best guarantee
00557     // that other nodes will think our address is the same as we do.)
00558     do {
00559       loopbackWorks = 0; // until we learn otherwise
00560 
00561       testAddr.s_addr = our_inet_addr("228.67.43.91"); // arbitrary
00562       Port testPort(15947); // ditto
00563       
00564       ReceivingSocketAddr = INADDR_ANY;
00565 
00566       sock = setupDatagramSocket(env, testPort);
00567       if (sock < 0) break;
00568       
00569       if (!socketJoinGroup(env, sock, testAddr.s_addr)) break;
00570       
00571       unsigned char testString[] = "hostIdTest";
00572       unsigned testStringLength = sizeof testString;
00573       
00574       if (!writeSocket(env, sock, testAddr, testPort, 0,
00575                        testString, testStringLength)) break;
00576       
00577       unsigned char readBuffer[20];
00578       struct timeval timeout;
00579       timeout.tv_sec = 5;
00580       timeout.tv_usec = 0;
00581       int bytesRead = readSocket(env, sock,
00582                                  readBuffer, sizeof readBuffer,
00583                                  fromAddr, &timeout);
00584       if (bytesRead == 0 // timeout occurred
00585           || bytesRead != (int)testStringLength
00586           || strncmp((char*)readBuffer, (char*)testString,
00587                      testStringLength) != 0) {
00588         break;
00589       }
00590 
00591       loopbackWorks = 1;
00592     } while (0);
00593 
00594     if (!loopbackWorks) do {
00595       // We couldn't find our address using multicast loopback
00596       // so try instead to look it up directly.
00597       char hostname[100];
00598       hostname[0] = '\0';
00599 #ifndef CRIS
00600       gethostname(hostname, sizeof hostname);
00601 #endif
00602       if (hostname[0] == '\0') {
00603         env.setResultErrMsg("initial gethostname() failed");
00604         break;
00605       }
00606       
00607 #if defined(VXWORKS)
00608 #include <hostLib.h>
00609       if (ERROR == (ourAddress = hostGetByName( hostname ))) break;
00610 #else
00611       struct hostent* hstent
00612         = (struct hostent*)gethostbyname(hostname);
00613       if (hstent == NULL || hstent->h_length != 4) {
00614         env.setResultErrMsg("initial gethostbyname() failed");
00615         break;
00616       }
00617       // Take the first address that's not bad
00618       // (This code, like many others, won't handle IPv6)
00619       netAddressBits addr = 0;
00620       for (unsigned i = 0; ; ++i) {
00621         char* addrPtr = hstent->h_addr_list[i];
00622         if (addrPtr == NULL) break;
00623         
00624         netAddressBits a = *(netAddressBits*)addrPtr;
00625         if (!badAddress(a)) {
00626           addr = a;
00627           break;
00628         }
00629       }
00630       if (addr != 0) {
00631         fromAddr.sin_addr.s_addr = addr;
00632       } else {
00633         env.setResultMsg("no address");
00634         break;
00635       }
00636     } while (0);
00637     
00638     // Make sure we have a good address:
00639     netAddressBits from = fromAddr.sin_addr.s_addr;
00640     if (badAddress(from)) {
00641       char tmp[100];
00642       sprintf(tmp,
00643               "This computer has an invalid IP address: 0x%x",
00644               (netAddressBits)(ntohl(from)));
00645       env.setResultMsg(tmp);
00646       from = 0;
00647     }
00648     
00649     ourAddress = from;
00650 #endif
00651     
00652     if (sock >= 0) {
00653       socketLeaveGroup(env, sock, testAddr.s_addr);
00654       closeSocket(sock);
00655     }
00656     
00657     // Use our newly-discovered IP address, and the current time,
00658     // to initialize the random number generator's seed:
00659     struct timeval timeNow;
00660     gettimeofday(&timeNow, NULL);
00661     unsigned seed = ourAddress^timeNow.tv_sec^timeNow.tv_usec;
00662     our_srandom(seed);
00663   }
00664   return ourAddress;
00665 }
00666 
00667 netAddressBits chooseRandomIPv4SSMAddress(UsageEnvironment& env) {
00668   // First, a hack to ensure that our random number generator is seeded:
00669   (void) ourSourceAddressForMulticast(env);
00670 
00671   // Choose a random address in the range [232.0.1.0, 232.255.255.255)
00672   // i.e., [0xE8000100, 0xE8FFFFFF)
00673   netAddressBits const first = 0xE8000100, lastPlus1 = 0xE8FFFFFF;
00674   netAddressBits const range = lastPlus1 - first;
00675 
00676   return htonl(first + ((netAddressBits)our_random())%range);
00677 }
00678 
00679 char const* timestampString() {
00680   struct timeval tvNow;
00681   gettimeofday(&tvNow, NULL);
00682   
00683 #if !defined(_WIN32_WCE)
00684   static char timeString[9]; // holds hh:mm:ss plus trailing '\0'
00685   char const* ctimeResult = ctime((time_t*)&tvNow.tv_sec);
00686   char const* from = &ctimeResult[11];
00687   int i;
00688   for (i = 0; i < 8; ++i) {
00689     timeString[i] = from[i];
00690   }
00691   timeString[i] = '\0';
00692 #else
00693   // WinCE apparently doesn't have "ctime()", so instead, construct
00694   // a timestamp string just using the integer and fractional parts
00695   // of "tvNow":
00696   static char timeString[50];
00697   sprintf(timeString, "%lu.%06ld", tvNow.tv_sec, tvNow.tv_usec);
00698 #endif
00699   
00700   return (char const*)&timeString;
00701 }
00702 
00703 #if (defined(__WIN32__) || defined(_WIN32)) && !defined(IMN_PIM)
00704 // For Windoze, we need to implement our own gettimeofday()
00705 #if !defined(_WIN32_WCE)
00706 #include <sys/timeb.h>
00707 #endif
00708 
00709 int gettimeofday(struct timeval* tp, int* /*tz*/) {
00710 #if defined(_WIN32_WCE)
00711   /* FILETIME of Jan 1 1970 00:00:00. */
00712   static const unsigned __int64 epoch = 116444736000000000L;
00713 
00714   FILETIME    file_time;
00715   SYSTEMTIME  system_time;
00716   ULARGE_INTEGER ularge;
00717 
00718   GetSystemTime(&system_time);
00719   SystemTimeToFileTime(&system_time, &file_time);
00720   ularge.LowPart = file_time.dwLowDateTime;
00721   ularge.HighPart = file_time.dwHighDateTime;
00722 
00723   tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L);
00724   tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
00725 #else
00726   struct timeb tb;
00727   ftime(&tb);
00728   tp->tv_sec = tb.time;
00729   tp->tv_usec = 1000*tb.millitm;
00730 #endif
00731   return 0;
00732 }
00733 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends