- 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     // We start by getting the size of the incoming packet
    00248     Uint32      PacketSize = 0;
    00249     std::size_t Received   = 0;
    00250     if (myPendingPacketSize < 0)
    00251     {
    00252         // Loop until we've received the entire size of the packet
    00253         // (even a 4 bytes variable may be received in more than one call)
    00254         while (myPendingHeaderSize < sizeof(myPendingHeader))
    00255         {
    00256             char* Data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize;
    00257             Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received, Address, Port);
    00258             myPendingHeaderSize += Received;
    00259
    00260             if (Status != Socket::Done)
    00261                 return Status;
    00262         }
    00263
    00264         PacketSize = ntohl(myPendingHeader);
    00265         myPendingHeaderSize = 0;
    00266     }
    00267     else
    00268     {
    00269         // There is a pending packet : we already know its size
    00270         PacketSize = myPendingPacketSize;
    00271     }
    00272
    00273     // Use another address instance for receiving the packet data ;
    00274     // chunks of data coming from a different sender will be discarded (and lost...)
    00275     IPAddress Sender;
    00276     unsigned short SenderPort;
    00277
    00278     // Then loop until we receive all the packet data
    00279     char Buffer[1024];
    00280     while (myPendingPacket.size() < PacketSize)
    00281     {
    00282         // Receive a chunk of data
    00283         std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
    00284         Socket::Status Status = Receive(Buffer, SizeToGet, Received, Sender, SenderPort);
    00285         if (Status != Socket::Done)
    00286         {
    00287             // We must save the size of the pending packet until we can receive its content
    00288             if (Status == Socket::NotReady)
    00289                 myPendingPacketSize = PacketSize;
    00290             return Status;
    00291         }
    00292
    00293         // Append it into the packet
    00294         if ((Sender == Address) && (SenderPort == Port) && (Received > 0))
    00295         {
    00296             myPendingPacket.resize(myPendingPacket.size() + Received);
    00297             char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
    00298             memcpy(Begin, Buffer, Received);
    00299         }
    00300     }
    00301
    00302     // We have received all the datas : we can copy it to the user packet, and clear our internal packet
    00303     PacketToReceive.Clear();
    00304     if (!myPendingPacket.empty())
    00305         PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
    00306     myPendingPacket.clear();
    00307     myPendingPacketSize = -1;
    00308
    00309     return Socket::Done;
    00310 }
    00311
    00312
    00316 bool SocketUDP::Close()
    00317 {
    00318     if (IsValid())
    00319     {
    00320         if (!SocketHelper::Close(mySocket))
    00321         {
    00322             std::cerr << "Failed to close socket" << std::endl;
    00323             return false;
    00324         }
    00325
    00326         mySocket = SocketHelper::InvalidSocket();
    00327     }
    00328
    00329     myPort       = 0;
    00330     myIsBlocking = true;
    00331
    00332     return true;
    00333 }
    00334
    00335
    00340 bool SocketUDP::IsValid() const
    00341 {
    00342     return mySocket != SocketHelper::InvalidSocket();
    00343 }
    00344
    00345
    00349 unsigned short SocketUDP::GetPort() const
    00350 {
    00351     return myPort;
    00352 }
    00353
    00354
    00358 bool SocketUDP::operator ==(const SocketUDP& Other) const
    00359 {
    00360     return mySocket == Other.mySocket;
    00361 }
    00362
    00363
    00367 bool SocketUDP::operator !=(const SocketUDP& Other) const
    00368 {
    00369     return mySocket != Other.mySocket;
    00370 }
    00371
    00372
    00378 bool SocketUDP::operator <(const SocketUDP& Other) const
    00379 {
    00380     return mySocket < Other.mySocket;
    00381 }
    00382
    00383
    00388 SocketUDP::SocketUDP(SocketHelper::SocketType Descriptor)
    00389 {
    00390     Create(Descriptor);
    00391 }
    00392
    00393
    00397 void SocketUDP::Create(SocketHelper::SocketType Descriptor)
    00398 {
    00399     // Use the given socket descriptor, or get a new one
    00400     mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_DGRAM, 0);
    00401     myIsBlocking = true;
    00402
    00403     // Clear the last port used
    00404     myPort = 0;
    00405
    00406     // Reset the pending packet
    00407     myPendingHeaderSize = 0;
    00408     myPendingPacket.clear();
    00409     myPendingPacketSize = -1;
    00410
    00411     // Setup default options
    00412     if (IsValid())
    00413     {
    00414         // To avoid the "Address already in use" error message when trying to bind to the same port
    00415         int Yes = 1;
    00416         if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
    00417         {
    00418             std::cerr << "Failed to set socket option \"reuse address\" ; "
    00419                       << "binding to a same port may fail if too fast" << std::endl;
    00420         }
    00421
    00422         // Enable broadcast by default
    00423         if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
    00424         {
    00425             std::cerr << "Failed to enable broadcast on UDP socket" << std::endl;
    00426         }
    00427
    00428         // Set blocking by default (should always be the case anyway)
    00429         SetBlocking(true);
    00430     }
    00431 }
    00432
    00433 } // namespace sf

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