SocketUDP.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/SocketUDP.hpp>
00029 #include <SFML/Network/IPAddress.hpp>
00030 #include <SFML/Network/Packet.hpp>
00031 #include <iostream>
00032 
00033 
00037 sfSocketUDP::sfSocketUDP() :
00038 mySocket(0),
00039 myPort  (0)
00040 {
00041     Create();
00042 }
00043 
00044 
00048 bool sfSocketUDP::Send(const char* Data, std::size_t Size, const sfIPAddress& Address, unsigned short Port)
00049 {
00050     // First check that socket is valid
00051     if (mySocket == INVALID_SOCKET)
00052         return false;
00053 
00054     // Check parameters
00055     if (Data && Size)
00056     {
00057         // Build the target address
00058         sockaddr_in Target;
00059         Target.sin_family      = AF_INET;
00060         Target.sin_port        = htons(Port);
00061         Target.sin_addr.s_addr = inet_addr(Address.ToString().c_str());
00062         memset(Target.sin_zero, 0, sizeof(Target.sin_zero));
00063 
00064         // Loop until every byte has been sent
00065         int Sent = 0;
00066         int SizeToSend = static_cast<int>(Size);
00067         for (int Length = 0; Length < SizeToSend; Length += Sent)
00068         {
00069             // Send a chunk of data
00070             Sent = sendto(mySocket, Data + Length, SizeToSend - Length, 0, reinterpret_cast<sockaddr*>(&Target), sizeof(Target));
00071 
00072             // Check errors
00073             if (Sent <= 0)
00074                 return false;
00075         }
00076     }
00077     else
00078     {
00079         // Error...
00080         std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl;
00081         return false;
00082     }
00083 
00084     return true;
00085 }
00086 
00087 
00093 bool sfSocketUDP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived, sfIPAddress& Address, unsigned short Port)
00094 {
00095     // First clear the size received
00096     SizeReceived = 0;
00097 
00098     // Check that socket is valid
00099     if (mySocket == INVALID_SOCKET)
00100         return false;
00101 
00102     // Check parameters
00103     if (Data && MaxSize)
00104     {
00105         // Check if the socket is bound to the specified port
00106         if (myPort != Port)
00107         {
00108             // If the socket was previously bound to another port, we need to recreate it
00109             if (myPort != 0)
00110             {
00111                 // Close the socket to unbind it from the port
00112                 Close();
00113 
00114                 // Recreate it
00115                 Create();
00116             }
00117 
00118             // Build an address with the specified port
00119             sockaddr_in Addr;
00120             Addr.sin_family      = AF_INET;
00121             Addr.sin_port        = htons(Port);
00122             Addr.sin_addr.s_addr = INADDR_ANY;
00123             memset(Addr.sin_zero, 0, sizeof(Addr.sin_zero));
00124 
00125             // Bind the socket to the port
00126             if (bind(mySocket, reinterpret_cast<sockaddr*>(&Addr), sizeof(Addr)) == -1)
00127             {
00128                 std::cerr << "Failed to bind the socket to port " << Port << std::endl;
00129                 myPort = 0;
00130                 return false;
00131             }
00132 
00133             // Save the new port
00134             myPort = Port;
00135         }
00136 
00137         // Data that will be filled with the other computer's address
00138         sockaddr_in Sender;
00139         Sender.sin_family      = AF_INET;
00140         Sender.sin_port        = htons(myPort);
00141         Sender.sin_addr.s_addr = INADDR_ANY;
00142         memset(Sender.sin_zero, 0, sizeof(Sender.sin_zero));
00143         socklen_t SenderSize = sizeof(Sender);
00144 
00145         // Receive a chunk of bytes
00146         int Received = recvfrom(mySocket, Data, static_cast<int>(MaxSize), 0, reinterpret_cast<sockaddr*>(&Sender), &SenderSize);
00147 
00148         // Check the number of bytes received
00149         if (Received > 0)
00150         {
00151             Address = sfIPAddress(inet_ntoa(Sender.sin_addr));
00152             SizeReceived = static_cast<std::size_t>(Received);
00153         }
00154         else
00155         {
00156             Address = sfIPAddress();
00157             return false;
00158         }
00159     }
00160     else
00161     {
00162         // Error...
00163         std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
00164         return false;
00165     }
00166 
00167     return true;
00168 }
00169 
00170 
00174 bool sfSocketUDP::Send(sfPacket& Packet, const sfIPAddress& Address, unsigned short Port)
00175 {
00176     // Let the packet do custom stuff before sending it
00177     Packet.OnSend();
00178 
00179     // First send the packet size
00180     sfUint32 PacketSize = htonl(Packet.GetDataSize());
00181     if (!Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize), Address, Port))
00182         return false;
00183 
00184     // Send the packet data
00185     if (!Send(Packet.GetData(), Packet.GetDataSize(), Address, Port))
00186         return false;
00187 
00188     return true;
00189 }
00190 
00191 
00197 bool sfSocketUDP::Receive(sfPacket& Packet, sfIPAddress& Address, unsigned short Port)
00198 {
00199     // This is not safe at all, as data can be lost, duplicated, or arrive in a different order.
00200     // So if a packet is split into more than one chunk, nobody knows what could happen...
00201     // Conclusion : we cannot use packet with UDP, unless we build a more complex protocol on top of it.
00202 
00203     // We start by getting the size of the incoming packet
00204     std::size_t Received   = 0;
00205     sfUint32    PacketSize = 0;
00206     Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received, Address, Port);
00207     PacketSize = ntohl(PacketSize);
00208 
00209     // Clear the packet
00210     Packet.Clear();
00211 
00212     // Use another address instance for receiving the packet data ;
00213     // chunks of data coming from a different sender will be discarded (and lost...)
00214     sfIPAddress Sender;
00215 
00216     // Then loop until we receive all the packet data
00217     char Buffer[1024];
00218     while (Packet.GetDataSize() < PacketSize)
00219     {
00220         // Receive a chunk of data
00221         if (!Receive(Buffer, sizeof(Buffer), Received, Sender, Port))
00222             return false;
00223 
00224         // Append it into the packet
00225         if (Sender == Address)
00226             Packet.Append(Buffer, Received);
00227     }
00228 
00229     // Let the packet do custom stuff after data reception
00230     Packet.OnReceive();
00231 
00232     return true;
00233 }
00234 
00235 
00239 bool sfSocketUDP::Close()
00240 {
00241     if (sf_private::close(mySocket) == -1)
00242     {
00243         std::cerr << "Failed to close socket" << std::endl;
00244         return false;
00245     }
00246 
00247     return true;
00248 }
00249 
00250 
00254 bool sfSocketUDP::operator ==(const sfSocketUDP& Other) const
00255 {
00256     return mySocket == Other.mySocket;
00257 }
00258 
00259 
00263 bool sfSocketUDP::operator !=(const sfSocketUDP& Other) const
00264 {
00265     return mySocket != Other.mySocket;
00266 }
00267 
00268 
00274 bool sfSocketUDP::operator <(const sfSocketUDP& Other) const
00275 {
00276     return mySocket < Other.mySocket;
00277 }
00278 
00279 
00284 sfSocketUDP::sfSocketUDP(sf_private::sfSocketType Descriptor) :
00285 mySocket(Descriptor),
00286 myPort  (0)
00287 {
00288 
00289 }
00290 
00291 
00295 void sfSocketUDP::Create()
00296 {
00297     // Create the socket
00298     mySocket = socket(PF_INET, SOCK_DGRAM, 0);
00299 
00300     // Clear the last port used
00301     myPort = 0;
00302 
00303     // To avoid the "Address already in use" error message when trying to bind to the same port
00304     char Yes = 1;
00305     if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1)
00306     {
00307         std::cerr << "Failed to set socket option \"reuse address\" ; "
00308                   << "binding to a same port may fail if too fast" << std::endl;
00309     }
00310 
00311     // Enable broadcast by default
00312     if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, &Yes, sizeof(int)) == -1)
00313     {
00314         std::cerr << "Failed to enable broadcast on UDP socket" << std::endl;
00315     }
00316 }