X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fio%2Fraw_socket.cxx;h=7fe2c6884cb61ca49dd07915a74a7bcce7e93bc2;hb=b7654c181dc8d52875365b170bc3092e8e51d68f;hp=7af6c695b372d8326e9376fe347be85732b52ca0;hpb=6b3a05e23fc8f8121f24824711917e7255f17fa8;p=simgear.git diff --git a/simgear/io/raw_socket.cxx b/simgear/io/raw_socket.cxx index 7af6c695..7fe2c688 100644 --- a/simgear/io/raw_socket.cxx +++ b/simgear/io/raw_socket.cxx @@ -25,8 +25,7 @@ #endif #include - -#include "sg_socket.hxx" +#include "raw_socket.hxx" #if defined(_WIN32) && !defined(__CYGWIN__) # define WINSOCK // use winsock convetions, otherwise standard POSIX @@ -37,6 +36,7 @@ #include #include #include // for snprintf +#include #if defined(WINSOCK) # include @@ -67,44 +67,73 @@ IPAddress::IPAddress ( const char* host, int port ) set ( host, port ) ; } +IPAddress::IPAddress( const IPAddress& other ) : + addr(NULL) +{ + if (other.addr) { + addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); + memcpy(addr, other.addr, sizeof(struct sockaddr_in)); + } +} + +const IPAddress& IPAddress::operator=(const IPAddress& other) +{ + if (addr) { + free(addr); + addr = NULL; + } + + if (other.addr) { + addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); + memcpy(addr, other.addr, sizeof(struct sockaddr_in)); + } + + return *this; +} void IPAddress::set ( const char* host, int port ) { - memset(this, 0, sizeof(IPAddress)); + addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); + memset(addr, 0, sizeof(struct sockaddr_in)); - sin_family = AF_INET ; - sin_port = htons (port); + addr->sin_family = AF_INET ; + addr->sin_port = htons (port); /* Convert a string specifying a host name or one of a few symbolic - ** names to a numeric IP address. This usually calls gethostbyname() + ** names to a numeric IP address. This usually calls getaddrinfo() ** to do the work; the names "" and "" are special. */ if (!host || host[0] == '\0') { - sin_addr = INADDR_ANY; + addr->sin_addr.s_addr = INADDR_ANY; return; } if (strcmp(host, "") == 0) { - sin_addr = INADDR_BROADCAST; + addr->sin_addr.s_addr = INADDR_BROADCAST; return; } - sin_addr = inet_addr ( host ) ; - if (sin_addr != INADDR_NONE) { - return; + struct addrinfo* result = NULL; + int err = getaddrinfo(host, NULL, NULL /* no hints */, &result); + if (err) { + SG_LOG(SG_IO, SG_WARN, "getaddrinfo failed for '" << host << "' : " << gai_strerror(err)); + } else if (result->ai_addrlen != getAddrLen()) { + SG_LOG(SG_IO, SG_ALERT, "mismatch in socket address sizes"); + } else { + memcpy(addr, result->ai_addr, result->ai_addrlen); } -// finally, try gethostbyname - struct hostent *hp = gethostbyname ( host ) ; - if (!hp) { - SG_LOG(SG_IO, SG_WARN, "gethostbyname failed for " << host); - sin_addr = INADDR_ANY ; - return; - } - - memcpy ( (char *) &sin_addr, hp->h_addr, hp->h_length ) ; + + freeaddrinfo(result); + addr->sin_port = htons (port); // fix up port after getaddrinfo } +IPAddress::~IPAddress() +{ + if (addr) { + free (addr); + } +} /* Create a string object representing an IP address. This is always a string of the form 'dd.dd.dd.dd' (with variable @@ -112,31 +141,27 @@ void IPAddress::set ( const char* host, int port ) const char* IPAddress::getHost () const { -#if 0 - const char* buf = inet_ntoa ( sin_addr ) ; -#else static char buf [32]; - long x = ntohl(sin_addr); + long x = ntohl(addr->sin_addr.s_addr); sprintf(buf, "%d.%d.%d.%d", (int) (x>>24) & 0xff, (int) (x>>16) & 0xff, (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff ); -#endif return buf; } unsigned int IPAddress::getIP () const { - return sin_addr; + return addr->sin_addr.s_addr; } unsigned int IPAddress::getPort() const { - return ntohs(sin_port); + return ntohs(addr->sin_port); } unsigned int IPAddress::getFamily () const { - return sin_family; + return addr->sin_family; } const char* IPAddress::getLocalHost () @@ -163,9 +188,18 @@ const char* IPAddress::getLocalHost () bool IPAddress::getBroadcast () const { - return sin_addr == INADDR_BROADCAST; + return (addr->sin_addr.s_addr == INADDR_BROADCAST); } +unsigned int IPAddress::getAddrLen() const +{ + return sizeof(struct sockaddr_in); +} + +struct sockaddr* IPAddress::getAddr() const +{ + return (struct sockaddr*) addr; +} Socket::Socket () { @@ -190,6 +224,25 @@ bool Socket::open ( bool stream ) { close () ; handle = ::socket ( AF_INET, (stream? SOCK_STREAM: SOCK_DGRAM), 0 ) ; + + // Jan 26, 2010: Patch to avoid the problem of the socket resource not + // yet being available if the program is restarted quickly after being + // killed. + // + // Reference: http://www.unixguide.net/network/socketfaq/4.5.shtml + // -- + // Also required for joining multicast domains + if ( stream ) { + int opt_boolean = 1; +#if defined(_WIN32) || defined(__CYGWIN__) + setsockopt( handle, SOL_SOCKET, SO_REUSEADDR, (char *)&opt_boolean, + sizeof(opt_boolean) ); +#else + setsockopt( handle, SOL_SOCKET, SO_REUSEADDR, &opt_boolean, + sizeof(opt_boolean) ); +#endif + } + return (handle != -1); } @@ -238,9 +291,50 @@ void Socket::setBroadcast ( bool broadcast ) int Socket::bind ( const char* host, int port ) { + int result; assert ( handle != -1 ) ; IPAddress addr ( host, port ) ; - return ::bind(handle,(const sockaddr*)&addr,sizeof(IPAddress)); + +#if !defined(WINSOCK) + if( (result = ::bind(handle, addr.getAddr(), addr.getAddrLen() ) ) < 0 ) { + SG_LOG(SG_IO, SG_ALERT, "bind(" << addr.getHost() << ":" << addr.getPort() << ") failed. Errno " << errno << " (" << strerror(errno) << ")"); + return result; + } +#endif + + // 224.0.0.0 - 239.255.255.255 are multicast + // Usage of 239.x.x.x is recommended for local scope + // Reference: http://tools.ietf.org/html/rfc5771 + if( ntohl(addr.getIP()) >= 0xe0000000 && ntohl(addr.getIP()) <= 0xefffffff ) { + +#if defined(WINSOCK) + struct sockaddr_in a; + a.sin_addr.S_un.S_addr = INADDR_ANY; + a.sin_family = AF_INET; + a.sin_port = htons(port); + + if( (result = ::bind(handle,(const sockaddr*)&a,sizeof(a))) < 0 ) { + SG_LOG(SG_IO, SG_ALERT, "bind(any:" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")"); + return result; + } +#endif + + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = addr.getIP(); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if( (result=::setsockopt(getHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq))) != 0 ) { + SG_LOG(SG_IO, SG_ALERT, "setsockopt(IP_ADD_MEMBERSHIP) failed. Errno " << errno << " (" << strerror(errno) << ")"); + return result; + } + } +#if defined(WINSOCK) + else if( (result = ::bind(handle,addr->getAddr(), addr->getAddrLen())) < 0 ) { + SG_LOG(SG_IO, SG_ALERT, "bind(" << host << ":" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")"); + return result; + } +#endif + + return 0; } @@ -261,20 +355,26 @@ int Socket::accept ( IPAddress* addr ) } else { - socklen_t addr_len = (socklen_t) sizeof(IPAddress) ; - return ::accept(handle,(sockaddr*)addr,&addr_len); + socklen_t addr_len = addr->getAddrLen(); ; + return ::accept(handle, addr->getAddr(), &addr_len); } } int Socket::connect ( const char* host, int port ) { - assert ( handle != -1 ) ; IPAddress addr ( host, port ) ; - if ( addr.getBroadcast() ) { + return connect ( &addr ); +} + + +int Socket::connect ( IPAddress* addr ) +{ + assert ( handle != -1 ) ; + if ( addr->getBroadcast() ) { setBroadcast( true ); } - return ::connect(handle,(const sockaddr*)&addr,sizeof(IPAddress)); + return ::connect(handle, addr->getAddr(), addr->getAddrLen() ); } @@ -290,7 +390,7 @@ int Socket::sendto ( const void * buffer, int size, { assert ( handle != -1 ) ; return ::sendto(handle,(const char*)buffer,size,flags, - (const sockaddr*)to,sizeof(IPAddress)); + (const sockaddr*) to->getAddr(), to->getAddrLen()); } @@ -305,8 +405,8 @@ int Socket::recvfrom ( void * buffer, int size, int flags, IPAddress* from ) { assert ( handle != -1 ) ; - socklen_t fromlen = (socklen_t) sizeof(IPAddress) ; - return ::recvfrom(handle,(char*)buffer,size,flags,(sockaddr*)from,&fromlen); + socklen_t fromlen = (socklen_t) from->getAddrLen() ; + return ::recvfrom(handle,(char*)buffer,size,flags, from->getAddr(),&fromlen); } @@ -331,7 +431,7 @@ bool Socket::isNonBlockingError () if ( wsa_errno != 0 ) { WSASetLastError(0); - ulSetError(UL_WARNING,"WSAGetLastError() => %d",wsa_errno); + SG_LOG(SG_IO, SG_WARN, "isNonBlockingError: WSAGetLastError():" << wsa_errno); switch (wsa_errno) { case WSAEWOULDBLOCK: // always == NET_EAGAIN? case WSAEALREADY: @@ -466,16 +566,13 @@ static void netExit ( void ) int Socket::initSockets() { - assert ( sizeof(sockaddr_in) == sizeof(IPAddress) ) ; - #if defined(WINSOCK) /* Start up the windows networking */ WORD version_wanted = MAKEWORD(1,1); WSADATA wsaData; if ( WSAStartup(version_wanted, &wsaData) != 0 ) { - ulSetError(UL_WARNING,"Couldn't initialize Winsock 1.1"); - return(-1); + throw sg_exception("WinSock initialization failed"); } #endif