From 629b24853a4bd89d61a9d944b679549e17a7032a Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 3 Nov 2016 15:15:42 +0100 Subject: [PATCH] Added hostBytesToStr function to socket library, fixed code style, fixed UDP Cygwin support --- lib/socket.cpp | 888 +++++++++++------------ lib/socket.h | 262 +++---- src/controller/controller_statistics.cpp | 11 +- 3 files changed, 544 insertions(+), 617 deletions(-) diff --git a/lib/socket.cpp b/lib/socket.cpp index 81ff3379..1ff5b049 100644 --- a/lib/socket.cpp +++ b/lib/socket.cpp @@ -3,17 +3,17 @@ /// Written by Jaron Vietor in 2010 for DDVTech #include "socket.h" -#include "timing.h" #include "defines.h" -#include -#include +#include "timing.h" +#include +#include #include #include -#include #include -#include +#include +#include -#define BUFFER_BLOCKSIZE 4096 //set buffer blocksize to 4KiB +#define BUFFER_BLOCKSIZE 4096 // set buffer blocksize to 4KiB #ifdef __CYGWIN__ #define SOCKETSIZE 8092ul @@ -21,7 +21,33 @@ #define SOCKETSIZE 51200ul #endif -std::string uint2string(unsigned int i) { +/// Checks bytes (length len) containing a binary-encoded IPv4 or IPv6 IP address, and writes it in human-readable notation to target. +/// Writes "unknown" if it cannot decode to a sensible value. +void Socket::hostBytesToStr(const char *bytes, size_t len, std::string &target){ + switch (len){ + case 4: + char tmpstr[16]; + snprintf(tmpstr, 16, "%hhu.%hhu.%hhu.%hhu", bytes[0], bytes[1], bytes[2], bytes[3]); + target = tmpstr; + break; + case 16: + if (memcmp(bytes, "\000\000\000\000\000\000\000\000\000\000\377\377", 12) == 0){ + char tmpstr[16]; + snprintf(tmpstr, 16, "%hhu.%hhu.%hhu.%hhu", bytes[12], bytes[13], bytes[14], bytes[15]); + target = tmpstr; + }else{ + char tmpstr[40]; + snprintf(tmpstr, 40, "%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x:%0.2x%0.2x", bytes[0], bytes[1], + bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], + bytes[14], bytes[15]); + target = tmpstr; + } + break; + default: target = "unknown"; break; + } +} + +std::string uint2string(unsigned int i){ std::stringstream st; st << i; return st.str(); @@ -30,97 +56,87 @@ std::string uint2string(unsigned int i) { /// Returns the amount of elements in the internal std::deque of std::string objects. /// The back is popped as long as it is empty, first - this way this function is /// guaranteed to return 0 if the buffer is empty. -unsigned int Socket::Buffer::size() { - while (data.size() > 0 && data.back().empty()) { - data.pop_back(); - } +unsigned int Socket::Buffer::size(){ + while (data.size() > 0 && data.back().empty()){data.pop_back();} return data.size(); } /// Returns either the amount of total bytes available in the buffer or max, whichever is smaller. -unsigned int Socket::Buffer::bytes(unsigned int max) { +unsigned int Socket::Buffer::bytes(unsigned int max){ unsigned int i = 0; - for (std::deque::iterator it = data.begin(); it != data.end(); ++it) { + for (std::deque::iterator it = data.begin(); it != data.end(); ++it){ i += (*it).size(); - if (i >= max) { - return max; - } + if (i >= max){return max;} } return i; } /// Appends this string to the internal std::deque of std::string objects. /// It is automatically split every BUFFER_BLOCKSIZE bytes. -void Socket::Buffer::append(const std::string & newdata) { +void Socket::Buffer::append(const std::string &newdata){ append(newdata.c_str(), newdata.size()); } /// Appends this data block to the internal std::deque of std::string objects. /// It is automatically split every BUFFER_BLOCKSIZE bytes. -void Socket::Buffer::append(const char * newdata, const unsigned int newdatasize) { +void Socket::Buffer::append(const char *newdata, const unsigned int newdatasize){ unsigned int i = 0, j = 0; - while (i < newdatasize) { + while (i < newdatasize){ j = i; - while (j < newdatasize && j - i <= BUFFER_BLOCKSIZE) { + while (j < newdatasize && j - i <= BUFFER_BLOCKSIZE){ j++; - if (newdata[j - 1] == '\n') { - break; - } + if (newdata[j - 1] == '\n'){break;} } - if (i != j) { - DONTEVEN_MSG("Adding a block of size %d", j - i); + if (i != j){ data.push_front(std::string(newdata + i, (size_t)(j - i))); i = j; - } else { + }else{ break; } } - if (data.size() > 5000) { - DEBUG_MSG(DLVL_WARN, "Warning: After %d new bytes, buffer has %d parts containing over %u bytes!", newdatasize, (int)data.size(), bytes(9000)); + if (data.size() > 5000){ + DEBUG_MSG(DLVL_WARN, "Warning: After %d new bytes, buffer has %d parts containing over %u bytes!", newdatasize, (int)data.size(), + bytes(9000)); } } /// Prepends this data block to the internal std::deque of std::string objects. /// It is _not_ automatically split every BUFFER_BLOCKSIZE bytes. -void Socket::Buffer::prepend(const std::string & newdata) { +void Socket::Buffer::prepend(const std::string &newdata){ data.push_back(newdata); } /// Prepends this data block to the internal std::deque of std::string objects. /// It is _not_ automatically split every BUFFER_BLOCKSIZE bytes. -void Socket::Buffer::prepend(const char * newdata, const unsigned int newdatasize) { +void Socket::Buffer::prepend(const char *newdata, const unsigned int newdatasize){ data.push_back(std::string(newdata, (size_t)newdatasize)); } /// Returns true if at least count bytes are available in this buffer. -bool Socket::Buffer::available(unsigned int count) { +bool Socket::Buffer::available(unsigned int count){ size(); unsigned int i = 0; - for (std::deque::iterator it = data.begin(); it != data.end(); ++it) { + for (std::deque::iterator it = data.begin(); it != data.end(); ++it){ i += (*it).size(); - if (i >= count) { - return true; - } + if (i >= count){return true;} } return false; } /// Removes count bytes from the buffer, returning them by value. /// Returns an empty string if not all count bytes are available. -std::string Socket::Buffer::remove(unsigned int count) { +std::string Socket::Buffer::remove(unsigned int count){ size(); - if (!available(count)) { - return ""; - } + if (!available(count)){return "";} unsigned int i = 0; std::string ret; ret.reserve(count); - for (std::deque::reverse_iterator it = data.rbegin(); it != data.rend(); ++it) { - if (i + (*it).size() < count) { + for (std::deque::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){ + if (i + (*it).size() < count){ ret.append(*it); i += (*it).size(); (*it).clear(); - } else { + }else{ ret.append(*it, 0, count - i); (*it).erase(0, count - i); break; @@ -131,19 +147,17 @@ std::string Socket::Buffer::remove(unsigned int count) { /// Copies count bytes from the buffer, returning them by value. /// Returns an empty string if not all count bytes are available. -std::string Socket::Buffer::copy(unsigned int count) { +std::string Socket::Buffer::copy(unsigned int count){ size(); - if (!available(count)) { - return ""; - } + if (!available(count)){return "";} unsigned int i = 0; std::string ret; ret.reserve(count); - for (std::deque::reverse_iterator it = data.rbegin(); it != data.rend(); ++it) { - if (i + (*it).size() < count) { + for (std::deque::reverse_iterator it = data.rbegin(); it != data.rend(); ++it){ + if (i + (*it).size() < count){ ret.append(*it); i += (*it).size(); - } else { + }else{ ret.append(*it, 0, count - i); break; } @@ -152,24 +166,24 @@ std::string Socket::Buffer::copy(unsigned int count) { } /// Gets a reference to the back of the internal std::deque of std::string objects. -std::string & Socket::Buffer::get() { +std::string &Socket::Buffer::get(){ size(); static std::string empty; - if (data.size() > 0) { + if (data.size() > 0){ return data.back(); - } else { + }else{ return empty; } } /// Completely empties the buffer -void Socket::Buffer::clear() { +void Socket::Buffer::clear(){ data.clear(); } /// Create a new base socket. This is a basic constructor for converting any valid socket to a Socket::Connection. /// \param sockNo Integer representing the socket to convert. -Socket::Connection::Connection(int sockNo) { +Socket::Connection::Connection(int sockNo){ sock = sockNo; pipes[0] = -1; pipes[1] = -1; @@ -178,12 +192,12 @@ Socket::Connection::Connection(int sockNo) { conntime = Util::epoch(); Error = false; Blocking = false; -} //Socket::Connection basic constructor +}// Socket::Connection basic constructor /// Simulate a socket using two file descriptors. /// \param write The filedescriptor to write to. /// \param read The filedescriptor to read from. -Socket::Connection::Connection(int write, int read) { +Socket::Connection::Connection(int write, int read){ sock = -1; pipes[0] = write; pipes[1] = read; @@ -192,11 +206,11 @@ Socket::Connection::Connection(int write, int read) { conntime = Util::epoch(); Error = false; Blocking = false; -} //Socket::Connection basic constructor +}// Socket::Connection basic constructor /// Create a new disconnected base socket. This is a basic constructor for placeholder purposes. /// A socket created like this is always disconnected and should/could be overwritten at some point. -Socket::Connection::Connection() { +Socket::Connection::Connection(){ sock = -1; pipes[0] = -1; pipes[1] = -1; @@ -205,49 +219,42 @@ Socket::Connection::Connection() { conntime = Util::epoch(); Error = false; Blocking = false; -} //Socket::Connection basic constructor +}// Socket::Connection basic constructor + +void Socket::Connection::resetCounter(){ + up = 0; + down = 0; +} /// Internally used call to make an file descriptor blocking or not. -void setFDBlocking(int FD, bool blocking) { +void setFDBlocking(int FD, bool blocking){ int flags = fcntl(FD, F_GETFL, 0); - if (!blocking) { + if (!blocking){ flags |= O_NONBLOCK; - } else { + }else{ flags &= !O_NONBLOCK; } fcntl(FD, F_SETFL, flags); } /// Internally used call to make an file descriptor blocking or not. -bool isFDBlocking(int FD) { +bool isFDBlocking(int FD){ int flags = fcntl(FD, F_GETFL, 0); return !(flags & O_NONBLOCK); } /// Set this socket to be blocking (true) or nonblocking (false). -void Socket::Connection::setBlocking(bool blocking) { - if (sock >= 0) { - setFDBlocking(sock, blocking); - } - if (pipes[0] >= 0) { - setFDBlocking(pipes[0], blocking); - } - if (pipes[1] >= 0) { - setFDBlocking(pipes[1], blocking); - } +void Socket::Connection::setBlocking(bool blocking){ + if (sock >= 0){setFDBlocking(sock, blocking);} + if (pipes[0] >= 0){setFDBlocking(pipes[0], blocking);} + if (pipes[1] >= 0){setFDBlocking(pipes[1], blocking);} } /// Set this socket to be blocking (true) or nonblocking (false). -bool Socket::Connection::isBlocking() { - if (sock >= 0) { - return isFDBlocking(sock); - } - if (pipes[0] >= 0) { - return isFDBlocking(pipes[0]); - } - if (pipes[1] >= 0) { - return isFDBlocking(pipes[1]); - } +bool Socket::Connection::isBlocking(){ + if (sock >= 0){return isFDBlocking(sock);} + if (pipes[0] >= 0){return isFDBlocking(pipes[0]);} + if (pipes[1] >= 0){return isFDBlocking(pipes[1]);} return false; } @@ -255,74 +262,63 @@ bool Socket::Connection::isBlocking() { /// If the connection is already closed, nothing happens. /// This function calls shutdown, thus making the socket unusable in all other /// processes as well. Do not use on shared sockets that are still in use. -void Socket::Connection::close() { - if (sock != -1) { - shutdown(sock, SHUT_RDWR); - } +void Socket::Connection::close(){ + if (sock != -1){shutdown(sock, SHUT_RDWR);} drop(); -} //Socket::Connection::close +}// Socket::Connection::close /// Close connection. The internal socket is closed and then set to -1. /// If the connection is already closed, nothing happens. /// This function does *not* call shutdown, allowing continued use in other /// processes. -void Socket::Connection::drop() { - if (connected()) { - if (sock != -1) { +void Socket::Connection::drop(){ + if (connected()){ + if (sock != -1){ DEBUG_MSG(DLVL_HIGH, "Socket %d closed", sock); errno = EINTR; - while (::close(sock) != 0 && errno == EINTR) { - } + while (::close(sock) != 0 && errno == EINTR){} sock = -1; } - if (pipes[0] != -1) { + if (pipes[0] != -1){ errno = EINTR; - while (::close(pipes[0]) != 0 && errno == EINTR) { - } + while (::close(pipes[0]) != 0 && errno == EINTR){} pipes[0] = -1; } - if (pipes[1] != -1) { + if (pipes[1] != -1){ errno = EINTR; - while (::close(pipes[1]) != 0 && errno == EINTR) { - } + while (::close(pipes[1]) != 0 && errno == EINTR){} pipes[1] = -1; } } -} //Socket::Connection::drop +}// Socket::Connection::drop /// Returns internal socket number. -int Socket::Connection::getSocket() { - if (sock != -1) { - return sock; - } - if (pipes[0] != -1) { - return pipes[0]; - } - if (pipes[1] != -1) { - return pipes[1]; - } +int Socket::Connection::getSocket(){ + if (sock != -1){return sock;} + if (pipes[0] != -1){return pipes[0];} + if (pipes[1] != -1){return pipes[1];} return -1; } /// Returns non-piped internal socket number. -int Socket::Connection::getPureSocket() { +int Socket::Connection::getPureSocket(){ return sock; } /// Returns a string describing the last error that occured. /// Only reports errors if an error actually occured - returns the host address or empty string otherwise. -std::string Socket::Connection::getError() { +std::string Socket::Connection::getError(){ return remotehost; } /// Create a new Unix Socket. This socket will (try to) connect to the given address right away. /// \param address String containing the location of the Unix socket to connect to. /// \param nonblock Whether the socket should be nonblocking. False by default. -Socket::Connection::Connection(std::string address, bool nonblock) { +Socket::Connection::Connection(std::string address, bool nonblock){ pipes[0] = -1; pipes[1] = -1; sock = socket(PF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { + if (sock < 0){ remotehost = strerror(errno); DEBUG_MSG(DLVL_FAIL, "Could not create socket! Error: %s", remotehost.c_str()); return; @@ -335,28 +331,28 @@ Socket::Connection::Connection(std::string address, bool nonblock) { sockaddr_un addr; addr.sun_family = AF_UNIX; strncpy(addr.sun_path, address.c_str(), address.size() + 1); - int r = connect(sock, (sockaddr *) &addr, sizeof(addr)); - if (r == 0) { - if (nonblock) { + int r = connect(sock, (sockaddr *)&addr, sizeof(addr)); + if (r == 0){ + if (nonblock){ int flags = fcntl(sock, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(sock, F_SETFL, flags); } - } else { + }else{ remotehost = strerror(errno); DEBUG_MSG(DLVL_FAIL, "Could not connect to %s! Error: %s", address.c_str(), remotehost.c_str()); close(); } -} //Socket::Connection Unix Contructor +}// Socket::Connection Unix Contructor /// Create a new TCP Socket. This socket will (try to) connect to the given host/port right away. /// \param host String containing the hostname to connect to. /// \param port String containing the port to connect to. /// \param nonblock Whether the socket should be nonblocking. -Socket::Connection::Connection(std::string host, int port, bool nonblock) { +Socket::Connection::Connection(std::string host, int port, bool nonblock){ pipes[0] = -1; pipes[1] = -1; - struct addrinfo * result, *rp, hints; + struct addrinfo *result, *rp, hints; Error = false; Blocking = false; up = 0; @@ -370,116 +366,106 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock) { hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; int s = getaddrinfo(host.c_str(), ss.str().c_str(), &hints, &result); - if (s != 0) { + if (s != 0){ DEBUG_MSG(DLVL_FAIL, "Could not connect to %s:%i! Error: %s", host.c_str(), port, gai_strerror(s)); close(); return; } remotehost = ""; - for (rp = result; rp != NULL; rp = rp->ai_next) { + for (rp = result; rp != NULL; rp = rp->ai_next){ sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (sock < 0) { - continue; - } - if (connect(sock, rp->ai_addr, rp->ai_addrlen) == 0) { - break; - } + if (sock < 0){continue;} + if (connect(sock, rp->ai_addr, rp->ai_addrlen) == 0){break;} remotehost += strerror(errno); ::close(sock); } freeaddrinfo(result); - if (rp == 0) { + if (rp == 0){ DEBUG_MSG(DLVL_FAIL, "Could not connect to %s! Error: %s", host.c_str(), remotehost.c_str()); close(); - } else { - if (nonblock) { + }else{ + if (nonblock){ int flags = fcntl(sock, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(sock, F_SETFL, flags); } } -} //Socket::Connection TCP Contructor +}// Socket::Connection TCP Contructor /// Returns the connected-state for this socket. /// Note that this function might be slightly behind the real situation. /// The connection status is updated after every read/write attempt, when errors occur /// and when the socket is closed manually. /// \returns True if socket is connected, false otherwise. -bool Socket::Connection::connected() const { +bool Socket::Connection::connected() const{ return (sock >= 0) || ((pipes[0] >= 0) && (pipes[1] >= 0)); } /// Returns the time this socket has been connected. -unsigned int Socket::Connection::connTime() { +unsigned int Socket::Connection::connTime(){ return conntime; } /// Returns total amount of bytes sent. -uint64_t Socket::Connection::dataUp() { +uint64_t Socket::Connection::dataUp(){ return up; } /// Returns total amount of bytes received. -uint64_t Socket::Connection::dataDown() { +uint64_t Socket::Connection::dataDown(){ return down; } /// Returns a std::string of stats, ended by a newline. /// Requires the current connector name as an argument. -std::string Socket::Connection::getStats(std::string C) { +std::string Socket::Connection::getStats(std::string C){ return "S " + getHost() + " " + C + " " + uint2string(Util::epoch() - conntime) + " " + uint2string(up) + " " + uint2string(down) + "\n"; } /// Updates the downbuffer internal variable. /// Returns true if new data was received, false otherwise. -bool Socket::Connection::spool() { +bool Socket::Connection::spool(){ /// \todo Provide better mechanism to prevent overbuffering. - if (downbuffer.size() > 10000) { + if (downbuffer.size() > 10000){ return true; - } else { + }else{ return iread(downbuffer); } } -bool Socket::Connection::peek() { +bool Socket::Connection::peek(){ /// clear buffer downbuffer.clear(); return iread(downbuffer, MSG_PEEK); } /// Returns a reference to the download buffer. -Socket::Buffer & Socket::Connection::Received() { +Socket::Buffer &Socket::Connection::Received(){ return downbuffer; } /// Will not buffer anything but always send right away. Blocks. /// Any data that could not be send will block until it can be send or the connection is severed. -void Socket::Connection::SendNow(const char * data, size_t len) { +void Socket::Connection::SendNow(const char *data, size_t len){ bool bing = isBlocking(); - if (!bing) { - setBlocking(true); - } + if (!bing){setBlocking(true);} unsigned int i = iwrite(data, std::min((long unsigned int)len, SOCKETSIZE)); - while (i < len && connected()) { - i += iwrite(data + i, std::min((long unsigned int)(len - i), SOCKETSIZE)); - } - if (!bing) { - setBlocking(false); - } + while (i < len && connected()){i += iwrite(data + i, std::min((long unsigned int)(len - i), SOCKETSIZE));} + if (!bing){setBlocking(false);} } /// Will not buffer anything but always send right away. Blocks. /// Any data that could not be send will block until it can be send or the connection is severed. -void Socket::Connection::SendNow(const char * data) { +void Socket::Connection::SendNow(const char *data){ int len = strlen(data); SendNow(data, len); } /// Will not buffer anything but always send right away. Blocks. /// Any data that could not be send will block until it can be send or the connection is severed. -void Socket::Connection::SendNow(const std::string & data) { +void Socket::Connection::SendNow(const std::string &data){ SendNow(data.data(), data.size()); } @@ -488,36 +474,32 @@ void Socket::Connection::SendNow(const std::string & data) { /// \param buffer Location of the buffer to write from. /// \param len Amount of bytes to write. /// \returns The amount of bytes actually written. -unsigned int Socket::Connection::iwrite(const void * buffer, int len) { - if (!connected() || len < 1) { - return 0; - } +unsigned int Socket::Connection::iwrite(const void *buffer, int len){ + if (!connected() || len < 1){return 0;} int r; - if (sock >= 0) { + if (sock >= 0){ r = send(sock, buffer, len, 0); - } else { + }else{ r = write(pipes[0], buffer, len); } - if (r < 0) { - switch (errno) { - case EWOULDBLOCK: - return 0; - break; - default: - Error = true; - INSANE_MSG("Could not iwrite data! Error: %s", strerror(errno)); - close(); - return 0; - break; + if (r < 0){ + switch (errno){ + case EWOULDBLOCK: return 0; break; + default: + Error = true; + INSANE_MSG("Could not iwrite data! Error: %s", strerror(errno)); + close(); + return 0; + break; } } - if (r == 0 && (sock >= 0)) { + if (r == 0 && (sock >= 0)){ DONTEVEN_MSG("Socket closed by remote"); close(); } up += r; return r; -} //Socket::Connection::iwrite +}// Socket::Connection::iwrite /// Incremental read call. This function tries to read len bytes to the buffer from the socket, /// returning the amount of bytes it actually read. @@ -525,42 +507,34 @@ unsigned int Socket::Connection::iwrite(const void * buffer, int len) { /// \param len Amount of bytes to read. /// \param flags Flags to use in the recv call. Ignored on fake sockets. /// \returns The amount of bytes actually read. -int Socket::Connection::iread(void * buffer, int len, int flags) { - if (!connected() || len < 1) { - return 0; - } +int Socket::Connection::iread(void *buffer, int len, int flags){ + if (!connected() || len < 1){return 0;} int r; - if (sock >= 0) { + if (sock >= 0){ r = recv(sock, buffer, len, flags); - } else { + }else{ r = recv(pipes[1], buffer, len, flags); - if (r < 0 && errno == ENOTSOCK) { - r = read(pipes[1], buffer, len); + if (r < 0 && errno == ENOTSOCK){r = read(pipes[1], buffer, len);} + } + if (r < 0){ + switch (errno){ + case EWOULDBLOCK: return 0; break; + case EINTR: return 0; break; + default: + Error = true; + INSANE_MSG("Could not iread data! Error: %s", strerror(errno)); + close(); + return 0; + break; } } - if (r < 0) { - switch (errno) { - case EWOULDBLOCK: - return 0; - break; - case EINTR: - return 0; - break; - default: - Error = true; - INSANE_MSG("Could not iread data! Error: %s", strerror(errno)); - close(); - return 0; - break; - } - } - if (r == 0) { + if (r == 0){ DONTEVEN_MSG("Socket closed by remote"); close(); } down += r; return r; -} //Socket::Connection::iread +}// Socket::Connection::iread /// Read call that is compatible with Socket::Buffer. /// Data is read using iread (which is nonblocking if the Socket::Connection itself is), @@ -568,43 +542,37 @@ int Socket::Connection::iread(void * buffer, int len, int flags) { /// \param buffer Socket::Buffer to append data to. /// \param flags Flags to use in the recv call. Ignored on fake sockets. /// \return True if new data arrived, false otherwise. -bool Socket::Connection::iread(Buffer & buffer, int flags) { +bool Socket::Connection::iread(Buffer &buffer, int flags){ char cbuffer[BUFFER_BLOCKSIZE]; int num = iread(cbuffer, BUFFER_BLOCKSIZE, flags); - if (num < 1) { - return false; - } + if (num < 1){return false;} buffer.append(cbuffer, num); return true; -} //iread +}// iread /// Incremental write call that is compatible with std::string. /// Data is written using iwrite (which is nonblocking if the Socket::Connection itself is), /// then removed from front of buffer. /// \param buffer std::string to remove data from. /// \return True if more data was sent, false otherwise. -bool Socket::Connection::iwrite(std::string & buffer) { - if (buffer.size() < 1) { - return false; - } +bool Socket::Connection::iwrite(std::string &buffer){ + if (buffer.size() < 1){return false;} unsigned int tmp = iwrite((void *)buffer.c_str(), buffer.size()); - if (!tmp) { - return false; - } + if (!tmp){return false;} buffer = buffer.substr(tmp); return true; -} //iwrite +}// iwrite /// Gets hostname for connection, if available. -std::string Socket::Connection::getHost() const { +std::string Socket::Connection::getHost() const{ return remotehost; } /// Gets hostname for connection, if available. /// Guaranteed to be either empty or 16 bytes long. -std::string Socket::Connection::getBinHost() { - if (remotehost.size()) { - struct addrinfo * result, *rp, hints; +std::string Socket::Connection::getBinHost(){ + if (remotehost.size()){ + struct addrinfo *result, *rp, hints; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; @@ -614,54 +582,50 @@ std::string Socket::Connection::getBinHost() { hints.ai_addr = NULL; hints.ai_next = NULL; int s = getaddrinfo(remotehost.c_str(), 0, &hints, &result); - if (s != 0) { + if (s != 0){ DEBUG_MSG(DLVL_FAIL, "Could not resolve '%s'! Error: %s", remotehost.c_str(), gai_strerror(s)); return ""; } char tmpBuffer[17] = "\000\000\000\000\000\000\000\000\000\000\377\377\000\000\000\000"; - for (rp = result; rp != NULL; rp = rp->ai_next) { - if (rp->ai_family == AF_INET) { - memcpy(tmpBuffer + 12, &((sockaddr_in *)rp->ai_addr)->sin_addr.s_addr, 4); - } - if (rp->ai_family == AF_INET6) { - memcpy(tmpBuffer, ((sockaddr_in6 *)rp->ai_addr)->sin6_addr.s6_addr, 16); - } + for (rp = result; rp != NULL; rp = rp->ai_next){ + if (rp->ai_family == AF_INET){memcpy(tmpBuffer + 12, &((sockaddr_in *)rp->ai_addr)->sin_addr.s_addr, 4);} + if (rp->ai_family == AF_INET6){memcpy(tmpBuffer, ((sockaddr_in6 *)rp->ai_addr)->sin6_addr.s6_addr, 16);} } freeaddrinfo(result); return std::string(tmpBuffer, 16); - } else { + }else{ return ""; } } /// Sets hostname for connection manually. /// Overwrites the detected host, thus possibily making it incorrect. -void Socket::Connection::setHost(std::string host) { +void Socket::Connection::setHost(std::string host){ remotehost = host; } /// Returns true if these sockets are the same socket. /// Does not check the internal stats - only the socket itself. -bool Socket::Connection::operator==(const Connection & B) const { +bool Socket::Connection::operator==(const Connection &B) const{ return sock == B.sock && pipes[0] == B.pipes[0] && pipes[1] == B.pipes[1]; } /// Returns true if these sockets are not the same socket. /// Does not check the internal stats - only the socket itself. -bool Socket::Connection::operator!=(const Connection & B) const { +bool Socket::Connection::operator!=(const Connection &B) const{ return sock != B.sock || pipes[0] != B.pipes[0] || pipes[1] != B.pipes[1]; } /// Returns true if the socket is valid. /// Aliases for Socket::Connection::connected() -Socket::Connection::operator bool() const { +Socket::Connection::operator bool() const{ return connected(); } /// Returns true if the given address can be matched with the remote host. /// Can no longer return true after any socket error have occurred. -bool Socket::Connection::isAddress(std::string addr) { - struct addrinfo * result, *rp, hints; +bool Socket::Connection::isAddress(std::string addr){ + struct addrinfo *result, *rp, hints; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; @@ -671,28 +635,20 @@ bool Socket::Connection::isAddress(std::string addr) { hints.ai_addr = NULL; hints.ai_next = NULL; int s = getaddrinfo(addr.c_str(), 0, &hints, &result); - if (s != 0) { - return false; - } + if (s != 0){return false;} char newaddr[INET_ADDRSTRLEN]; newaddr[0] = 0; - for (rp = result; rp != NULL; rp = rp->ai_next) { - if (rp->ai_family == AF_INET && inet_ntop(rp->ai_family, &(((sockaddr_in *)rp->ai_addr)->sin_addr), newaddr, INET_ADDRSTRLEN)) { + for (rp = result; rp != NULL; rp = rp->ai_next){ + if (rp->ai_family == AF_INET && inet_ntop(rp->ai_family, &(((sockaddr_in *)rp->ai_addr)->sin_addr), newaddr, INET_ADDRSTRLEN)){ DEBUG_MSG(DLVL_DEVEL, "Comparing: '%s' to '%s'", remotehost.c_str(), newaddr); - if (remotehost == newaddr) { - return true; - } + if (remotehost == newaddr){return true;} DEBUG_MSG(DLVL_DEVEL, "Comparing: '%s' to '::ffff:%s'", remotehost.c_str(), newaddr); - if (remotehost == std::string("::ffff:") + newaddr) { - return true; - } + if (remotehost == std::string("::ffff:") + newaddr){return true;} } - if (rp->ai_family == AF_INET6 && inet_ntop(rp->ai_family, &(((sockaddr_in6 *)rp->ai_addr)->sin6_addr), newaddr, INET_ADDRSTRLEN)) { + if (rp->ai_family == AF_INET6 && inet_ntop(rp->ai_family, &(((sockaddr_in6 *)rp->ai_addr)->sin6_addr), newaddr, INET_ADDRSTRLEN)){ DEBUG_MSG(DLVL_DEVEL, "Comparing: '%s' to '%s'", remotehost.c_str(), newaddr); - if (remotehost == newaddr) { - return true; - } + if (remotehost == newaddr){return true;} } } freeaddrinfo(result); @@ -700,9 +656,9 @@ bool Socket::Connection::isAddress(std::string addr) { } /// Create a new base Server. The socket is never connected, and a placeholder for later connections. -Socket::Server::Server() { +Socket::Server::Server(){ sock = -1; -} //Socket::Server base Constructor +}// Socket::Server base Constructor /// Create a new TCP Server. The socket is immediately bound and set to listen. /// A maximum of 100 connections will be accepted between accept() calls. @@ -710,21 +666,21 @@ Socket::Server::Server() { /// \param port The TCP port to listen on /// \param hostname (optional) The interface to bind to. The default is 0.0.0.0 (all interfaces). /// \param nonblock (optional) Whether accept() calls will be nonblocking. Default is false (blocking). -Socket::Server::Server(int port, std::string hostname, bool nonblock) { - if (!IPv6bind(port, hostname, nonblock) && !IPv4bind(port, hostname, nonblock)) { +Socket::Server::Server(int port, std::string hostname, bool nonblock){ + if (!IPv6bind(port, hostname, nonblock) && !IPv4bind(port, hostname, nonblock)){ DEBUG_MSG(DLVL_FAIL, "Could not create socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str()); sock = -1; } -} //Socket::Server TCP Constructor +}// Socket::Server TCP Constructor /// Attempt to bind an IPv6 socket. /// \param port The TCP port to listen on /// \param hostname The interface to bind to. The default is 0.0.0.0 (all interfaces). /// \param nonblock Whether accept() calls will be nonblocking. Default is false (blocking). /// \return True if successful, false otherwise. -bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock) { +bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock){ sock = socket(AF_INET6, SOCK_STREAM, 0); - if (sock < 0) { + if (sock < 0){ errors = strerror(errno); DEBUG_MSG(DLVL_ERROR, "Could not create IPv6 socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str()); return false; @@ -735,7 +691,7 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock) { on = 0; setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); #endif - if (nonblock) { + if (nonblock){ int flags = fcntl(sock, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(sock, F_SETFL, flags); @@ -743,25 +699,25 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock) { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; - addr.sin6_port = htons(port); //set port - if (hostname == "0.0.0.0" || hostname.length() == 0) { + addr.sin6_port = htons(port); // set port + if (hostname == "0.0.0.0" || hostname.length() == 0){ addr.sin6_addr = in6addr_any; - } else { - inet_pton(AF_INET6, hostname.c_str(), &addr.sin6_addr); //set interface, 0.0.0.0 (default) is all + }else{ + inet_pton(AF_INET6, hostname.c_str(), &addr.sin6_addr); // set interface, 0.0.0.0 (default) is all } - int ret = bind(sock, (sockaddr *) &addr, sizeof(addr)); //do the actual bind - if (ret == 0) { - ret = listen(sock, 100); //start listening, backlog of 100 allowed - if (ret == 0) { + int ret = bind(sock, (sockaddr *)&addr, sizeof(addr)); // do the actual bind + if (ret == 0){ + ret = listen(sock, 100); // start listening, backlog of 100 allowed + if (ret == 0){ DEBUG_MSG(DLVL_DEVEL, "IPv6 socket success @ %s:%i", hostname.c_str(), port); return true; - } else { + }else{ errors = strerror(errno); DEBUG_MSG(DLVL_ERROR, "IPv6 listen failed! Error: %s", errors.c_str()); close(); return false; } - } else { + }else{ errors = strerror(errno); DEBUG_MSG(DLVL_ERROR, "IPv6 Binding %s:%i failed (%s)", hostname.c_str(), port, errors.c_str()); close(); @@ -774,16 +730,16 @@ bool Socket::Server::IPv6bind(int port, std::string hostname, bool nonblock) { /// \param hostname The interface to bind to. The default is 0.0.0.0 (all interfaces). /// \param nonblock Whether accept() calls will be nonblocking. Default is false (blocking). /// \return True if successful, false otherwise. -bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock) { +bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock){ sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { + if (sock < 0){ errors = strerror(errno); DEBUG_MSG(DLVL_ERROR, "Could not create IPv4 socket %s:%i! Error: %s", hostname.c_str(), port, errors.c_str()); return false; } int on = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - if (nonblock) { + if (nonblock){ int flags = fcntl(sock, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(sock, F_SETFL, flags); @@ -791,25 +747,25 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock) { struct sockaddr_in addr4; memset(&addr4, 0, sizeof(addr4)); addr4.sin_family = AF_INET; - addr4.sin_port = htons(port); //set port - if (hostname == "0.0.0.0" || hostname.length() == 0) { + addr4.sin_port = htons(port); // set port + if (hostname == "0.0.0.0" || hostname.length() == 0){ addr4.sin_addr.s_addr = INADDR_ANY; - } else { - inet_pton(AF_INET, hostname.c_str(), &addr4.sin_addr); //set interface, 0.0.0.0 (default) is all + }else{ + inet_pton(AF_INET, hostname.c_str(), &addr4.sin_addr); // set interface, 0.0.0.0 (default) is all } - int ret = bind(sock, (sockaddr *) &addr4, sizeof(addr4)); //do the actual bind - if (ret == 0) { - ret = listen(sock, 100); //start listening, backlog of 100 allowed - if (ret == 0) { + int ret = bind(sock, (sockaddr *)&addr4, sizeof(addr4)); // do the actual bind + if (ret == 0){ + ret = listen(sock, 100); // start listening, backlog of 100 allowed + if (ret == 0){ DEBUG_MSG(DLVL_DEVEL, "IPv4 socket success @ %s:%i", hostname.c_str(), port); return true; - } else { + }else{ errors = strerror(errno); DEBUG_MSG(DLVL_ERROR, "IPv4 listen failed! Error: %s", errors.c_str()); close(); return false; } - } else { + }else{ errors = strerror(errno); DEBUG_MSG(DLVL_ERROR, "IPv4 Binding %s:%i failed (%s)", hostname.c_str(), port, errors.c_str()); close(); @@ -820,18 +776,19 @@ bool Socket::Server::IPv4bind(int port, std::string hostname, bool nonblock) { /// Create a new Unix Server. The socket is immediately bound and set to listen. /// A maximum of 100 connections will be accepted between accept() calls. /// Any further connections coming in will be dropped. -/// The address used will first be unlinked - so it succeeds if the Unix socket already existed. Watch out for this behaviour - it will delete any file located at address! +/// The address used will first be unlinked - so it succeeds if the Unix socket already existed. Watch out for this behaviour - it will delete +/// any file located at address! /// \param address The location of the Unix socket to bind to. /// \param nonblock (optional) Whether accept() calls will be nonblocking. Default is false (blocking). -Socket::Server::Server(std::string address, bool nonblock) { +Socket::Server::Server(std::string address, bool nonblock){ unlink(address.c_str()); sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { + if (sock < 0){ errors = strerror(errno); DEBUG_MSG(DLVL_ERROR, "Could not create unix socket %s! Error: %s", address.c_str(), errors.c_str()); return; } - if (nonblock) { + if (nonblock){ int flags = fcntl(sock, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(sock, F_SETFL, flags); @@ -839,60 +796,58 @@ Socket::Server::Server(std::string address, bool nonblock) { sockaddr_un addr; addr.sun_family = AF_UNIX; strncpy(addr.sun_path, address.c_str(), address.size() + 1); - int ret = bind(sock, (sockaddr *) &addr, sizeof(addr)); - if (ret == 0) { - ret = listen(sock, 100); //start listening, backlog of 100 allowed - if (ret == 0) { + int ret = bind(sock, (sockaddr *)&addr, sizeof(addr)); + if (ret == 0){ + ret = listen(sock, 100); // start listening, backlog of 100 allowed + if (ret == 0){ return; - } else { + }else{ errors = strerror(errno); DEBUG_MSG(DLVL_ERROR, "Unix listen failed! Error: %s", errors.c_str()); close(); return; } - } else { + }else{ errors = strerror(errno); DEBUG_MSG(DLVL_ERROR, "Unix Binding %s failed (%s)", address.c_str(), errors.c_str()); close(); return; } -} //Socket::Server Unix Constructor +}// Socket::Server Unix Constructor /// Accept any waiting connections. If the Socket::Server is blocking, this function will block until there is an incoming connection. /// If the Socket::Server is nonblocking, it might return a Socket::Connection that is not connected, so check for this. /// \param nonblock (optional) Whether the newly connected socket should be nonblocking. Default is false (blocking). /// \returns A Socket::Connection, which may or may not be connected, depending on settings and circumstances. -Socket::Connection Socket::Server::accept(bool nonblock) { - if (sock < 0) { - return Socket::Connection(-1); - } +Socket::Connection Socket::Server::accept(bool nonblock){ + if (sock < 0){return Socket::Connection(-1);} struct sockaddr_in6 addrinfo; socklen_t len = sizeof(addrinfo); static char addrconv[INET6_ADDRSTRLEN]; - int r = ::accept(sock, (sockaddr *) &addrinfo, &len); - //set the socket to be nonblocking, if requested. - //we could do this through accept4 with a flag, but that call is non-standard... - if ((r >= 0) && nonblock) { + int r = ::accept(sock, (sockaddr *)&addrinfo, &len); + // set the socket to be nonblocking, if requested. + // we could do this through accept4 with a flag, but that call is non-standard... + if ((r >= 0) && nonblock){ int flags = fcntl(r, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(r, F_SETFL, flags); } Socket::Connection tmp(r); - if (r < 0) { - if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EINTR)) { + if (r < 0){ + if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EINTR)){ DEBUG_MSG(DLVL_FAIL, "Error during accept - closing server socket %d.", sock); close(); } - } else { - if (addrinfo.sin6_family == AF_INET6) { + }else{ + if (addrinfo.sin6_family == AF_INET6){ tmp.remotehost = inet_ntop(AF_INET6, &(addrinfo.sin6_addr), addrconv, INET6_ADDRSTRLEN); DEBUG_MSG(DLVL_HIGH, "IPv6 addr [%s]", tmp.remotehost.c_str()); } - if (addrinfo.sin6_family == AF_INET) { - tmp.remotehost = inet_ntop(AF_INET, &(((sockaddr_in *) &addrinfo)->sin_addr), addrconv, INET6_ADDRSTRLEN); + if (addrinfo.sin6_family == AF_INET){ + tmp.remotehost = inet_ntop(AF_INET, &(((sockaddr_in *)&addrinfo)->sin_addr), addrconv, INET6_ADDRSTRLEN); DEBUG_MSG(DLVL_HIGH, "IPv4 addr [%s]", tmp.remotehost.c_str()); } - if (addrinfo.sin6_family == AF_UNIX) { + if (addrinfo.sin6_family == AF_UNIX){ DEBUG_MSG(DLVL_HIGH, "Unix connection"); tmp.remotehost = "UNIX_SOCKET"; } @@ -901,17 +856,13 @@ Socket::Connection Socket::Server::accept(bool nonblock) { } /// Set this socket to be blocking (true) or nonblocking (false). -void Socket::Server::setBlocking(bool blocking) { - if (sock >= 0) { - setFDBlocking(sock, blocking); - } +void Socket::Server::setBlocking(bool blocking){ + if (sock >= 0){setFDBlocking(sock, blocking);} } /// Set this socket to be blocking (true) or nonblocking (false). -bool Socket::Server::isBlocking() { - if (sock >= 0) { - return isFDBlocking(sock); - } +bool Socket::Server::isBlocking(){ + if (sock >= 0){return isFDBlocking(sock);} return false; } @@ -919,40 +870,37 @@ bool Socket::Server::isBlocking() { /// If the connection is already closed, nothing happens. /// This function calls shutdown, thus making the socket unusable in all other /// processes as well. Do not use on shared sockets that are still in use. -void Socket::Server::close() { - if (sock != -1) { - shutdown(sock, SHUT_RDWR); - } +void Socket::Server::close(){ + if (sock != -1){shutdown(sock, SHUT_RDWR);} drop(); -} //Socket::Server::close +}// Socket::Server::close /// Close connection. The internal socket is closed and then set to -1. /// If the connection is already closed, nothing happens. /// This function does *not* call shutdown, allowing continued use in other /// processes. -void Socket::Server::drop() { - if (connected()) { - if (sock != -1) { +void Socket::Server::drop(){ + if (connected()){ + if (sock != -1){ DEBUG_MSG(DLVL_HIGH, "ServerSocket %d closed", sock); errno = EINTR; - while (::close(sock) != 0 && errno == EINTR) { - } + while (::close(sock) != 0 && errno == EINTR){} sock = -1; } } -} //Socket::Server::drop +}// Socket::Server::drop /// Returns the connected-state for this socket. /// Note that this function might be slightly behind the real situation. /// The connection status is updated after every accept attempt, when errors occur /// and when the socket is closed manually. /// \returns True if socket is connected, false otherwise. -bool Socket::Server::connected() const { +bool Socket::Server::connected() const{ return (sock >= 0); -} //Socket::Server::connected +}// Socket::Server::connected /// Returns internal socket number. -int Socket::Server::getSocket() { +int Socket::Server::getSocket(){ return sock; } @@ -960,16 +908,14 @@ int Socket::Server::getSocket() { /// 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){ family = AF_INET6; sock = socket(AF_INET6, SOCK_DGRAM, 0); - if (sock == -1) { + if (sock == -1){ sock = socket(AF_INET, SOCK_DGRAM, 0); family = AF_INET; } - if (sock == -1) { - DEBUG_MSG(DLVL_FAIL, "Could not create UDP socket: %s", strerror(errno)); - } + if (sock == -1){DEBUG_MSG(DLVL_FAIL, "Could not create UDP socket: %s", strerror(errno));} up = 0; down = 0; destAddr = 0; @@ -977,35 +923,29 @@ Socket::UDPConnection::UDPConnection(bool nonblock) { data = 0; data_size = 0; data_len = 0; - if (nonblock) { - setBlocking(!nonblock); - } -} //Socket::UDPConnection UDP Contructor + if (nonblock){setBlocking(!nonblock);} +}// 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){ family = AF_INET6; sock = socket(AF_INET6, SOCK_DGRAM, 0); - if (sock == -1) { + if (sock == -1){ sock = socket(AF_INET, SOCK_DGRAM, 0); family = AF_INET; } - if (sock == -1) { - DEBUG_MSG(DLVL_FAIL, "Could not create UDP socket: %s", strerror(errno)); - } + if (sock == -1){DEBUG_MSG(DLVL_FAIL, "Could not create UDP socket: %s", strerror(errno));} up = 0; down = 0; - if (o.destAddr && o.destAddr_size) { + if (o.destAddr && o.destAddr_size){ destAddr = malloc(o.destAddr_size); - if (destAddr) { - memcpy(destAddr, o.destAddr, o.destAddr_size); - } - } else { + if (destAddr){memcpy(destAddr, o.destAddr, o.destAddr_size);} + }else{ destAddr = 0; destAddr_size = 0; } - data = (char*)malloc(1024); + data = (char *)malloc(1024); if (data){ data_size = 1024; }else{ @@ -1016,22 +956,21 @@ Socket::UDPConnection::UDPConnection(const UDPConnection & o) { /// Close the UDP socket void Socket::UDPConnection::close(){ - if (sock != -1) { + if (sock != -1){ errno = EINTR; - while (::close(sock) != 0 && errno == EINTR) { - } + while (::close(sock) != 0 && errno == EINTR){} sock = -1; } } /// Closes the UDP socket, cleans up any memory allocated by the socket. -Socket::UDPConnection::~UDPConnection() { +Socket::UDPConnection::~UDPConnection(){ close(); - if (destAddr) { + if (destAddr){ free(destAddr); destAddr = 0; } - if (data) { + if (data){ free(data); data = 0; } @@ -1039,39 +978,43 @@ Socket::UDPConnection::~UDPConnection() { /// Stores the properties of the receiving 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) { - if (destAddr) { - free(destAddr); - destAddr = 0; +void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){ + //UDP sockets can switch between IPv4 and IPv6 on demand. + //We change IPv4-mapped IPv6 addresses into IPv4 addresses for Windows-sillyness reasons. + if (destIp.substr(0, 7) == "::ffff:"){ + destIp = destIp.substr(7); } - destAddr = malloc(sizeof(struct sockaddr_in6)); - if (!destAddr) { - return; - } - destAddr_size = sizeof(struct sockaddr_in6); - memset(destAddr, 0, destAddr_size); - - struct addrinfo * result, *rp, hints; + struct addrinfo *result, *rp, hints; std::stringstream ss; ss << port; memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = family; + hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_ADDRCONFIG; - hints.ai_protocol = 0; + hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED; + hints.ai_protocol = IPPROTO_UDP; hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; int s = getaddrinfo(destIp.c_str(), ss.str().c_str(), &hints, &result); - if (s != 0) { + if (s != 0){ DEBUG_MSG(DLVL_FAIL, "Could not connect UDP socket to %s:%i! Error: %s", destIp.c_str(), port, gai_strerror(s)); return; } - for (rp = result; rp != NULL; rp = rp->ai_next) { - //assume success + for (rp = result; rp != NULL; rp = rp->ai_next){ + // assume success + if (destAddr){ + free(destAddr); + destAddr = 0; + } + destAddr_size = rp->ai_addrlen; + destAddr = malloc(destAddr_size); + if (!destAddr){return;} memcpy(destAddr, rp->ai_addr, rp->ai_addrlen); + close(); + family = rp->ai_family; + sock = socket(family, SOCK_DGRAM, 0); freeaddrinfo(result); return; //\todo Possibly detect and handle failure @@ -1080,27 +1023,27 @@ void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port) { free(destAddr); destAddr = 0; DEBUG_MSG(DLVL_FAIL, "Could not set destination for UDP socket: %s:%d", destIp.c_str(), port); -}//Socket::UDPConnection SetDestination +}// Socket::UDPConnection SetDestination /// Gets the properties of the receiving end of this UDP socket. /// This will be the receiving end for all SendNow calls. -void Socket::UDPConnection::GetDestination(std::string & destIp, uint32_t & port) { - if (!destAddr || !destAddr_size) { +void Socket::UDPConnection::GetDestination(std::string &destIp, uint32_t &port){ + if (!destAddr || !destAddr_size){ destIp = ""; port = 0; return; } char addr_str[INET6_ADDRSTRLEN + 1]; - addr_str[INET6_ADDRSTRLEN] = 0;//set last byte to zero, to prevent walking out of the array - if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET6) { - if (inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)destAddr)->sin6_addr), addr_str, INET6_ADDRSTRLEN) != 0) { + addr_str[INET6_ADDRSTRLEN] = 0; // set last byte to zero, to prevent walking out of the array + if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET6){ + if (inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)destAddr)->sin6_addr), addr_str, INET6_ADDRSTRLEN) != 0){ destIp = addr_str; port = ntohs(((struct sockaddr_in6 *)destAddr)->sin6_port); return; } } - if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET) { - if (inet_ntop(AF_INET, &(((struct sockaddr_in *)destAddr)->sin_addr), addr_str, INET6_ADDRSTRLEN) != 0) { + if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET){ + if (inet_ntop(AF_INET, &(((struct sockaddr_in *)destAddr)->sin_addr), addr_str, INET6_ADDRSTRLEN) != 0){ destIp = addr_str; port = ntohs(((struct sockaddr_in *)destAddr)->sin_port); return; @@ -1109,39 +1052,33 @@ void Socket::UDPConnection::GetDestination(std::string & destIp, uint32_t & port destIp = ""; port = 0; DEBUG_MSG(DLVL_FAIL, "Could not get destination for UDP socket"); -}//Socket::UDPConnection GetDestination +}// Socket::UDPConnection GetDestination /// Returns the port number of the receiving end of this socket. /// Returns 0 on error. uint32_t Socket::UDPConnection::getDestPort() const{ if (!destAddr || !destAddr_size){return 0;} - if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET6) { - return ntohs(((struct sockaddr_in6 *)destAddr)->sin6_port); - } - if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET) { - return ntohs(((struct sockaddr_in *)destAddr)->sin_port); - } + if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET6){return ntohs(((struct sockaddr_in6 *)destAddr)->sin6_port);} + if (((struct sockaddr_in *)destAddr)->sin_family == AF_INET){return ntohs(((struct sockaddr_in *)destAddr)->sin_port);} return 0; } /// 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) { - if (sock >= 0) { - setFDBlocking(sock, blocking); - } +void Socket::UDPConnection::setBlocking(bool blocking){ + if (sock >= 0){setFDBlocking(sock, blocking);} } /// Sends a UDP datagram using the buffer sdata. /// This function simply calls SendNow(const char*, size_t) -void Socket::UDPConnection::SendNow(const std::string & sdata) { +void Socket::UDPConnection::SendNow(const std::string &sdata){ SendNow(sdata.c_str(), sdata.size()); } /// Sends a UDP datagram using the buffer sdata. /// sdata is required to be NULL-terminated. /// This function simply calls SendNow(const char*, size_t) -void Socket::UDPConnection::SendNow(const char * sdata) { +void Socket::UDPConnection::SendNow(const char *sdata){ int len = strlen(sdata); SendNow(sdata, len); } @@ -1149,14 +1086,12 @@ void Socket::UDPConnection::SendNow(const char * sdata) { /// 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; - } +void Socket::UDPConnection::SendNow(const char *sdata, size_t len){ + if (len < 1){return;} int r = sendto(sock, sdata, len, 0, (sockaddr *)destAddr, destAddr_size); - if (r > 0) { + if (r > 0){ up += r; - } else { + }else{ DEBUG_MSG(DLVL_FAIL, "Could not send UDP data through %d: %s", sock, strerror(errno)); } } @@ -1165,24 +1100,25 @@ void Socket::UDPConnection::SendNow(const char * sdata, size_t len) { /// If that fails, returns zero. /// \arg port Port to bind to, required. /// \arg iface Interface address to listen for packets on (may be multicast address) -/// \arg multicastInterfaces Comma-separated list of interfaces to listen on for multicast packets. Optional, left out means automatically chosen by kernel. +/// \arg multicastInterfaces Comma-separated list of interfaces to listen on for multicast packets. Optional, left out means automatically chosen +/// by kernel. /// \return Actually bound port number, or zero on error. -int Socket::UDPConnection::bind(int port, std::string iface, const std::string & multicastInterfaces) { - close();//we open a new socket for each attempt +int Socket::UDPConnection::bind(int port, std::string iface, const std::string &multicastInterfaces){ + close(); // we open a new socket for each attempt int result = 0; int addr_ret; bool multicast = false; struct addrinfo hints, *addr_result, *rp; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_PASSIVE; - hints.ai_family = AF_UNSPEC; + hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; std::stringstream ss; ss << port; - if (iface == "0.0.0.0" || iface.length() == 0) { + if (iface == "0.0.0.0" || iface.length() == 0){ if ((addr_ret = getaddrinfo(0, ss.str().c_str(), &hints, &addr_result)) != 0){ FAIL_MSG("Could not resolve %s for UDP: %s", iface.c_str(), gai_strerror(addr_ret)); return 0; @@ -1195,15 +1131,13 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string & } std::string err_str; - for (rp = addr_result; rp != NULL; rp = rp->ai_next) { + for (rp = addr_result; rp != NULL; rp = rp->ai_next){ sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (sock == -1) { - continue; - } + if (sock == -1){continue;} char human_addr[INET6_ADDRSTRLEN]; getnameinfo(rp->ai_addr, rp->ai_addrlen, human_addr, INET6_ADDRSTRLEN, 0, 0, NI_NUMERICHOST); MEDIUM_MSG("Attempting bind to %s (%s)", human_addr, rp->ai_family == AF_INET6 ? "IPv6" : "IPv4"); - if (::bind(sock, rp->ai_addr, rp->ai_addrlen) == 0) { + if (::bind(sock, rp->ai_addr, rp->ai_addrlen) == 0){ family = rp->ai_family; hints.ai_family = family; break; @@ -1212,33 +1146,33 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string & err_str += human_addr; err_str += ":"; err_str += strerror(errno); - close();//we open a new socket for each attempt + close(); // we open a new socket for each attempt } if (sock == -1){ FAIL_MSG("Could not open %s for UDP: %s", iface.c_str(), err_str.c_str()); freeaddrinfo(addr_result); return 0; } - //socket is bound! Let's collect some more data... + // socket is bound! Let's collect some more data... if (family == AF_INET6){ - sockaddr_in6 * addr6 = (sockaddr_in6*)(rp->ai_addr); + sockaddr_in6 *addr6 = (sockaddr_in6 *)(rp->ai_addr); result = ntohs(addr6->sin6_port); - if (memcmp((char*)&(addr6->sin6_addr), "\000\000\000\000\000\000\000\000\000\000\377\377", 12) == 0){ - //IPv6-mapped IPv4 address - 13th byte ([12]) holds the first IPv4 byte - multicast = (((char*)&(addr6->sin6_addr))[12] & 0xF0) == 0xE0; + if (memcmp((char *)&(addr6->sin6_addr), "\000\000\000\000\000\000\000\000\000\000\377\377", 12) == 0){ + // IPv6-mapped IPv4 address - 13th byte ([12]) holds the first IPv4 byte + multicast = (((char *)&(addr6->sin6_addr))[12] & 0xF0) == 0xE0; }else{ //"normal" IPv6 address - prefix ff00::/8 - multicast = (((char*)&(addr6->sin6_addr))[0] == 0xFF); + multicast = (((char *)&(addr6->sin6_addr))[0] == 0xFF); } }else{ - sockaddr_in * addr4 = (sockaddr_in*)(rp->ai_addr); + sockaddr_in *addr4 = (sockaddr_in *)(rp->ai_addr); result = ntohs(addr4->sin_port); - //multicast has a "1110" bit prefix - multicast = (((char*)&(addr4->sin_addr))[0] & 0xF0) == 0xE0; + // multicast has a "1110" bit prefix + multicast = (((char *)&(addr4->sin_addr))[0] & 0xF0) == 0xE0; } freeaddrinfo(addr_result); - //handle multicast membership(s) + // handle multicast membership(s) if (multicast){ struct ipv6_mreq mreq6; struct ip_mreq mreq4; @@ -1254,71 +1188,71 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string & if (!multicastInterfaces.length()){ if (family == AF_INET6){ - memcpy(&mreq6.ipv6mr_multiaddr, &((sockaddr_in6*)resmulti->ai_addr)->sin6_addr, sizeof(mreq6.ipv6mr_multiaddr)); - if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)) != 0) { + memcpy(&mreq6.ipv6mr_multiaddr, &((sockaddr_in6 *)resmulti->ai_addr)->sin6_addr, sizeof(mreq6.ipv6mr_multiaddr)); + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)) != 0){ FAIL_MSG("Unable to register for IPv6 multicast on all interfaces: %s", strerror(errno)); close(); result = -1; } }else{ - mreq4.imr_multiaddr = ((sockaddr_in*)resmulti->ai_addr)->sin_addr; + mreq4.imr_multiaddr = ((sockaddr_in *)resmulti->ai_addr)->sin_addr; mreq4.imr_interface.s_addr = INADDR_ANY; - if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq4, sizeof(mreq4)) != 0) { + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq4, sizeof(mreq4)) != 0){ FAIL_MSG("Unable to register for IPv4 multicast on all interfaces: %s", strerror(errno)); close(); result = -1; } } }else{ - size_t nxtPos = std::string::npos; - bool atLeastOne = false; - for (size_t loc = 0; loc != std::string::npos; loc = (nxtPos == std::string::npos ? nxtPos : nxtPos + 1)){ - nxtPos = multicastInterfaces.find(',', loc); - std::string curIface = multicastInterfaces.substr(loc, (nxtPos == std::string::npos ? nxtPos : nxtPos - loc)); - //do a bit of filtering for IPv6, removing the []-braces, if any - if (curIface[0] == '['){ - if (curIface[curIface.size() - 1] == ']'){ - curIface = curIface.substr(1, curIface.size()-2); - }else{ - curIface = curIface.substr(1, curIface.size()-1); - } - } - if (family == AF_INET6){ - INFO_MSG("Registering for IPv6 multicast on interface %s", curIface.c_str()); - if ((addr_ret = getaddrinfo(curIface.c_str(), 0, &hints, &reslocal)) != 0){ - WARN_MSG("Unable to resolve IPv6 interface address %s: %s", curIface.c_str(), gai_strerror(addr_ret)); - continue; - } - memcpy(&mreq6.ipv6mr_multiaddr, &((sockaddr_in6*)resmulti->ai_addr)->sin6_addr, sizeof(mreq6.ipv6mr_multiaddr)); - mreq6.ipv6mr_interface = ((sockaddr_in6*)reslocal->ai_addr)->sin6_scope_id; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)) != 0) { - FAIL_MSG("Unable to register for IPv6 multicast on interface %s (%u): %s", curIface.c_str(), ((sockaddr_in6*)reslocal->ai_addr)->sin6_scope_id, strerror(errno)); - }else{ - atLeastOne = true; - } + size_t nxtPos = std::string::npos; + bool atLeastOne = false; + for (size_t loc = 0; loc != std::string::npos; loc = (nxtPos == std::string::npos ? nxtPos : nxtPos + 1)){ + nxtPos = multicastInterfaces.find(',', loc); + std::string curIface = multicastInterfaces.substr(loc, (nxtPos == std::string::npos ? nxtPos : nxtPos - loc)); + // do a bit of filtering for IPv6, removing the []-braces, if any + if (curIface[0] == '['){ + if (curIface[curIface.size() - 1] == ']'){ + curIface = curIface.substr(1, curIface.size() - 2); }else{ - INFO_MSG("Registering for IPv4 multicast on interface %s", curIface.c_str()); - if ((addr_ret = getaddrinfo(curIface.c_str(), 0, &hints, &reslocal)) != 0){ - WARN_MSG("Unable to resolve IPv4 interface address %s: %s", curIface.c_str(), gai_strerror(addr_ret)); - continue; - } - mreq4.imr_multiaddr = ((sockaddr_in*)resmulti->ai_addr)->sin_addr; - mreq4.imr_interface = ((sockaddr_in*)reslocal->ai_addr)->sin_addr; - if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq4, sizeof(mreq4)) != 0) { - FAIL_MSG("Unable to register for IPv4 multicast on interface %s: %s", curIface.c_str() , strerror(errno)); - }else{ - atLeastOne = true; - } + curIface = curIface.substr(1, curIface.size() - 1); } - if (!atLeastOne){ - close(); - result = -1; + } + if (family == AF_INET6){ + INFO_MSG("Registering for IPv6 multicast on interface %s", curIface.c_str()); + if ((addr_ret = getaddrinfo(curIface.c_str(), 0, &hints, &reslocal)) != 0){ + WARN_MSG("Unable to resolve IPv6 interface address %s: %s", curIface.c_str(), gai_strerror(addr_ret)); + continue; } - freeaddrinfo(reslocal);//free resolved interface addr - }//loop over all interfaces + memcpy(&mreq6.ipv6mr_multiaddr, &((sockaddr_in6 *)resmulti->ai_addr)->sin6_addr, sizeof(mreq6.ipv6mr_multiaddr)); + mreq6.ipv6mr_interface = ((sockaddr_in6 *)reslocal->ai_addr)->sin6_scope_id; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)) != 0){ + FAIL_MSG("Unable to register for IPv6 multicast on interface %s (%u): %s", curIface.c_str(), + ((sockaddr_in6 *)reslocal->ai_addr)->sin6_scope_id, strerror(errno)); + }else{ + atLeastOne = true; + } + }else{ + INFO_MSG("Registering for IPv4 multicast on interface %s", curIface.c_str()); + if ((addr_ret = getaddrinfo(curIface.c_str(), 0, &hints, &reslocal)) != 0){ + WARN_MSG("Unable to resolve IPv4 interface address %s: %s", curIface.c_str(), gai_strerror(addr_ret)); + continue; + } + mreq4.imr_multiaddr = ((sockaddr_in *)resmulti->ai_addr)->sin_addr; + mreq4.imr_interface = ((sockaddr_in *)reslocal->ai_addr)->sin_addr; + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq4, sizeof(mreq4)) != 0){ + FAIL_MSG("Unable to register for IPv4 multicast on interface %s: %s", curIface.c_str(), strerror(errno)); + }else{ + atLeastOne = true; + } + } + if (!atLeastOne){ + close(); + result = -1; + } + freeaddrinfo(reslocal); // free resolved interface addr + }// loop over all interfaces } - freeaddrinfo(resmulti);//free resolved multicast addr - + freeaddrinfo(resmulti); // free resolved multicast addr } return result; } @@ -1327,7 +1261,7 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string & /// 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() { +bool Socket::UDPConnection::Receive(){ #ifdef __CYGWIN__ if (data_size != SOCKETSIZE){ data = (char *)realloc(data, SOCKETSIZE); @@ -1335,16 +1269,14 @@ bool Socket::UDPConnection::Receive() { } #endif int r = recvfrom(sock, data, data_size, MSG_PEEK | MSG_TRUNC | MSG_DONTWAIT, 0, 0); - if (r == -1) { - if (errno != EAGAIN) { - INFO_MSG("UDP receive: %d (%s)", errno, strerror(errno)); - } + if (r == -1){ + if (errno != EAGAIN){INFO_MSG("UDP receive: %d (%s)", errno, strerror(errno));} data_len = 0; return false; } - if (data_size < (unsigned int)r) { - char* tmp = (char*)realloc(data, r); - if (tmp) { + if (data_size < (unsigned int)r){ + char *tmp = (char *)realloc(data, r); + if (tmp){ data = tmp; data_size = r; }else{ @@ -1354,16 +1286,16 @@ bool Socket::UDPConnection::Receive() { } socklen_t destsize = destAddr_size; r = recvfrom(sock, data, data_size, 0, (sockaddr *)destAddr, &destsize); - if (r > 0) { + if (r > 0){ down += r; data_len = r; return true; - } else { + }else{ data_len = 0; return false; } } -int Socket::UDPConnection::getSock() { +int Socket::UDPConnection::getSock(){ return sock; } diff --git a/lib/socket.h b/lib/socket.h index 79530bb3..0760346c 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -3,150 +3,154 @@ /// Written by Jaron Vietor in 2010 for DDVTech #pragma once -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -//for being friendly with Socket::Connection down below -namespace Buffer { +// for being friendly with Socket::Connection down below +namespace Buffer{ class user; } -///Holds Socket tools. -namespace Socket { +/// Holds Socket tools. +namespace Socket{ + + void hostBytesToStr(const char *bytes, size_t len, std::string &target); /// A buffer made out of std::string objects that can be efficiently read from and written to. - class Buffer { - private: - std::deque data; - public: - unsigned int size(); - unsigned int bytes(unsigned int max); - void append(const std::string & newdata); - void append(const char * newdata, const unsigned int newdatasize); - void prepend(const std::string & newdata); - void prepend(const char * newdata, const unsigned int newdatasize); - std::string & get(); - bool available(unsigned int count); - std::string remove(unsigned int count); - std::string copy(unsigned int count); - void clear(); + class Buffer{ + private: + std::deque data; + + public: + unsigned int size(); + unsigned int bytes(unsigned int max); + void append(const std::string &newdata); + void append(const char *newdata, const unsigned int newdatasize); + void prepend(const std::string &newdata); + void prepend(const char *newdata, const unsigned int newdatasize); + std::string &get(); + bool available(unsigned int count); + std::string remove(unsigned int count); + std::string copy(unsigned int count); + void clear(); }; - //Buffer + // Buffer /// This class is for easy communicating through sockets, either TCP or Unix. - class Connection { - private: - int sock; ///< Internally saved socket number. - int pipes[2]; ///< Internally saved file descriptors for pipe socket simulation. - std::string remotehost; ///< Stores remote host address. - uint64_t up; - uint64_t down; - long long int conntime; - Buffer downbuffer; ///< Stores temporary data coming in. - int iread(void * buffer, int len, int flags = 0); ///< Incremental read call. - unsigned int iwrite(const void * buffer, int len); ///< Incremental write call. - bool iread(Buffer & buffer, int flags = 0); ///< Incremental write call that is compatible with Socket::Buffer. - bool iwrite(std::string & buffer); ///< Write call that is compatible with std::string. - public: - //friends - friend class ::Buffer::user; - //constructors - Connection(); ///< Create a new disconnected base socket. - Connection(int sockNo); ///< Create a new base socket. - Connection(std::string hostname, int port, bool nonblock); ///< Create a new TCP socket. - Connection(std::string adres, bool nonblock = false); ///< Create a new Unix Socket. - Connection(int write, int read); ///< Simulate a socket using two file descriptors. - //generic methods - void close(); ///< Close connection. - void drop(); ///< Close connection without shutdown. - void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false). - bool isBlocking(); ///< Check if this socket is blocking (true) or nonblocking (false). - std::string getHost() const; ///< Gets hostname for connection, if available. - std::string getBinHost(); - void setHost(std::string host); ///< Sets hostname for connection manually. - int getSocket(); ///< Returns internal socket number. - int getPureSocket(); ///< Returns non-piped internal socket number. - std::string getError(); ///< Returns a string describing the last error that occured. - bool connected() const; ///< Returns the connected-state for this socket. - bool isAddress(std::string addr); - //buffered i/o methods - bool spool(); ///< Updates the downbufferinternal variables. - bool peek(); ///< Clears the downbuffer and fills it with peek - Buffer & Received(); ///< Returns a reference to the download buffer. - void SendNow(const std::string & data); ///< Will not buffer anything but always send right away. Blocks. - void SendNow(const char * data); ///< Will not buffer anything but always send right away. Blocks. - void SendNow(const char * data, size_t len); ///< Will not buffer anything but always send right away. Blocks. - //stats related methods - unsigned int connTime();///< Returns the time this socket has been connected. - uint64_t dataUp(); ///< Returns total amount of bytes sent. - uint64_t dataDown(); ///< Returns total amount of bytes received. - std::string getStats(std::string C); ///< Returns a std::string of stats, ended by a newline. - friend class Server; - bool Error; ///< Set to true if a socket error happened. - bool Blocking; ///< Set to true if a socket is currently or wants to be blocking. - //overloaded operators - bool operator==(const Connection & B) const; - bool operator!=(const Connection & B) const; - operator bool() const; + class Connection{ + private: + int sock; ///< Internally saved socket number. + int pipes[2]; ///< Internally saved file descriptors for pipe socket simulation. + std::string remotehost; ///< Stores remote host address. + uint64_t up; + uint64_t down; + long long int conntime; + Buffer downbuffer; ///< Stores temporary data coming in. + int iread(void *buffer, int len, int flags = 0); ///< Incremental read call. + unsigned int iwrite(const void *buffer, int len); ///< Incremental write call. + bool iread(Buffer &buffer, int flags = 0); ///< Incremental write call that is compatible with Socket::Buffer. + bool iwrite(std::string &buffer); ///< Write call that is compatible with std::string. + public: + // friends + friend class ::Buffer::user; + // constructors + Connection(); ///< Create a new disconnected base socket. + Connection(int sockNo); ///< Create a new base socket. + Connection(std::string hostname, int port, bool nonblock); ///< Create a new TCP socket. + Connection(std::string adres, bool nonblock = false); ///< Create a new Unix Socket. + Connection(int write, int read); ///< Simulate a socket using two file descriptors. + // generic methods + void close(); ///< Close connection. + void drop(); ///< Close connection without shutdown. + void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false). + bool isBlocking(); ///< Check if this socket is blocking (true) or nonblocking (false). + std::string getHost() const; ///< Gets hostname for connection, if available. + std::string getBinHost(); + void setHost(std::string host); ///< Sets hostname for connection manually. + int getSocket(); ///< Returns internal socket number. + int getPureSocket(); ///< Returns non-piped internal socket number. + std::string getError(); ///< Returns a string describing the last error that occured. + bool connected() const; ///< Returns the connected-state for this socket. + bool isAddress(std::string addr); + // buffered i/o methods + bool spool(); ///< Updates the downbufferinternal variables. + bool peek(); ///< Clears the downbuffer and fills it with peek + Buffer &Received(); ///< Returns a reference to the download buffer. + void SendNow(const std::string &data); ///< Will not buffer anything but always send right away. Blocks. + void SendNow(const char *data); ///< Will not buffer anything but always send right away. Blocks. + void SendNow(const char *data, size_t len); ///< Will not buffer anything but always send right away. Blocks. + // stats related methods + unsigned int connTime(); ///< Returns the time this socket has been connected. + uint64_t dataUp(); ///< Returns total amount of bytes sent. + uint64_t dataDown(); ///< Returns total amount of bytes received. + void resetCounter(); ///< Resets the up/down bytes counter to zero. + std::string getStats(std::string C); ///< Returns a std::string of stats, ended by a newline. + friend class Server; + bool Error; ///< Set to true if a socket error happened. + bool Blocking; ///< Set to true if a socket is currently or wants to be blocking. + // overloaded operators + bool operator==(const Connection &B) const; + bool operator!=(const Connection &B) const; + operator bool() const; }; /// This class is for easily setting up listening socket, either TCP or Unix. - class Server { - private: - std::string errors; ///< Stores errors that may have occured. - int sock; ///< Internally saved socket number. - bool IPv6bind(int port, std::string hostname, bool nonblock); ///< Attempt to bind an IPv6 socket - bool IPv4bind(int port, std::string hostname, bool nonblock); ///< Attempt to bind an IPv4 socket - public: - Server(); ///< Create a new base Server. - Server(int port, std::string hostname = "0.0.0.0", bool nonblock = false); ///< Create a new TCP Server. - Server(std::string adres, bool nonblock = false); ///< Create a new Unix Server. - Connection accept(bool nonblock = false); ///< Accept any waiting connections. - void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false). - bool connected() const; ///< Returns the connected-state for this socket. - bool isBlocking(); ///< Check if this socket is blocking (true) or nonblocking (false). - void close(); ///< Close connection. - void drop(); ///< Close connection without shutdown. - int getSocket(); ///< Returns internal socket number. + class Server{ + private: + std::string errors; ///< Stores errors that may have occured. + int sock; ///< Internally saved socket number. + bool IPv6bind(int port, std::string hostname, bool nonblock); ///< Attempt to bind an IPv6 socket + bool IPv4bind(int port, std::string hostname, bool nonblock); ///< Attempt to bind an IPv4 socket + public: + Server(); ///< Create a new base Server. + Server(int port, std::string hostname = "0.0.0.0", bool nonblock = false); ///< Create a new TCP Server. + Server(std::string adres, bool nonblock = false); ///< Create a new Unix Server. + Connection accept(bool nonblock = false); ///< Accept any waiting connections. + void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false). + bool connected() const; ///< Returns the connected-state for this socket. + bool isBlocking(); ///< Check if this socket is blocking (true) or nonblocking (false). + void close(); ///< Close connection. + void drop(); ///< Close connection without shutdown. + int getSocket(); ///< Returns internal socket number. }; - class UDPConnection { - private: - int sock; ///< Internally saved socket number. - std::string remotehost;///< Stores remote host address - void * destAddr;///< Destination address pointer. - unsigned int destAddr_size;///< Size of the destination address pointer. - unsigned int up;///< Amount of bytes transferred up. - unsigned int down;///< Amount of bytes transferred down. - unsigned int data_size;///< The size in bytes of the allocated space in the data pointer. - int family;///