- Main Page
- Namespaces
- Classes
- Files

- File List

# SocketTCP.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/SocketTCP.hpp>
    00029 #include <SFML/Network/IPAddress.hpp>
    00030 #include <SFML/Network/Packet.hpp>
    00031 #include <SFML/Network/SocketHelper.hpp>
    00032 #include <algorithm>
    00033 #include <iostream>
    00034 #include <string.h>
    00035
    00036
    00037 #ifdef _MSC_VER
    00038     #pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
    00039 #endif
    00040
    00041
    00042 namespace sf
    00043 {
    00047 SocketTCP::SocketTCP()
    00048 {
    00049     Create(SocketHelper::InvalidSocket());
    00050 }
    00051
    00052
    00056 void SocketTCP::SetBlocking(bool Blocking)
    00057 {
    00058     // Make sure our socket is valid
    00059     if (!IsValid())
    00060         Create();
    00061
    00062     SocketHelper::SetBlocking(mySocket, Blocking);
    00063     myIsBlocking = Blocking;
    00064 }
    00065
    00066
    00070 Socket::Status SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout)
    00071 {
    00072     // Make sure our socket is valid
    00073     if (!IsValid())
    00074         Create();
    00075
    00076     // Build the host address
    00077     sockaddr_in SockAddr;
    00078     memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
    00079     SockAddr.sin_addr.s_addr = inet_addr(HostAddress.ToString().c_str());
    00080     SockAddr.sin_family      = AF_INET;
    00081     SockAddr.sin_port        = htons(Port);
    00082
    00083     if (Timeout <= 0)
    00084     {
    00085         // ----- We're not using a timeout : just try to connect -----
    00086
    00087         if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
    00088         {
    00089             // Failed to connect
    00090             return SocketHelper::GetErrorStatus();
    00091         }
    00092
    00093         // Connection succeeded
    00094         return Socket::Done;
    00095     }
    00096     else
    00097     {
    00098         // ----- We're using a timeout : we'll need a few tricks to make it work -----
    00099
    00100         // Save the previous blocking state
    00101         bool IsBlocking = myIsBlocking;
    00102
    00103         // Switch to non-blocking to enable our connection timeout
    00104         if (IsBlocking)
    00105             SetBlocking(false);
    00106
    00107         // Try to connect to host
    00108         if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) >= 0)
    00109         {
    00110             // We got instantly connected! (it may no happen a lot...)
    00111             return Socket::Done;
    00112         }
    00113
    00114         // Get the error status
    00115         Socket::Status Status = SocketHelper::GetErrorStatus();
    00116
    00117         // If we were in non-blocking mode, return immediatly
    00118         if (!IsBlocking)
    00119             return Status;
    00120
    00121         // Otherwise, wait until something happens to our socket (success, timeout or error)
    00122         if (Status == Socket::NotReady)
    00123         {
    00124             // Setup the selector
    00125             fd_set Selector;
    00126             FD_ZERO(&Selector);
    00127             FD_SET(mySocket, &Selector);
    00128
    00129             // Setup the timeout
    00130             timeval Time;
    00131             Time.tv_sec  = static_cast<long>(Timeout);
    00132             Time.tv_usec = (static_cast<long>(Timeout * 1000) % 1000) * 1000;
    00133
    00134             // Wait for something to write on our socket (which means that the connection request has returned)
    00135             if (select(static_cast<int>(mySocket + 1), NULL, &Selector, NULL, &Time) > 0)
    00136             {
    00137                 // At this point the connection may have been either accepted or refused.
    00138                 // To know whether it's a success or a failure, we try to retrieve the name of the connected peer
    00139                 SocketHelper::LengthType Size = sizeof(SockAddr);
    00140                 if (getpeername(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), &Size) != -1)
    00141                 {
    00142                     // Connection accepted
    00143                     Status = Socket::Done;
    00144                 }
    00145                 else
    00146                 {
    00147                     // Connection failed
    00148                     Status = SocketHelper::GetErrorStatus();
    00149                 }
    00150             }
    00151             else
    00152             {
    00153                 // Failed to connect before timeout is over
    00154                 Status = SocketHelper::GetErrorStatus();
    00155             }
    00156         }
    00157
    00158         // Switch back to blocking mode
    00159         SetBlocking(true);
    00160
    00161         return Status;
    00162     }
    00163 }
    00164
    00165
    00169 bool SocketTCP::Listen(unsigned short Port)
    00170 {
    00171     // Make sure our socket is valid
    00172     if (!IsValid())
    00173         Create();
    00174
    00175     // Build the address
    00176     sockaddr_in SockAddr;
    00177     memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
    00178     SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    00179     SockAddr.sin_family      = AF_INET;
    00180     SockAddr.sin_port        = htons(Port);
    00181
    00182     // Bind the socket to the specified port
    00183     if (bind(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
    00184     {
    00185         // Not likely to happen, but...
    00186         std::cerr << "Failed to bind socket to port " << Port << std::endl;
    00187         return false;
    00188     }
    00189
    00190     // Listen to the bound port
    00191     if (listen(mySocket, 0) == -1)
    00192     {
    00193         // Oops, socket is deaf
    00194         std::cerr << "Failed to listen to port " << Port << std::endl;
    00195         return false;
    00196     }
    00197
    00198     return true;
    00199 }
    00200
    00201
    00206 Socket::Status SocketTCP::Accept(SocketTCP& Connected, IPAddress* Address)
    00207 {
    00208     // Address that will be filled with client informations
    00209     sockaddr_in ClientAddress;
    00210     SocketHelper::LengthType Length = sizeof(ClientAddress);
    00211
    00212     // Accept a new connection
    00213     Connected = accept(mySocket, reinterpret_cast<sockaddr*>(&ClientAddress), &Length);
    00214
    00215     // Check errors
    00216     if (!Connected.IsValid())
    00217     {
    00218         if (Address)
    00219             *Address = IPAddress();
    00220
    00221         return SocketHelper::GetErrorStatus();
    00222     }
    00223
    00224     // Fill address if requested
    00225     if (Address)
    00226         *Address = IPAddress(inet_ntoa(ClientAddress.sin_addr));
    00227
    00228     return Socket::Done;
    00229 }
    00230
    00231
    00235 Socket::Status SocketTCP::Send(const char* Data, std::size_t Size)
    00236 {
    00237     // First check that socket is valid
    00238     if (!IsValid())
    00239         return Socket::Error;
    00240
    00241     // Check parameters
    00242     if (Data && Size)
    00243     {
    00244         // Loop until every byte has been sent
    00245         int Sent = 0;
    00246         int SizeToSend = static_cast<int>(Size);
    00247         for (int Length = 0; Length < SizeToSend; Length += Sent)
    00248         {
    00249             // Send a chunk of data
    00250             Sent = send(mySocket, Data + Length, SizeToSend - Length, 0);
    00251
    00252             // Check if an error occured
    00253             if (Sent <= 0)
    00254                 return SocketHelper::GetErrorStatus();
    00255         }
    00256
    00257         return Socket::Done;
    00258     }
    00259     else
    00260     {
    00261         // Error...
    00262         std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl;
    00263         return Socket::Error;
    00264     }
    00265 }
    00266
    00267
    00272 Socket::Status SocketTCP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived)
    00273 {
    00274     // First clear the size received
    00275     SizeReceived = 0;
    00276
    00277     // Check that socket is valid
    00278     if (!IsValid())
    00279         return Socket::Error;
    00280
    00281     // Check parameters
    00282     if (Data && MaxSize)
    00283     {
    00284         // Receive a chunk of bytes
    00285         int Received = recv(mySocket, Data, static_cast<int>(MaxSize), 0);
    00286
    00287         // Check the number of bytes received
    00288         if (Received > 0)
    00289         {
    00290             SizeReceived = static_cast<std::size_t>(Received);
    00291             return Socket::Done;
    00292         }
    00293         else if (Received == 0)
    00294         {
    00295             return Socket::Disconnected;
    00296         }
    00297         else
    00298         {
    00299             return SocketHelper::GetErrorStatus();
    00300         }
    00301     }
    00302     else
    00303     {
    00304         // Error...
    00305         std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
    00306         return Socket::Error;
    00307     }
    00308 }
    00309
    00310
    00314 Socket::Status SocketTCP::Send(Packet& PacketToSend)
    00315 {
    00316     // Get the data to send from the packet
    00317     std::size_t DataSize = 0;
    00318     const char* Data = PacketToSend.OnSend(DataSize);
    00319
    00320     // Send the packet size
    00321     Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
    00322     Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize));
    00323
    00324     // Send the packet data
    00325     if (PacketSize > 0)
    00326     {
    00327         return Send(Data, DataSize);
    00328     }
    00329     else
    00330     {
    00331         return Socket::Done;
    00332     }
    00333 }
    00334
    00335
    00340 Socket::Status SocketTCP::Receive(Packet& PacketToReceive)
    00341 {
    00342     // We start by getting the size of the incoming packet
    00343     Uint32      PacketSize = 0;
    00344     std::size_t Received   = 0;
    00345     if (myPendingPacketSize < 0)
    00346     {
    00347         // Loop until we've received the entire size of the packet
    00348         // (even a 4 bytes variable may be received in more than one call)
    00349         while (myPendingHeaderSize < sizeof(myPendingHeader))
    00350         {
    00351             char* Data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize;
    00352             Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received);
    00353             myPendingHeaderSize += Received;
    00354
    00355             if (Status != Socket::Done)
    00356                 return Status;
    00357         }
    00358
    00359         PacketSize = ntohl(myPendingHeader);
    00360         myPendingHeaderSize = 0;
    00361     }
    00362     else
    00363     {
    00364         // There is a pending packet : we already know its size
    00365         PacketSize = myPendingPacketSize;
    00366     }
    00367
    00368     // Then loop until we receive all the packet data
    00369     char Buffer[1024];
    00370     while (myPendingPacket.size() < PacketSize)
    00371     {
    00372         // Receive a chunk of data
    00373         std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
    00374         Socket::Status Status = Receive(Buffer, SizeToGet, Received);
    00375         if (Status != Socket::Done)
    00376         {
    00377             // We must save the size of the pending packet until we can receive its content
    00378             if (Status == Socket::NotReady)
    00379                 myPendingPacketSize = PacketSize;
    00380             return Status;
    00381         }
    00382
    00383         // Append it into the packet
    00384         if (Received > 0)
    00385         {
    00386             myPendingPacket.resize(myPendingPacket.size() + Received);
    00387             char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
    00388             memcpy(Begin, Buffer, Received);
    00389         }
    00390     }
    00391
    00392     // We have received all the datas : we can copy it to the user packet, and clear our internal packet
    00393     PacketToReceive.Clear();
    00394     if (!myPendingPacket.empty())
    00395         PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
    00396     myPendingPacket.clear();
    00397     myPendingPacketSize = -1;
    00398
    00399     return Socket::Done;
    00400 }
    00401
    00402
    00406 bool SocketTCP::Close()
    00407 {
    00408     if (IsValid())
    00409     {
    00410         if (!SocketHelper::Close(mySocket))
    00411         {
    00412             std::cerr << "Failed to close socket" << std::endl;
    00413             return false;
    00414         }
    00415
    00416         mySocket = SocketHelper::InvalidSocket();
    00417     }
    00418
    00419     myIsBlocking = true;
    00420
    00421     return true;
    00422 }
    00423
    00424
    00429 bool SocketTCP::IsValid() const
    00430 {
    00431     return mySocket != SocketHelper::InvalidSocket();
    00432 }
    00433
    00434
    00438 bool SocketTCP::operator ==(const SocketTCP& Other) const
    00439 {
    00440     return mySocket == Other.mySocket;
    00441 }
    00442
    00443
    00447 bool SocketTCP::operator !=(const SocketTCP& Other) const
    00448 {
    00449     return mySocket != Other.mySocket;
    00450 }
    00451
    00452
    00458 bool SocketTCP::operator <(const SocketTCP& Other) const
    00459 {
    00460     return mySocket < Other.mySocket;
    00461 }
    00462
    00463
    00468 SocketTCP::SocketTCP(SocketHelper::SocketType Descriptor)
    00469 {
    00470     Create(Descriptor);
    00471 }
    00472
    00473
    00477 void SocketTCP::Create(SocketHelper::SocketType Descriptor)
    00478 {
    00479     // Use the given socket descriptor, or get a new one
    00480     mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_STREAM, 0);
    00481     myIsBlocking = true;
    00482
    00483     // Reset the pending packet
    00484     myPendingHeaderSize = 0;
    00485     myPendingPacket.clear();
    00486     myPendingPacketSize = -1;
    00487
    00488     // Setup default options
    00489     if (IsValid())
    00490     {
    00491         // To avoid the "Address already in use" error message when trying to bind to the same port
    00492         int Yes = 1;
    00493         if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
    00494         {
    00495             std::cerr << "Failed to set socket option \"SO_REUSEADDR\" ; "
    00496                       << "binding to a same port may fail if too fast" << std::endl;
    00497         }
    00498
    00499         // Disable the Nagle algorithm (ie. removes buffering of TCP packets)
    00500         if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
    00501         {
    00502             std::cerr << "Failed to set socket option \"TCP_NODELAY\" ; "
    00503                       << "all your TCP packets will be buffered" << std::endl;
    00504         }
    00505
    00506         // Set blocking by default (should always be the case anyway)
    00507         SetBlocking(true);
    00508     }
    00509 }
    00510
    00511 } // namespace sf

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