D:/Programmation/Cpp/SFML/src/SFML/Network/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         int 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             in_addr SenderAddr = Sender.sin_addr;
00152             Address = sfIPAddress(inet_ntoa(Sender.sin_addr));
00153             SizeReceived = static_cast<std::size_t>(Received);
00154         }
00155         else
00156         {
00157             Address = sfIPAddress();
00158             return false;
00159         }
00160     }
00161     else
00162     {
00163         // Error...
00164         std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
00165         return false;
00166     }
00167 
00168     return true;
00169 }
00170 
00171 
00175 bool sfSocketUDP::Send(sfPacket& Packet, const sfIPAddress& Address, unsigned short Port)
00176 {
00177     // Let the packet do custom stuff before sending it
00178     Packet.OnSend();
00179 
00180     // First send the packet size
00181     sfUint32 PacketSize = htonl(Packet.GetDataSize());
00182     if (!Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize), Address, Port))
00183         return false;
00184 
00185     // Send the packet data
00186     if (!Send(Packet.GetData(), Packet.GetDataSize(), Address, Port))
00187         return false;
00188 
00189     return true;
00190 }
00191 
00192 
00198 bool sfSocketUDP::Receive(sfPacket& Packet, sfIPAddress& Address, unsigned short Port)
00199 {
00200     // This is not safe at all, as data can be lost, duplicated, or arrive in a different order.
00201     // So if a packet is split into more than one chunk, nobody knows what could happen...
00202     // Conclusion : we cannot use packet with UDP, unless we build a more complex protocol on top of it.
00203 
00204     // We start by getting the size of the incoming packet
00205     std::size_t Received   = 0;
00206     sfUint32    PacketSize = 0;
00207     Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received, Address, Port);
00208     PacketSize = ntohl(PacketSize);
00209 
00210     // Clear the packet
00211     Packet.Clear();
00212 
00213     // Use another addresse instance for receiving the packet data ;
00214     // chunks of data coming from a different sender will be discarded (and lost...)
00215     sfIPAddress Sender;
00216 
00217     // Then loop until we receive all the packet data
00218     char Buffer[1024];
00219     while (Packet.GetDataSize() < PacketSize)
00220     {
00221         // Receive a chunk of data
00222         if (!Receive(Buffer, sizeof(Buffer), Received, Sender, Port))
00223             return false;
00224 
00225         // Append it into the packet
00226         if (Sender == Address)
00227             Packet.Append(Buffer, Received);
00228     }
00229 
00230     // Let the packet do custom stuff after data reception
00231     Packet.OnReceive();
00232 
00233     return true;
00234 }
00235 
00236 
00240 bool sfSocketUDP::Close()
00241 {
00242     if (sf_private::close(mySocket) == -1)
00243     {
00244         std::cerr << "Failed to close socket" << std::endl;
00245         return false;
00246     }
00247 
00248     return true;
00249 }
00250 
00251 
00255 bool sfSocketUDP::operator ==(const sfSocketUDP& Other) const
00256 {
00257     return mySocket == Other.mySocket;
00258 }
00259 
00260 
00264 bool sfSocketUDP::operator !=(const sfSocketUDP& Other) const
00265 {
00266     return mySocket != Other.mySocket;
00267 }
00268 
00269 
00275 bool sfSocketUDP::operator <(const sfSocketUDP& Other) const
00276 {
00277     return mySocket < Other.mySocket;
00278 }
00279 
00280 
00285 sfSocketUDP::sfSocketUDP(sf_private::sfSocketType Descriptor) :
00286 mySocket(Descriptor),
00287 myPort  (0)
00288 {
00289 
00290 }
00291 
00292 
00296 void sfSocketUDP::Create()
00297 {
00298     // Create the socket
00299     mySocket = socket(PF_INET, SOCK_DGRAM, 0);
00300 
00301     // Clear the last port used
00302     myPort = 0;
00303 
00304     // To avoid the "Address already in use" error message when trying to bind to the same port
00305     char Yes = 1;
00306     if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1)
00307     {
00308         std::cerr << "Failed to set socket option \"reuse address\" ; "
00309                   << "binding to a same port may fail if too fast" << std::endl;
00310     }
00311 
00312     // Enable broadcast by default
00313     if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, &Yes, sizeof(int)) == -1)
00314     {
00315         std::cerr << "Failed to enable broadcast on UDP socket" << std::endl;
00316     }
00317 }

Generated for SFML by  doxygen 1.5.2