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 <SFML/System/Err.hpp> 00032 #include <algorithm> 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 sockAddr; 00076 sockAddr.sin_family = AF_INET; 00077 sockAddr.sin_port = htons(port); 00078 sockAddr.sin_addr.s_addr = INADDR_ANY; 00079 memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero)); 00080 00081 // Bind the socket to the port 00082 if (bind(mySocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)) == -1) 00083 { 00084 Err() << "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 sizeInBytes, 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 && sizeInBytes) 00126 { 00127 // Build the target address 00128 sockaddr_in sockAddr; 00129 sockAddr.sin_family = AF_INET; 00130 sockAddr.sin_port = htons(port); 00131 sockAddr.sin_addr.s_addr = inet_addr(address.ToString().c_str()); 00132 memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero)); 00133 00134 // Loop until every byte has been sent 00135 int sent = 0; 00136 int sizeToSend = static_cast<int>(sizeInBytes); 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*>(&sockAddr), sizeof(sockAddr)); 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 Err() << "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 Err() << "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 sockAddr; 00183 sockAddr.sin_family = AF_INET; 00184 sockAddr.sin_port = 0; 00185 sockAddr.sin_addr.s_addr = INADDR_ANY; 00186 memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero)); 00187 SocketHelper::LengthType sockAddrSize = sizeof(sockAddr); 00188 00189 // Receive a chunk of bytes 00190 int received = recvfrom(mySocket, data, static_cast<int>(maxSize), 0, reinterpret_cast<sockaddr*>(&sockAddr), &sockAddrSize); 00191 00192 // Check the number of bytes received 00193 if (received > 0) 00194 { 00195 address = IPAddress(inet_ntoa(sockAddr.sin_addr)); 00196 port = ntohs(sockAddr.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 Err() << "Cannot receive data from the network (invalid parameters)" << std::endl; 00211 return Socket::Error; 00212 } 00213 } 00214 00215 00219 Socket::Status SocketUDP::Send(Packet& packet, 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 = packet.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& packet, 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 packet.Clear(); 00304 if (!myPendingPacket.empty()) 00305 packet.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 Err() << "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 Err() << "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 Err() << "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 ::