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 ::