SocketUDP.cpp
00001 00002 // 00003 // SFML - Simple and Fast Multimedia Library 00004 // Copyright (C) 2007-2009 Laurent Gomila ([email protected]) 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 ::