Merge branch 'development' into LTS_development
# Conflicts: # lib/socket.cpp # lib/socket.h
This commit is contained in:
commit
fdb5fbad45
3 changed files with 539 additions and 619 deletions
298
lib/socket.cpp
298
lib/socket.cpp
|
@ -3,15 +3,15 @@
|
|||
/// Written by Jaron Vietor in 2010 for DDVTech
|
||||
|
||||
#include "socket.h"
|
||||
#include "timing.h"
|
||||
#include "defines.h"
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include "timing.h"
|
||||
#include <cstdlib>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <netdb.h>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define BUFFER_BLOCKSIZE 4096 // set buffer blocksize to 4KiB
|
||||
|
||||
|
@ -21,6 +21,32 @@
|
|||
#define SOCKETSIZE 51200ul
|
||||
#endif
|
||||
|
||||
/// 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;
|
||||
|
@ -31,9 +57,7 @@ std::string uint2string(unsigned int i) {
|
|||
/// 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();
|
||||
}
|
||||
while (data.size() > 0 && data.back().empty()){data.pop_back();}
|
||||
return data.size();
|
||||
}
|
||||
|
||||
|
@ -42,9 +66,7 @@ unsigned int Socket::Buffer::bytes(unsigned int max) {
|
|||
unsigned int i = 0;
|
||||
for (std::deque<std::string>::iterator it = data.begin(); it != data.end(); ++it){
|
||||
i += (*it).size();
|
||||
if (i >= max) {
|
||||
return max;
|
||||
}
|
||||
if (i >= max){return max;}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
@ -63,12 +85,9 @@ void Socket::Buffer::append(const char * newdata, const unsigned int newdatasize
|
|||
j = i;
|
||||
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);
|
||||
data.push_front(std::string(newdata + i, (size_t)(j - i)));
|
||||
i = j;
|
||||
}else{
|
||||
|
@ -76,7 +95,8 @@ void Socket::Buffer::append(const char * newdata, const unsigned int newdatasize
|
|||
}
|
||||
}
|
||||
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));
|
||||
DEBUG_MSG(DLVL_WARN, "Warning: After %d new bytes, buffer has %d parts containing over %u bytes!", newdatasize, (int)data.size(),
|
||||
bytes(9000));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,9 +118,7 @@ bool Socket::Buffer::available(unsigned int count) {
|
|||
unsigned int i = 0;
|
||||
for (std::deque<std::string>::iterator it = data.begin(); it != data.end(); ++it){
|
||||
i += (*it).size();
|
||||
if (i >= count) {
|
||||
return true;
|
||||
}
|
||||
if (i >= count){return true;}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -109,9 +127,7 @@ bool Socket::Buffer::available(unsigned int count) {
|
|||
/// Returns an empty string if not all count bytes are available.
|
||||
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);
|
||||
|
@ -133,9 +149,7 @@ std::string Socket::Buffer::remove(unsigned int count) {
|
|||
/// Returns an empty string if not all count bytes are available.
|
||||
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);
|
||||
|
@ -207,7 +221,6 @@ Socket::Connection::Connection() {
|
|||
Blocking = false;
|
||||
}// Socket::Connection basic constructor
|
||||
|
||||
|
||||
void Socket::Connection::resetCounter(){
|
||||
up = 0;
|
||||
down = 0;
|
||||
|
@ -232,28 +245,16 @@ bool isFDBlocking(int FD) {
|
|||
|
||||
/// 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);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
if (sock >= 0){return isFDBlocking(sock);}
|
||||
if (pipes[0] >= 0){return isFDBlocking(pipes[0]);}
|
||||
if (pipes[1] >= 0){return isFDBlocking(pipes[1]);}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -262,9 +263,7 @@ bool Socket::Connection::isBlocking() {
|
|||
/// 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);
|
||||
}
|
||||
if (sock != -1){shutdown(sock, SHUT_RDWR);}
|
||||
drop();
|
||||
}// Socket::Connection::close
|
||||
|
||||
|
@ -277,20 +276,17 @@ void Socket::Connection::drop() {
|
|||
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){
|
||||
errno = EINTR;
|
||||
while (::close(pipes[0]) != 0 && errno == EINTR) {
|
||||
}
|
||||
while (::close(pipes[0]) != 0 && errno == EINTR){}
|
||||
pipes[0] = -1;
|
||||
}
|
||||
if (pipes[1] != -1){
|
||||
errno = EINTR;
|
||||
while (::close(pipes[1]) != 0 && errno == EINTR) {
|
||||
}
|
||||
while (::close(pipes[1]) != 0 && errno == EINTR){}
|
||||
pipes[1] = -1;
|
||||
}
|
||||
}
|
||||
|
@ -298,15 +294,9 @@ void 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];
|
||||
}
|
||||
if (sock != -1){return sock;}
|
||||
if (pipes[0] != -1){return pipes[0];}
|
||||
if (pipes[1] != -1){return pipes[1];}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -385,12 +375,8 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock) {
|
|||
remotehost = "";
|
||||
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);
|
||||
}
|
||||
|
@ -464,16 +450,10 @@ Socket::Buffer & Socket::Connection::Received() {
|
|||
/// 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){
|
||||
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.
|
||||
|
@ -495,9 +475,7 @@ void Socket::Connection::SendNow(const std::string & data) {
|
|||
/// \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;
|
||||
}
|
||||
if (!connected() || len < 1){return 0;}
|
||||
int r;
|
||||
if (sock >= 0){
|
||||
r = send(sock, buffer, len, 0);
|
||||
|
@ -506,9 +484,7 @@ unsigned int Socket::Connection::iwrite(const void * buffer, int len) {
|
|||
}
|
||||
if (r < 0){
|
||||
switch (errno){
|
||||
case EWOULDBLOCK:
|
||||
return 0;
|
||||
break;
|
||||
case EWOULDBLOCK: return 0; break;
|
||||
default:
|
||||
Error = true;
|
||||
INSANE_MSG("Could not iwrite data! Error: %s", strerror(errno));
|
||||
|
@ -532,26 +508,18 @@ unsigned int Socket::Connection::iwrite(const void * buffer, int len) {
|
|||
/// \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;
|
||||
}
|
||||
if (!connected() || len < 1){return 0;}
|
||||
int r;
|
||||
if (sock >= 0){
|
||||
r = recv(sock, buffer, len, flags);
|
||||
}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;
|
||||
case EWOULDBLOCK: return 0; break;
|
||||
case EINTR: return 0; break;
|
||||
default:
|
||||
Error = true;
|
||||
INSANE_MSG("Could not iread data! Error: %s", strerror(errno));
|
||||
|
@ -577,9 +545,7 @@ int Socket::Connection::iread(void * buffer, int len, 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
|
||||
|
@ -590,13 +556,9 @@ bool Socket::Connection::iread(Buffer & buffer, int flags) {
|
|||
/// \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;
|
||||
}
|
||||
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
|
||||
|
@ -626,12 +588,8 @@ std::string Socket::Connection::getBinHost() {
|
|||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
@ -677,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)){
|
||||
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)){
|
||||
DEBUG_MSG(DLVL_DEVEL, "Comparing: '%s' to '%s'", remotehost.c_str(), newaddr);
|
||||
if (remotehost == newaddr) {
|
||||
return true;
|
||||
}
|
||||
if (remotehost == newaddr){return true;}
|
||||
}
|
||||
}
|
||||
freeaddrinfo(result);
|
||||
|
@ -826,7 +776,8 @@ 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){
|
||||
|
@ -869,9 +820,7 @@ Socket::Server::Server(std::string address, bool nonblock) {
|
|||
/// \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);
|
||||
}
|
||||
if (sock < 0){return Socket::Connection(-1);}
|
||||
struct sockaddr_in6 addrinfo;
|
||||
socklen_t len = sizeof(addrinfo);
|
||||
static char addrconv[INET6_ADDRSTRLEN];
|
||||
|
@ -908,16 +857,12 @@ 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (sock >= 0){return isFDBlocking(sock);}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -926,9 +871,7 @@ bool Socket::Server::isBlocking() {
|
|||
/// 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);
|
||||
}
|
||||
if (sock != -1){shutdown(sock, SHUT_RDWR);}
|
||||
drop();
|
||||
}// Socket::Server::close
|
||||
|
||||
|
@ -941,8 +884,7 @@ void Socket::Server::drop() {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
@ -973,9 +915,7 @@ Socket::UDPConnection::UDPConnection(bool nonblock) {
|
|||
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;
|
||||
|
@ -983,9 +923,7 @@ Socket::UDPConnection::UDPConnection(bool nonblock) {
|
|||
data = 0;
|
||||
data_size = 0;
|
||||
data_len = 0;
|
||||
if (nonblock) {
|
||||
setBlocking(!nonblock);
|
||||
}
|
||||
if (nonblock){setBlocking(!nonblock);}
|
||||
}// Socket::UDPConnection UDP Contructor
|
||||
|
||||
/// Copies a UDP socket, re-allocating local copies of any needed structures.
|
||||
|
@ -997,16 +935,12 @@ Socket::UDPConnection::UDPConnection(const UDPConnection & o) {
|
|||
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){
|
||||
destAddr = malloc(o.destAddr_size);
|
||||
if (destAddr) {
|
||||
memcpy(destAddr, o.destAddr, o.destAddr_size);
|
||||
}
|
||||
if (destAddr){memcpy(destAddr, o.destAddr, o.destAddr_size);}
|
||||
}else{
|
||||
destAddr = 0;
|
||||
destAddr_size = 0;
|
||||
|
@ -1024,8 +958,7 @@ Socket::UDPConnection::UDPConnection(const UDPConnection & o) {
|
|||
void Socket::UDPConnection::close(){
|
||||
if (sock != -1){
|
||||
errno = EINTR;
|
||||
while (::close(sock) != 0 && errno == EINTR) {
|
||||
}
|
||||
while (::close(sock) != 0 && errno == EINTR){}
|
||||
sock = -1;
|
||||
}
|
||||
}
|
||||
|
@ -1046,26 +979,20 @@ 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;
|
||||
//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;
|
||||
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;
|
||||
|
@ -1077,7 +1004,17 @@ void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port) {
|
|||
|
||||
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
|
||||
|
@ -1121,21 +1058,15 @@ void Socket::UDPConnection::GetDestination(std::string & destIp, uint32_t & port
|
|||
/// 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);
|
||||
}
|
||||
if (sock >= 0){setFDBlocking(sock, blocking);}
|
||||
}
|
||||
|
||||
/// Sends a UDP datagram using the buffer sdata.
|
||||
|
@ -1156,9 +1087,7 @@ void Socket::UDPConnection::SendNow(const char * sdata) {
|
|||
/// 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, sdata, len, 0, (sockaddr *)destAddr, destAddr_size);
|
||||
if (r > 0){
|
||||
up += r;
|
||||
|
@ -1171,7 +1100,8 @@ 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
|
||||
|
@ -1181,7 +1111,7 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string &
|
|||
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;
|
||||
|
||||
|
@ -1203,9 +1133,7 @@ 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){
|
||||
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");
|
||||
|
@ -1298,7 +1226,8 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string &
|
|||
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));
|
||||
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;
|
||||
}
|
||||
|
@ -1324,7 +1253,6 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string &
|
|||
}// loop over all interfaces
|
||||
}
|
||||
freeaddrinfo(resmulti); // free resolved multicast addr
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1342,9 +1270,7 @@ 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 (errno != EAGAIN){INFO_MSG("UDP receive: %d (%s)", errno, strerror(errno));}
|
||||
data_len = 0;
|
||||
return false;
|
||||
}
|
||||
|
|
25
lib/socket.h
25
lib/socket.h
|
@ -3,18 +3,18 @@
|
|||
/// Written by Jaron Vietor in 2010 for DDVTech
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <deque>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// for being friendly with Socket::Connection down below
|
||||
namespace Buffer{
|
||||
|
@ -24,10 +24,13 @@ namespace Buffer {
|
|||
/// 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<std::string> data;
|
||||
|
||||
public:
|
||||
unsigned int size();
|
||||
unsigned int bytes(unsigned int max);
|
||||
|
@ -149,5 +152,5 @@ namespace Socket {
|
|||
void SendNow(const char *data);
|
||||
void SendNow(const char *data, size_t len);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -79,16 +79,7 @@ std::string Controller::sessIndex::toStr(){
|
|||
/// Initializes a sessIndex from a statExchange object, converting binary format IP addresses into strings.
|
||||
/// This extracts the host, stream name, connector and crc field, ignoring everything else.
|
||||
Controller::sessIndex::sessIndex(IPC::statExchange & data){
|
||||
std::string tHost = data.host();
|
||||
if (tHost.substr(0, 12) == std::string("\000\000\000\000\000\000\000\000\000\000\377\377", 12)){
|
||||
char tmpstr[16];
|
||||
snprintf(tmpstr, 16, "%hhu.%hhu.%hhu.%hhu", tHost[12], tHost[13], tHost[14], tHost[15]);
|
||||
host = 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", tHost[0], tHost[1], tHost[2], tHost[3], tHost[4], tHost[5], tHost[6], tHost[7], tHost[8], tHost[9], tHost[10], tHost[11], tHost[12], tHost[13], tHost[14], tHost[15]);
|
||||
host = tmpstr;
|
||||
}
|
||||
Socket::hostBytesToStr(data.host().c_str(), 16, host);
|
||||
streamName = data.streamName();
|
||||
connector = data.connector();
|
||||
crc = data.crc();
|
||||
|
|
Loading…
Add table
Reference in a new issue