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

Generated on Tue Jul 22 06:39:05 2008 for live by  doxygen 1.5.2