- Main Page
- Namespaces
- Classes
- Files

- File List

# SocketUDP.cpp

    00001
    00002 //
    00003 // SFML - Simple and Fast Multimedia Library
    00004 // Copyright (C) 2007-2009 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 <algorithm>
    00032 #include <iostream>
    00033 #include <string.h>
    00034
    00035
    00036 namespace sf
    00037 {
    00041 SocketUDP::SocketUDP()
    00042 {
    00043     Create();
    00044 }
    00045
    00046
    00050 void SocketUDP::SetBlocking(bool Blocking)
    00051 {
    00052     // Make sure our socket is valid
    00053     if (!IsValid())
    00054         Create();
    00055
    00056     SocketHelper::SetBlocking(mySocket, Blocking);
    00057     myIsBlocking = Blocking;
    00058 }
    00059
    00060
    00064 bool SocketUDP::Bind(unsigned short Port)
    00065 {
    00066     // Check if the socket is already bound to the specified port
    00067     if (myPort != Port)
    00068     {
    00069         // If the socket was previously bound to another port, we need to unbind it first
    00070         Unbind();
    00071
    00072         if (Port != 0)
    00073         {
    00074             // Build an address with the specified port
    00075             sockaddr_in Addr;
    00076             Addr.sin_family      = AF_INET;
    00077             Addr.sin_port        = htons(Port);
    00078             Addr.sin_addr.s_addr = INADDR_ANY;
    00079             memset(Addr.sin_zero, 0, sizeof(Addr.sin_zero));
    00080
    00081             // Bind the socket to the port
    00082             if (bind(mySocket, reinterpret_cast<sockaddr*>(&Addr), sizeof(Addr)) == -1)
    00083             {
    00084                 std::cerr << "Failed to bind the socket to port " << Port << std::endl;
    00085                 myPort = 0;
    00086                 return false;
    00087             }
    00088         }
    00089
    00090         // Save the new port
    00091         myPort = Port;
    00092     }
    00093
    00094     return true;
    00095 }
    00096
    00097
    00101 bool SocketUDP::Unbind()
    00102 {
    00103     // To unbind the socket, we just recreate it
    00104     if (myPort != 0)
    00105     {
    00106         Close();
    00107         Create();
    00108         myPort = 0;
    00109     }
    00110
    00111     return true;
    00112 }
    00113
    00114
    00118 Socket::Status SocketUDP::Send(const char* Data, std::size_t Size, const IPAddress& Address, unsigned short Port)
    00119 {
    00120     // Make sure the socket is valid
    00121     if (!IsValid())
    00122         Create();
    00123
    00124     // Check parameters
    00125     if (Data && Size)
    00126     {
    00127         // Build the target address
    00128         sockaddr_in Target;
    00129         Target.sin_family      = AF_INET;
    00130         Target.sin_port        = htons(Port);
    00131         Target.sin_addr.s_addr = inet_addr(Address.ToString().c_str());
    00132         memset(Target.sin_zero, 0, sizeof(Target.sin_zero));
    00133
    00134         // Loop until every byte has been sent
    00135         int Sent = 0;
    00136         int SizeToSend = static_cast<int>(Size);
    00137         for (int Length = 0; Length < SizeToSend; Length += Sent)
    00138         {
    00139             // Send a chunk of data
    00140             Sent = sendto(mySocket, Data + Length, SizeToSend - Length, 0, reinterpret_cast<sockaddr*>(&Target), sizeof(Target));
    00141
    00142             // Check errors
    00143             if (Sent <= 0)
    00144                 return SocketHelper::GetErrorStatus();
    00145         }
    00146
    00147         return Socket::Done;
    00148     }
    00149     else
    00150     {
    00151         // Error...
    00152         std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl;
    00153         return Socket::Error;
    00154     }
    00155 }
    00156
    00157
    00162 Socket::Status SocketUDP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived, IPAddress& Address, unsigned short& Port)
    00163 {
    00164     // First clear the size received
    00165     SizeReceived = 0;
    00166
    00167     // Make sure the socket is bound to a port
    00168     if (myPort == 0)
    00169     {
    00170         std::cerr << "Failed to receive data ; the UDP socket first needs to be bound to a port" << std::endl;
    00171         return Socket::Error;
    00172     }
    00173
    00174     // Make sure the socket is valid
    00175     if (!IsValid())
    00176         Create();
    00177
    00178     // Check parameters
    00179     if (Data && MaxSize)
    00180     {
    00181         // Data that will be filled with the other computer's address
    00182         sockaddr_in Sender;
    00183         Sender.sin_family      = AF_INET;
    00184         Sender.sin_port        = 0;
    00185         Sender.sin_addr.s_addr = INADDR_ANY;
    00186         memset(Sender.sin_zero, 0, sizeof(Sender.sin_zero));
    00187         SocketHelper::LengthType SenderSize = sizeof(Sender);
    00188
    00189         // Receive a chunk of bytes
    00190         int Received = recvfrom(mySocket, Data, static_cast<int>(MaxSize), 0, reinterpret_cast<sockaddr*>(&Sender), &SenderSize);
    00191
    00192         // Check the number of bytes received
    00193         if (Received > 0)
    00194         {
    00195             Address = IPAddress(inet_ntoa(Sender.sin_addr));
    00196             Port = ntohs(Sender.sin_port);
    00197             SizeReceived = static_cast<std::size_t>(Received);
    00198             return Socket::Done;
    00199         }
    00200         else
    00201         {
    00202             Address = IPAddress();
    00203             Port = 0;
    00204             return Received == 0 ? Socket::Disconnected : SocketHelper::GetErrorStatus();
    00205         }
    00206     }
    00207     else
    00208     {
    00209         // Error...
    00210         std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
    00211         return Socket::Error;
    00212     }
    00213 }
    00214
    00215
    00219 Socket::Status SocketUDP::Send(Packet& PacketToSend, const IPAddress& Address, unsigned short Port)
    00220 {
    00221     // Get the data to send from the packet
    00222     std::size_t DataSize = 0;
    00223     const char* Data = PacketToSend.OnSend(DataSize);
    00224
    00225     // Send the packet size
    00226     Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
    00227     Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize), Address, Port);
    00228
    00229     // Send the packet data
    00230     if (PacketSize > 0)
    00231     {
    00232         return Send(Data, DataSize, Address, Port);
    00233     }
    00234     else
    00235     {
    00236         return Socket::Done;
    00237     }
    00238 }
    00239
    00240
    00245 Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address, unsigned short& Port)
    00246 {
    00247     // This is not safe at all, as data can be lost, duplicated, or arrive in a different order.
    00248     // So if a packet is split into more than one chunk, nobody knows what could happen...
    00249     // Conclusion : we shouldn't use packets with UDP, unless we build a more complex protocol on top of it.
    00250
    00251     // We start by getting the size of the incoming packet
    00252     Uint32      PacketSize = 0;
    00253     std::size_t Received   = 0;
    00254     if (myPendingPacketSize < 0)
    00255     {
    00256         Socket::Status Status = Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received, Address, Port);
    00257         if (Status != Socket::Done)
    00258             return Status;
    00259
    00260         PacketSize = ntohl(PacketSize);
    00261     }
    00262     else
    00263     {
    00264         // There is a pending packet : we already know its size
    00265         PacketSize = myPendingPacketSize;
    00266     }
    00267
    00268     // Clear the user packet
    00269     PacketToReceive.Clear();
    00270
    00271     // Use another address instance for receiving the packet data ;
    00272     // chunks of data coming from a different sender will be discarded (and lost...)
    00273     IPAddress Sender;
    00274     unsigned short SenderPort;
    00275
    00276     // Then loop until we receive all the packet data
    00277     char Buffer[1024];
    00278     while (myPendingPacket.size() < PacketSize)
    00279     {
    00280         // Receive a chunk of data
    00281         std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
    00282         Socket::Status Status = Receive(Buffer, SizeToGet, Received, Sender, SenderPort);
    00283         if (Status != Socket::Done)
    00284         {
    00285             // We must save the size of the pending packet until we can receive its content
    00286             if (Status == Socket::NotReady)
    00287                 myPendingPacketSize = PacketSize;
    00288             return Status;
    00289         }
    00290
    00291         // Append it into the packet
    00292         if ((Sender == Address) && (SenderPort == Port) && (Received > 0))
    00293         {
    00294             myPendingPacket.resize(myPendingPacket.size() + Received);
    00295             char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
    00296             memcpy(Begin, Buffer, Received);
    00297         }
    00298     }
    00299
    00300     // We have received all the datas : we can copy it to the user packet, and clear our internal packet
    00301     PacketToReceive.Clear();
    00302     if (!myPendingPacket.empty())
    00303         PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
    00304     myPendingPacket.clear();
    00305     myPendingPacketSize = -1;
    00306
    00307     return Socket::Done;
    00308 }
    00309
    00310
    00314 bool SocketUDP::Close()
    00315 {
    00316     if (IsValid())
    00317     {
    00318         if (!SocketHelper::Close(mySocket))
    00319         {
    00320             std::cerr << "Failed to close socket" << std::endl;
    00321             return false;
    00322         }
    00323
    00324         mySocket = SocketHelper::InvalidSocket();
    00325     }
    00326
    00327     myPort       = 0;
    00328     myIsBlocking = true;
    00329
    00330     return true;
    00331 }
    00332
    00333
    00338 bool SocketUDP::IsValid() const
    00339 {
    00340     return mySocket != SocketHelper::InvalidSocket();
    00341 }
    00342
    00343
    00347 unsigned short SocketUDP::GetPort() const
    00348 {
    00349     return myPort;
    00350 }
    00351
    00352
    00356 bool SocketUDP::operator ==(const SocketUDP& Other) const
    00357 {
    00358     return mySocket == Other.mySocket;
    00359 }
    00360
    00361
    00365 bool SocketUDP::operator !=(const SocketUDP& Other) const
    00366 {
    00367     return mySocket != Other.mySocket;
    00368 }
    00369
    00370
    00376 bool SocketUDP::operator <(const SocketUDP& Other) const
    00377 {
    00378     return mySocket < Other.mySocket;
    00379 }
    00380
    00381
    00386 SocketUDP::SocketUDP(SocketHelper::SocketType Descriptor)
    00387 {
    00388     Create(Descriptor);
    00389 }
    00390
    00391
    00395 void SocketUDP::Create(SocketHelper::SocketType Descriptor)
    00396 {
    00397     // Use the given socket descriptor, or get a new one
    00398     mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_DGRAM, 0);
    00399     myIsBlocking = true;
    00400
    00401     // Clear the last port used
    00402     myPort = 0;
    00403
    00404     // Reset the pending packet
    00405     myPendingPacket.clear();
    00406     myPendingPacketSize = -1;
    00407
    00408     // Setup default options
    00409     if (IsValid())
    00410     {
    00411         // To avoid the "Address already in use" error message when trying to bind to the same port
    00412         int Yes = 1;
    00413         if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
    00414         {
    00415             std::cerr << "Failed to set socket option \"reuse address\" ; "
    00416                       << "binding to a same port may fail if too fast" << std::endl;
    00417         }
    00418
    00419         // Enable broadcast by default
    00420         if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
    00421         {
    00422             std::cerr << "Failed to enable broadcast on UDP socket" << std::endl;
    00423         }
    00424
    00425         // Set blocking by default (should always be the case anyway)
    00426         SetBlocking(true);
    00427     }
    00428 }
    00429
    00430 } // namespace sf

:: Copyright © 2007-2008 Laurent Gomila, all rights reserved :: Documentation generated by doxygen 1.5.2 ::