|
MythTV
0.26-pre
|
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
1.7.6.1