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