UDP socket edits by Erik Zandvliet

This commit is contained in:
Thulinma 2016-02-12 16:16:49 +01:00
parent d56e7f1408
commit 243595ff4d
2 changed files with 59 additions and 24 deletions

View file

@ -971,12 +971,18 @@ int Socket::Server::getSocket() {
/// If both fail, prints an DLVL_FAIL debug message. /// If both fail, prints an DLVL_FAIL debug message.
/// \param nonblock Whether the socket should be nonblocking. /// \param nonblock Whether the socket should be nonblocking.
Socket::UDPConnection::UDPConnection(bool nonblock) { Socket::UDPConnection::UDPConnection(bool nonblock) {
#ifdef __CYGWIN__
#warning UDP over IPv6 is currently disabled on windows
isIPv6 = false;
sock = socket(AF_INET, SOCK_DGRAM, 0);
#else
isIPv6 = true; isIPv6 = true;
sock = socket(AF_INET6, SOCK_DGRAM, 0); sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock == -1) { if (sock == -1) {
sock = socket(AF_INET, SOCK_DGRAM, 0); sock = socket(AF_INET, SOCK_DGRAM, 0);
isIPv6 = false; isIPv6 = false;
} }
#endif
if (sock == -1) { if (sock == -1) {
DEBUG_MSG(DLVL_FAIL, "Could not create UDP socket: %s", strerror(errno)); DEBUG_MSG(DLVL_FAIL, "Could not create UDP socket: %s", strerror(errno));
} }
@ -995,18 +1001,18 @@ Socket::UDPConnection::UDPConnection(bool nonblock) {
/// Copies a UDP socket, re-allocating local copies of any needed structures. /// Copies a UDP socket, re-allocating local copies of any needed structures.
/// The data/data_size/data_len variables are *not* copied over. /// The data/data_size/data_len variables are *not* copied over.
Socket::UDPConnection::UDPConnection(const UDPConnection & o) { Socket::UDPConnection::UDPConnection(const UDPConnection & o) {
#ifdef __CYGWIN__
#warning UDP over IPv6 is currently disabled on windows
isIPv6 = false;
sock = socket(AF_INET, SOCK_DGRAM, 0);
#else
isIPv6 = true; isIPv6 = true;
sock = socket(AF_INET6, SOCK_DGRAM, 0); sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock == -1) { if (sock == -1) {
sock = socket(AF_INET, SOCK_DGRAM, 0); sock = socket(AF_INET, SOCK_DGRAM, 0);
isIPv6 = false; isIPv6 = false;
}else{
#ifdef __CYGWIN__
// Under windows, turn IPv6-only mode off.
int on = 0;
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
#endif
} }
#endif
if (sock == -1) { if (sock == -1) {
DEBUG_MSG(DLVL_FAIL, "Could not create UDP socket: %s", strerror(errno)); DEBUG_MSG(DLVL_FAIL, "Could not create UDP socket: %s", strerror(errno));
} }
@ -1144,7 +1150,8 @@ void Socket::UDPConnection::SendNow(const char * sdata, size_t len) {
/// If that fails too, gives up and returns zero. /// If that fails too, gives up and returns zero.
/// Prints a debug message at DLVL_FAIL level if binding failed. /// Prints a debug message at DLVL_FAIL level if binding failed.
/// \return Actually bound port number, or zero on error. /// \return Actually bound port number, or zero on error.
int Socket::UDPConnection::bind(int port, std::string iface) { int Socket::UDPConnection::bind(int port, std::string iface, const std::string & multicastInterfaces) {
int result = 0;
if (isIPv6) { if (isIPv6) {
struct sockaddr_in6 s6; struct sockaddr_in6 s6;
memset(&s6, 0, sizeof(s6)); memset(&s6, 0, sizeof(s6));
@ -1157,32 +1164,60 @@ int Socket::UDPConnection::bind(int port, std::string iface) {
s6.sin6_port = htons(port); s6.sin6_port = htons(port);
int r = ::bind(sock, (sockaddr *)&s6, sizeof(s6)); int r = ::bind(sock, (sockaddr *)&s6, sizeof(s6));
if (r == 0) { if (r == 0) {
return ntohs(s6.sin6_port); result = ntohs(s6.sin6_port);
} }
} else { } else {
struct sockaddr_in s4; struct sockaddr_in s4;
memset(&s4, 0, sizeof(s4)); memset(&s4, 0, sizeof(s4));
s4.sin_family = AF_INET; s4.sin_family = AF_INET;
if (iface == "0.0.0.0" || iface.length() == 0) { if (iface == "0.0.0.0" || iface.length() == 0) {
s4.sin_addr.s_addr = INADDR_ANY; s4.sin_addr.s_addr = htonl(INADDR_ANY);
} else { } else {
inet_pton(AF_INET, iface.c_str(), &s4.sin_addr); inet_pton(AF_INET, iface.c_str(), &s4.sin_addr);
} }
s4.sin_port = htons(port); s4.sin_port = htons(port);
int r = ::bind(sock, (sockaddr *)&s4, sizeof(s4)); int r = ::bind(sock, (sockaddr *)&s4, sizeof(s4));
if (r == 0) { if (r == 0) {
return ntohs(s4.sin_port); result = ntohs(s4.sin_port);
} }
} }
if (!result){
DEBUG_MSG(DLVL_FAIL, "Could not bind %s UDP socket to port %d: %s", isIPv6 ? "IPv6" : "IPv4", port, strerror(errno)); DEBUG_MSG(DLVL_FAIL, "Could not bind %s UDP socket to port %d: %s", isIPv6 ? "IPv6" : "IPv4", port, strerror(errno));
return 0; return 0;
} }
//Detect multicast
if (iface.length() && ((atoi(iface.c_str()) & 0xE0) == 0xE0)){
if (!multicastInterfaces.length()){
WARN_MSG("Multicast IP given without any defined interfaces");
}else{
struct ip_mreq group;
inet_pton(AF_INET, iface.c_str(), &group.imr_multiaddr.s_addr);
size_t loc = 0;
while (loc != std::string::npos){
size_t nxtPos = multicastInterfaces.find(',', loc);
std::string curIface = multicastInterfaces.substr(loc, (nxtPos == std::string::npos ? nxtPos : nxtPos - loc));
inet_pton(AF_INET, curIface.c_str(), &group.imr_interface.s_addr);
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0) {
WARN_MSG("Unable to register for multicast on interface %s: %s", curIface.c_str() , strerror(errno));
}
loc = (nxtPos == std::string::npos ? nxtPos : nxtPos + 1);
}
}
}
return result;
}
/// Attempt to receive a UDP packet. /// Attempt to receive a UDP packet.
/// This will automatically allocate or resize the internal data buffer if needed. /// 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". /// 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. /// \return True if a packet was received, false otherwise.
bool Socket::UDPConnection::Receive() { bool Socket::UDPConnection::Receive() {
#ifdef __CYGWIN__
if (data_size != SOCKETSIZE){
data = (char *)realloc(data, SOCKETSIZE);
data_size = SOCKETSIZE;
}
#endif
int r = recvfrom(sock, data, data_size, MSG_PEEK | MSG_TRUNC, 0, 0); int r = recvfrom(sock, data, data_size, MSG_PEEK | MSG_TRUNC, 0, 0);
if (r == -1) { if (r == -1) {
if (errno != EAGAIN) { if (errno != EAGAIN) {

View file

@ -137,7 +137,7 @@ namespace Socket {
UDPConnection(bool nonblock = false); UDPConnection(bool nonblock = false);
~UDPConnection(); ~UDPConnection();
int getSock(); int getSock();
int bind(int port, std::string iface = ""); int bind(int port, std::string iface = "", const std::string & multicastAddress = "");
void setBlocking(bool blocking); void setBlocking(bool blocking);
void SetDestination(std::string hostname, uint32_t port); void SetDestination(std::string hostname, uint32_t port);
void GetDestination(std::string & hostname, uint32_t & port); void GetDestination(std::string & hostname, uint32_t & port);