IPAddress.cpp

00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com)
00005 //
00006 // This software is provided 'as-is', without any express or implied warranty.
00007 // In no event will the authors be held liable for any damages arising from the use of this software.
00008 //
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it freely,
00011 // subject to the following restrictions:
00012 //
00013 // 1. The origin of this software must not be misrepresented;
00014 //    you must not claim that you wrote the original software.
00015 //    If you use this software in a product, an acknowledgment
00016 //    in the product documentation would be appreciated but is not required.
00017 //
00018 // 2. Altered source versions must be plainly marked as such,
00019 //    and must not be misrepresented as being the original software.
00020 //
00021 // 3. This notice may not be removed or altered from any source distribution.
00022 //
00024 
00026 // Headers
00028 #include <SFML/Network/IPAddress.hpp>
00029 #include <SFML/Network/Sockets.hpp>
00030 
00031 
00032 namespace sf
00033 {
00037 const IPAddress IPAddress::LocalHost("127.0.0.1");
00038 
00039 
00043 IPAddress::IPAddress() :
00044 myAddress(INADDR_NONE)
00045 {
00046 
00047 }
00048 
00049 
00053 IPAddress::IPAddress(const std::string& Address)
00054 {
00055     // First try to convert it as a byte representation ("xxx.xxx.xxx.xxx")
00056     myAddress = inet_addr(Address.c_str());
00057 
00058     // If not successful, try to convert it as a host name
00059     if (!IsValid())
00060     {
00061         hostent* Host = gethostbyname(Address.c_str());
00062         if (Host)
00063         {
00064             // Host found, extract its IP address
00065             myAddress = reinterpret_cast<in_addr*>(Host->h_addr)->s_addr;
00066         }
00067         else
00068         {
00069             // Host name not found on the network
00070             myAddress = INADDR_NONE;
00071         }
00072     }
00073 }
00074 
00075 
00079 IPAddress::IPAddress(Uint8 Byte0, Uint8 Byte1, Uint8 Byte2, Uint8 Byte3)
00080 {
00081     myAddress = htonl((Byte0 << 24) | (Byte1 << 16) | (Byte2 << 8) | Byte3);
00082 }
00083 
00084 
00088 bool IPAddress::IsValid() const
00089 {
00090     return myAddress != INADDR_NONE;
00091 }
00092 
00093 
00097 std::string IPAddress::ToString() const
00098 {
00099     in_addr InAddr;
00100     InAddr.s_addr = myAddress;
00101 
00102     return inet_ntoa(InAddr);
00103 }
00104 
00105 
00109 IPAddress IPAddress::GetLocalAddress()
00110 {
00111     // The method here is to connect a UDP socket to anyone (here to localhost),
00112     // and get the local socket address with the getsockname function.
00113     // UDP connection will not send anything to the network, so this function won't cause any overhead
00114 
00115     IPAddress LocalAddress;
00116 
00117     // Create the socket
00118     priv::SocketType Socket = socket(PF_INET, SOCK_DGRAM, 0);
00119     if (Socket == INVALID_SOCKET)
00120         return LocalAddress;
00121 
00122     // Build the host address (use a random port)
00123     sockaddr_in SockAddr;
00124     memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
00125     SockAddr.sin_addr.s_addr = INADDR_LOOPBACK;
00126     SockAddr.sin_family      = AF_INET;
00127     SockAddr.sin_port        = htons(4567);
00128 
00129     // Connect the socket
00130     if (connect(Socket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
00131     {
00132         priv::close(Socket);
00133         return LocalAddress;
00134     }
00135  
00136     // Get the local address of the socket connection
00137     socklen_t Size = sizeof(SockAddr);
00138     if (getsockname(Socket, reinterpret_cast<sockaddr*>(&SockAddr), &Size) == -1)
00139     {
00140         priv::close(Socket);
00141         return LocalAddress;
00142     }
00143 
00144     // Close the socket
00145     priv::close(Socket);
00146 
00147     // Finally build the IP address
00148     LocalAddress.myAddress = SockAddr.sin_addr.s_addr;
00149 
00150     return LocalAddress;
00151 }
00152 
00153 
00157 IPAddress IPAddress::GetPublicAddress()
00158 {
00159     // The trick here is more complicated, because the only way
00160     // to get our public IP address is to get it from a distant computer.
00161     // Here we get the web page from http://www.whatismyip.org
00162     // and parse the result to extract our IP address
00163     // (not very hard : the web page contains only our IP address)
00164 
00165     IPAddress PublicAddress;
00166 
00167     // Create the socket
00168     priv::SocketType Socket = socket(PF_INET, SOCK_STREAM, 0);
00169     if (Socket == INVALID_SOCKET)
00170         return PublicAddress;
00171 
00172     // Build the server address (use port 80 for HTTP)
00173     IPAddress Server("www.whatismyip.org");
00174     sockaddr_in SockAddr;
00175     memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
00176     SockAddr.sin_addr.s_addr = inet_addr(Server.ToString().c_str());
00177     SockAddr.sin_family      = AF_INET;
00178     SockAddr.sin_port        = htons(80);
00179 
00180     // Connect the socket
00181     if (connect(Socket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
00182     {
00183         priv::close(Socket);
00184         return PublicAddress;
00185     }
00186 
00187     // Send a request for getting the index page
00188     const char Request[] = "GET / HTTP/1.0\r\n"
00189                            "From: camembert@fromage.com\r\n"
00190                            "User-Agent: SFML/1.0\r\n"
00191                            "\r\n";
00192     if (send(Socket, Request, sizeof(Request), 0) <= 0)
00193     {
00194         priv::close(Socket);
00195         return PublicAddress;
00196     }
00197 
00198     // Get the response (the source code of the web page)
00199     char Response[1024];
00200     int Received = recv(Socket, Response, sizeof(Response), 0);
00201 
00202     // Close the socket
00203     priv::close(Socket);
00204 
00205     if (Received <= 0)
00206         return PublicAddress;
00207 
00208     // Extract the address from the source code of the web page
00209     // (extract from first \r\n\r\n to the end)
00210     std::string Page(Response, Received);
00211     std::string::size_type Start = Page.find("\r\n\r\n");
00212     if (Start != std::string::npos)
00213     {
00214         PublicAddress = Page.substr(Start + 4);
00215     }
00216 
00217     return PublicAddress;
00218 }
00219 
00220 
00224 bool IPAddress::operator ==(const IPAddress& Other) const
00225 {
00226     return myAddress == Other.myAddress;
00227 }
00228 
00229 
00233 bool IPAddress::operator !=(const IPAddress& Other) const
00234 {
00235     return myAddress != Other.myAddress;
00236 }
00237 
00238 
00242 bool IPAddress::operator <(const IPAddress& Other) const
00243 {
00244     return myAddress < Other.myAddress;
00245 }
00246 
00247 
00251 bool IPAddress::operator >(const IPAddress& Other) const
00252 {
00253     return myAddress > Other.myAddress;
00254 }
00255 
00256 
00260 bool IPAddress::operator <=(const IPAddress& Other) const
00261 {
00262     return myAddress <= Other.myAddress;
00263 }
00264 
00265 
00269 bool IPAddress::operator >=(const IPAddress& Other) const
00270 {
00271     return myAddress >= Other.myAddress;
00272 }
00273 
00274 
00278 std::istream& operator >>(std::istream& Stream, IPAddress& Address)
00279 {
00280     std::string Str;
00281     Stream >> Str;
00282     Address = IPAddress(Str);
00283 
00284     return Stream;
00285 }
00286 
00287 
00291 std::ostream& operator <<(std::ostream& Stream, const IPAddress& Address)
00292 {
00293     return Stream << Address.ToString();
00294 }
00295 
00296 } // namespace sf