Updated/added Socket::UDPConnection documentation, added support for binding to a port and for receiving data.

This commit is contained in:
Thulinma 2014-02-04 18:20:40 +01:00
parent 773234f231
commit 7f1b28bd6f
2 changed files with 105 additions and 20 deletions

View file

@ -899,7 +899,9 @@ int Socket::Server::getSocket(){
} }
/// Create a new UDP Socket. /// Create a new UDP Socket.
/// \param nonblock Whether the socket should be nonblocking. /// Will attempt to create an IPv6 UDP socket, on fail try a IPV4 UDP socket.
/// If both fail, prints an DLVL_FAIL debug message.
/// \param nonblock Whether the socket should be nonblocking.
Socket::UDPConnection::UDPConnection(bool nonblock){ Socket::UDPConnection::UDPConnection(bool nonblock){
sock = socket(AF_INET6, SOCK_DGRAM, 0); sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock == -1){ if (sock == -1){
@ -912,11 +914,16 @@ Socket::UDPConnection::UDPConnection(bool nonblock){
down = 0; down = 0;
destAddr = 0; destAddr = 0;
destAddr_size = 0; destAddr_size = 0;
data = 0;
data_size = 0;
data_len = 0;
if (nonblock){ if (nonblock){
setBlocking(!nonblock); setBlocking(!nonblock);
} }
} //Socket::UDPConnection UDP Contructor } //Socket::UDPConnection UDP Contructor
/// Copies a UDP socket, re-allocating local copies of any needed structures.
/// The data/data_size/data_len variables are *not* copied over.
Socket::UDPConnection::UDPConnection(const UDPConnection & o){ Socket::UDPConnection::UDPConnection(const UDPConnection & o){
sock = socket(AF_INET6, SOCK_DGRAM, 0); sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock == -1){ if (sock == -1){
@ -936,8 +943,12 @@ Socket::UDPConnection::UDPConnection(const UDPConnection & o){
destAddr = 0; destAddr = 0;
destAddr_size = 0; destAddr_size = 0;
} }
data = 0;
data_size = 0;
data_len = 0;
} }
/// Closes the UDP socket, cleans up any memory allocated by the socket.
Socket::UDPConnection::~UDPConnection(){ Socket::UDPConnection::~UDPConnection(){
if (sock != -1){ if (sock != -1){
errno = EINTR; errno = EINTR;
@ -949,9 +960,19 @@ Socket::UDPConnection::~UDPConnection(){
free(destAddr); free(destAddr);
destAddr = 0; destAddr = 0;
} }
if (data){
free(data);
data = 0;
}
} }
/// Stores the properties of the reiving end of this UDP socket.
/// This will be the receiving end for all SendNow calls.
void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){ void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){
if (destAddr){
free(destAddr);
destAddr = 0;
}
destAddr = malloc(sizeof(struct sockaddr_in6)); destAddr = malloc(sizeof(struct sockaddr_in6));
if (destAddr){ if (destAddr){
destAddr_size = sizeof(struct sockaddr_in6); destAddr_size = sizeof(struct sockaddr_in6);
@ -979,27 +1000,87 @@ void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){
DEBUG_MSG(DLVL_FAIL, "Could not set destination for UDP socket: %s:%d", destIp.c_str(), port); DEBUG_MSG(DLVL_FAIL, "Could not set destination for UDP socket: %s:%d", destIp.c_str(), port);
}//Socket::UDPConnection SetDestination }//Socket::UDPConnection SetDestination
/// Sets the socket to be blocking if the parameters is true.
/// Sets the socket to be non-blocking otherwise.
void Socket::UDPConnection::setBlocking(bool blocking){ void Socket::UDPConnection::setBlocking(bool blocking){
if (sock >= 0){ if (sock >= 0){
setFDBlocking(sock, blocking); setFDBlocking(sock, blocking);
} }
} }
void Socket::UDPConnection::SendNow(const std::string & data){ /// Sends a UDP datagram using the buffer sdata.
SendNow(data.c_str(), data.size()); /// This function simply calls SendNow(const char*, size_t)
void Socket::UDPConnection::SendNow(const std::string & sdata){
SendNow(sdata.c_str(), sdata.size());
} }
void Socket::UDPConnection::SendNow(const char* data){ /// Sends a UDP datagram using the buffer sdata.
int len = strlen(data); /// sdata is required to be NULL-terminated.
SendNow(data, len); /// This function simply calls SendNow(const char*, size_t)
void Socket::UDPConnection::SendNow(const char* sdata){
int len = strlen(sdata);
SendNow(sdata, len);
} }
void Socket::UDPConnection::SendNow(const char * data, size_t len){ /// Sends a UDP datagram using the buffer sdata of length len.
/// Does not do anything if len < 1.
/// Prints an DLVL_FAIL level debug message if sending failed.
void Socket::UDPConnection::SendNow(const char * sdata, size_t len){
if (len < 1){return;} if (len < 1){return;}
int r = sendto(sock, data, len, 0, (sockaddr*)destAddr, destAddr_size); int r = sendto(sock, sdata, len, 0, (sockaddr*)destAddr, destAddr_size);
if (r > 0){ if (r > 0){
up += r; up += r;
}else{ }else{
DEBUG_MSG(DLVL_FAIL, "Could not send UDP data through %d: %s", sock, strerror(errno)); DEBUG_MSG(DLVL_FAIL, "Could not send UDP data through %d: %s", sock, strerror(errno));
} }
} }
/// Bind to a port number, returning the bound port.
/// Attempts to bind over IPv6 first.
/// If it fails, attempts to bind over IPv4.
/// If that fails too, gives up and returns zero.
/// Prints a debug message at DLVL_FAIL level if binding failed.
/// \return Actually bound port number, or zero on error.
int Socket::UDPConnection::bind(int port){
struct sockaddr_in6 s6;
s6.sin6_family = AF_INET6;
s6.sin6_addr = in6addr_any;
if (port){s6.sin6_port = htons(port);}
int r = ::bind(sock, (sockaddr*)&s6, sizeof(s6));
if (r == 0){return ntohs(s6.sin6_port);}
struct sockaddr_in s4;
s4.sin_family = AF_INET;
s4.sin_addr.s_addr = INADDR_ANY;
if (port){s4.sin_port = htons(port);}
r = ::bind(sock, (sockaddr*)&s4, sizeof(s4));
if (r == 0){return ntohs(s4.sin_port);}
DEBUG_MSG(DLVL_FAIL, "Could not bind UDP socket to port %d", port);
return 0;
}
/// Attempt to receive a UDP packet.
/// This will automatically allocate or resize the internal data buffer if needed.
/// If a packet is received, it will be placed in the "data" member, with it's length in "data_len".
/// \return True if a packet was received, false otherwise.
bool Socket::UDPConnection::Receive(){
int r = recvfrom(sock, data, data_size, MSG_PEEK | MSG_TRUNC, 0, 0);
if (data_size < (unsigned int)r){
data = (char*)realloc(data, r);
if (data){
data_size = r;
}else{
data_size = 0;
}
}
r = recvfrom(sock, data, data_size, 0, 0, 0);
if (r > 0){
down += r;
data_len = r;
return true;
}else{
data_len = 0;
return false;
}
}

View file

@ -123,20 +123,24 @@ namespace Socket {
private: private:
int sock; ///< Internally saved socket number. int sock; ///< Internally saved socket number.
std::string remotehost;///< Stores remote host address std::string remotehost;///< Stores remote host address
void * destAddr; void * destAddr;///< Destination address pointer.
unsigned int destAddr_size; unsigned int destAddr_size;///< Size of the destination address pointer.
unsigned int up; unsigned int up;///< Amount of bytes transferred up.
unsigned int down; unsigned int down;///< Amount of bytes transferred down.
unsigned int data_size;///< The size in bytes of the allocated space in the data pointer.
public: public:
UDPConnection(const UDPConnection & o); ///< Copy constructor char * data;///< Holds the last received packet.
UDPConnection(bool nonblock = false); ///< Create new UDP socket unsigned int data_len; ///< The size in bytes of the last received packet.
UDPConnection(const UDPConnection & o);
UDPConnection(bool nonblock = false);
~UDPConnection(); ~UDPConnection();
void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false). int bind(int port);
void SetDestination(std::string hostname, uint32_t port); ///< Sets the hostname and port destination for this UDP socket. void setBlocking(bool blocking);
void Close();///< Closes the local socket void SetDestination(std::string hostname, uint32_t port);
void SendNow(const std::string & data); ///< Will not buffer anything but always send right away. Blocks. bool Receive();
void SendNow(const char * data); ///< Will not buffer anything but always send right away. Blocks. void SendNow(const std::string & data);
void SendNow(const char * data, size_t len); ///< Will not buffer anything but always send right away. Blocks. void SendNow(const char * data);
void SendNow(const char * data, size_t len);
}; };
} }