Browse Source

Consolidated PR #27 for current git

Branch netjack_squashed_interface_selection_plus_ipv6

Original PR:
https://github.com/jackaudio/jack2/pull/27
by rufferson, first comment Mar 3, 2013

Commits on Mar 12, 2017

    Add interface selection for NetJack components

@rufferson
rufferson committed on Mar 3, 2013

 * Multicast interface selection to UnixSocket - added methods
   Bind and JoinMCastGroup with <char *if_name> argument
 * Interface handling to NetInterface class tree - new field and
   its initialization/usage in Slave branch.
 * Multicast interface selection to NetSlaves (Adapter/Driver)
   and NetMaster, where master can now listen all interfaces.

Commits on Mar 15, 2017

    Add IPv6 support to UnixSocket and NetInterfaces

@rufferson
rufferson committed on Feb 21, 2013

 * Cleaned up direct references to sockaddr_in
 * Changed fRecvAddr & fSendAddr to sockaddr_storage
 * Added field fFamily indicating current probed AF.
 * Added protected method ProbeAF accepting IP to probe
   and addr to fill in. As well as final call to test
   which should be either connect or bind.
 * Reworked protocol specific methods to act on fFamily
 * IsLocal now checks assigned interface addresses
 * Introduced internal state tracker to avoid double bind
 * Workaround for GLIBC bug returning wrong order of AFs
   http://sourceware.org/bugzilla/show_bug.cgi?id=14967
 * Corrected interface selection for Slaves - only one
   interface could be used to multicast the packet
 * Retab changes

This branch has conflicts that must be resolved
to resolve conflicts before continuing.
Conflicting files
common/JackNetDriver.h
posix/JackNetUnixSocket.cpp

wget https://github.com/jackaudio/jack2/pull/27.diff

$ patch -p 1 < 27.diff
patching file common/JackNetAdapter.cpp
patching file common/JackNetDriver.cpp
patching file common/JackNetDriver.h
Hunk #1 FAILED at 79.
1 out of 1 hunk FAILED -- saving rejects to file common/JackNetDriver.h.rej
patching file common/JackNetInterface.cpp
patching file common/JackNetInterface.h
patching file common/JackNetManager.cpp
patching file common/JackNetManager.h
patching file common/JackNetTool.h
patching file posix/JackNetUnixSocket.cpp
Hunk #4 FAILED at 229.
Hunk #5 succeeded at 281 (offset -8 lines).
Hunk #6 succeeded at 303 (offset -8 lines).
Hunk #7 succeeded at 325 (offset -8 lines).
Hunk #8 succeeded at 363 (offset -8 lines).
Hunk #9 succeeded at 486 (offset -8 lines).
Hunk #10 succeeded at 508 (offset -8 lines).
Hunk #11 succeeded at 537 (offset -8 lines).
Hunk #12 succeeded at 586 (offset -8 lines).
Hunk #13 succeeded at 607 (offset -8 lines).
Hunk #14 succeeded at 615 (offset -8 lines).
Hunk #15 succeeded at 644 (offset -8 lines).
Hunk #16 succeeded at 673 (offset -8 lines).
1 out of 16 hunks FAILED -- saving rejects to file posix/JackNetUnixSocket.cpp.rej

 find|grep rej
./posix/JackNetUnixSocket.cpp.rej
./common/JackNetDriver.h.rej

--- posix/JackNetUnixSocket.cpp
+++ posix/JackNetUnixSocket.cpp
@@ -229,58 +311,117 @@
     {
         if (strcmp(ip, "127.0.0.1") == 0) {
             return true;
-        }
+        } else if(!strcmp(ip,"::1"))
+            return true;

-        char host_name[32];
-        gethostname(host_name, sizeof(host_name));
+        struct ifaddrs *ifas, *ifa;
+        socklen_t len;

-        struct hostent* host = gethostbyname(host_name);
-        if (host) {
-            for (int i = 0; host->h_addr_list[i] != 0; ++i) {
-                struct in_addr addr;
-                memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
-                if (strcmp(inet_ntoa(addr), ip) == 0) {
-                    return true;
-                }
-            }
-            return false;
-        } else {
-            return false;
+        if (getifaddrs(&ifas) == -1) {
+                jack_error("JackNetUnixSocket::IsLocal error in getifaddrs");
+                return false;
         }
+        for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
+                if (ifa->ifa_addr == NULL)
+                    continue; // Address is mandatory
+                len = (ifa->ifa_addr->sa_family==AF_INET)?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6);
+                if(!getnameinfo(ifa->ifa_addr, len, f_addr_buff, INET6_ADDRSTRLEN, NULL,0, NI_NUMERICSERV | NI_DGRAM | NI_NUMERICHOST))
+                    if(!strcmp(f_addr_buff,ip))
+                        break;
+        }
+        freeifaddrs(ifas);
+        return (ifa != NULL);
     }

     int JackNetUnixSocket::Bind()
     {
-        return bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
+        int yes=1;
+        if(fState & JNS_BOUND) return 0;
+        // Multicast is incompatible with V4MAPPED or V4COMPAT addresses, if probe detected MC we need V6ONLY
+        if(fFamily == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&_sock6(fRecvAddr).sin6_addr) && fState & JNS_MCAST)
+            if(SetOption(IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) return SOCKET_ERROR;
+        if(bind(fSockfd, reinterpret_cast<struct sockaddr*>(&fRecvAddr), sizeof(fRecvAddr))) return SOCKET_ERROR;
+        fState |= JNS_BOUND;
+        return 0;
+    }
+    int JackNetUnixSocket::Bind(const char *if_name)
+    {
+        int ret = Bind();
+        if(!ret && strcmp(if_name,"any")) {
+            if(fFamily == AF_INET) {
+                // 'all' for this case will lead to 'last valid interface', which is not that one might expect
+                if(strcmp(if_name,"all"))
+                    ret = BindMCastIface(if_name, IP_MULTICAST_IF, &_sock4(fSendAddr).sin_addr);
+                else
+                    jack_error("Multicast Interface all not found, sending from default");
+            } else if(fFamily == AF_INET6) {
+                struct if_nameindex *if_ni = if_nameindex(); // In V6 world we do everything differently.
+                if(if_ni) {
+                    int i;
+                    for (i=0; if_ni[i].if_index > 0; i++) {
+                        if(if_ni[i].if_index == 1)
+                            continue; // Skip loopback
+                        if(!strcmp(if_ni[i].if_name,if_name)) {
+                            ret = SetOption(IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_ni[i].if_index, sizeof(if_ni[i].if_index));
+                            jack_log("JackNetUnixSocket::Bind Multicasting from %s",if_ni[i].if_name);
+                            break;
+                        }
+                    }
+                    if(if_ni[i].if_index == 0) jack_error("Multicast Interface %s not found, sending from default",if_name);
+                    if_freenameindex(if_ni);
+                }
+            }
+        }
+        return ret;
     }

     int JackNetUnixSocket::BindWith(const char* ip)
     {
-        int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
-        if (addr_conv < 0) {
-            return addr_conv;
+        if(fFamily == AF_UNSPEC) {
+            if(!fPort) return SOCKET_ERROR;
+            if(ProbeAF(ip,&fRecvAddr,&bind)<0) return SOCKET_ERROR;
+            fState |= JNS_BOUND;
+            return 0;
+        } else {
+            if(SetRecvIP(ip)==-1) return SOCKET_ERROR;
+            return Bind();
         }
-        return Bind();
     }

     int JackNetUnixSocket::BindWith(int port)
     {
-        fRecvAddr.sin_port = htons(port);
-        return Bind();
+        if(fFamily == AF_UNSPEC) {
+            fPort = port;
+            if(ProbeAF(NULL,&fRecvAddr,&bind)<0) return SOCKET_ERROR;
+            fState |= JNS_BOUND;
+            return 0;
+        } else {
+            SetPort(port);
+            return Bind();
+        }
     }

     int JackNetUnixSocket::Connect()
     {
-        return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
+        if(fFamily != AF_UNSPEC)
+            return connect(fSockfd, (struct sockaddr*)&fSendAddr,sizeof(fSendAddr));
+        jack_error("JackNetUnixSocket::Connect Family not initialized");
+        return SOCKET_ERROR;
     }

     int JackNetUnixSocket::ConnectTo(const char* ip)
     {
-        int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
-        if (addr_conv < 0) {
-            return addr_conv;
+        socklen_t l=sizeof(fRecvAddr);
+        if(fPort==0) return SOCKET_ERROR;
+        if(fState & JNS_PROBED) {
+            Reset();
+            fFamily=AF_UNSPEC;
         }
-        return Connect();
+        if(fSockfd)
+            Close();
+        if(ProbeAF(ip,&fSendAddr,&connect)<0) return SOCKET_ERROR;
+        fState |= JNS_CONNCD;
+        return getsockname(fSockfd, (struct sockaddr *)&fRecvAddr, &l);
     }

     void JackNetUnixSocket::Close()

--- common/JackNetDriver.h
+++ common/JackNetDriver.h
@@ -79,7 +79,7 @@
         public:

             JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
-                        const char* ip, int port, int mtu, int midi_input_ports, int midi_output_ports,
+                        const char* ip, int port, const char* mcif, int mtu, int midi_input_ports, int midi_output_ports,
                         char* net_name, uint transport_sync, int network_latency, int celt_encoding,
                         int opus_encoding, bool auto_save);
             virtual ~JackNetDriver();
netjack_squashed_interface_selection_plus_ipv6
Thomas Brand 6 years ago
parent
commit
40cb345a38
10 changed files with 472 additions and 139 deletions
  1. +14
    -7
      common/JackNetAdapter.cpp
  2. +16
    -3
      common/JackNetDriver.cpp
  3. +1
    -1
      common/JackNetDriver.h
  4. +8
    -2
      common/JackNetInterface.cpp
  5. +4
    -0
      common/JackNetInterface.h
  6. +24
    -5
      common/JackNetManager.cpp
  7. +1
    -0
      common/JackNetManager.h
  8. +0
    -2
      common/JackNetTool.h
  9. +386
    -113
      posix/JackNetUnixSocket.cpp
  10. +18
    -6
      posix/JackNetUnixSocket.h

+ 14
- 7
common/JackNetAdapter.cpp View File

@@ -35,7 +35,7 @@ namespace Jack
because we don't have full parametering right now, parameters will be parsed from the param list,
and then JackNetSlaveInterface will be filled with proper values.
*/
char multicast_ip[32];
char multicast_ip[32],multicast_if[32];
uint udp_port;
GetHostName(fParams.fName, JACK_CLIENT_NAME_SIZE);
fSocket.GetName(fParams.fSlaveNetName);
@@ -58,11 +58,10 @@ namespace Jack
udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT;

const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
if (default_multicast_ip) {
strcpy(multicast_ip, default_multicast_ip);
} else {
strcpy(multicast_ip, DEFAULT_MULTICAST_IP);
}
strcpy(multicast_ip, (default_multicast_ip) ? default_multicast_ip : DEFAULT_MULTICAST_IP);

const char* default_multicast_if = getenv("JACK_NETJACK_INTERFACE");
strcpy(multicast_if, (default_multicast_if) ? default_multicast_if : DEFAULT_MULTICAST_IF);

//options parsing
const JSList* node;
@@ -76,6 +75,10 @@ namespace Jack
assert(strlen(param->value.str) < 32);
strcpy(multicast_ip, param->value.str);
break;
case 'f' :
assert(strlen(param->value.str) < 32);
strcpy(multicast_if, param->value.str);
break;
case 'p' :
udp_port = param->value.ui;
break;
@@ -128,9 +131,10 @@ namespace Jack
}

strcpy(fMulticastIP, multicast_ip);
if(strcmp(multicast_if,DEFAULT_MULTICAST_IF))
strcpy(fMulticastIF, multicast_if);

// Set the socket parameters
fSocket.SetPort(udp_port);
fSocket.SetAddress(fMulticastIP, udp_port);

// If not set, takes default
@@ -424,6 +428,9 @@ extern "C"
strcpy(value.str, DEFAULT_MULTICAST_IP);
jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address, or explicit IP of the master", NULL);

strcpy(value.str, DEFAULT_MULTICAST_IF);
jack_driver_descriptor_add_parameter(desc, &filler, "multicast-if", 'f', JackDriverParamString, &value, NULL, "Multicast interface name or any", "Multicast interface to send probes from (any - kernel chosen (default), if_name - from specified interface)");

value.i = DEFAULT_PORT;
jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);



+ 16
- 3
common/JackNetDriver.cpp View File

@@ -28,7 +28,7 @@ using namespace std;
namespace Jack
{
JackNetDriver::JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
const char* ip, int udp_port, int mtu, int midi_input_ports, int midi_output_ports,
const char* ip, int udp_port, const char* mcif, int mtu, int midi_input_ports, int midi_output_ports,
char* net_name, uint transport_sync, int network_latency,
int celt_encoding, int opus_encoding, bool auto_save)
: JackWaiterDriver(name, alias, engine, table), JackNetSlaveInterface(ip, udp_port)
@@ -39,6 +39,8 @@ namespace Jack
if (strcmp(net_name, "") == 0) {
GetHostName(net_name, JACK_CLIENT_NAME_SIZE);
}
if(strcmp(mcif,DEFAULT_MULTICAST_IF))
strcpy(fMulticastIF,mcif);

fParams.fMtu = mtu;
@@ -676,6 +678,9 @@ namespace Jack
strcpy(value.str, DEFAULT_MULTICAST_IP);
jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address, or explicit IP of the master", NULL);

strcpy(value.str, DEFAULT_MULTICAST_IF);
jack_driver_descriptor_add_parameter(desc, &filler, "multicast-if", 'f', JackDriverParamString, &value, NULL, "Multicast interface name or any", "Multicast interface to send probes from (any - kernel chosen (default), if_name - send from specified interface)");

value.i = DEFAULT_PORT;
jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);

@@ -719,8 +724,9 @@ Deactivated for now..

SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
{
char multicast_if[32];
char multicast_ip[32];
char net_name[JACK_CLIENT_NAME_SIZE+1] = {0};
char net_name[JACK_CLIENT_NAME_SIZE + 1] = {0};
int udp_port;
int mtu = DEFAULT_MTU;
// Desactivated for now...
@@ -747,6 +753,9 @@ Deactivated for now..
const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
strcpy(multicast_ip, (default_multicast_ip) ? default_multicast_ip : DEFAULT_MULTICAST_IP);
const char* default_multicast_if = getenv("JACK_NETJACK_INTERFACE");
strcpy(multicast_if, (default_multicast_if) ? default_multicast_if : DEFAULT_MULTICAST_IF);

for (node = params; node; node = jack_slist_next(node)) {
param = (const jack_driver_param_t*) node->data;
switch (param->character)
@@ -755,6 +764,10 @@ Deactivated for now..
assert(strlen(param->value.str) < 32);
strcpy(multicast_ip, param->value.str);
break;
case 'f' :
assert(strlen(param->value.str) < 32);
strcpy(multicast_if, param->value.str);
break;
case 'p':
udp_port = param->value.ui;
break;
@@ -808,7 +821,7 @@ Deactivated for now..
try {

Jack::JackDriverClientInterface* driver = new Jack::JackWaitThreadedDriver(
new Jack::JackNetDriver("system", "net_pcm", engine, table, multicast_ip, udp_port, mtu,
new Jack::JackNetDriver("system", "net_pcm", engine, table, multicast_ip, udp_port, multicast_if, mtu,
midi_input_ports, midi_output_ports,
net_name, transport_sync,
network_latency, celt_encoding, opus_encoding, auto_save));


+ 1
- 1
common/JackNetDriver.h View File

@@ -79,7 +79,7 @@ namespace Jack
public:

JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
const char* ip, int port, int mtu, int midi_input_ports, int midi_output_ports,
const char* ip, int port, const char* mcif, int mtu, int midi_input_ports, int midi_output_ports,
char* net_name, uint transport_sync, int network_latency, int celt_encoding,
int opus_encoding, bool auto_save);
virtual ~JackNetDriver();


+ 8
- 2
common/JackNetInterface.cpp View File

@@ -57,6 +57,7 @@ namespace Jack
fSetTimeOut = false;
fTxBuffer = NULL;
fRxBuffer = NULL;
fMulticastIF[0]=0;
fNetAudioCaptureBuffer = NULL;
fNetAudioPlaybackBuffer = NULL;
fNetMidiCaptureBuffer = NULL;
@@ -700,6 +701,12 @@ namespace Jack

if (fSocket.IsLocal(fMulticastIP)) {
jack_info("Local IP is used...");
} else if (fMulticastIF[0]) {
// bind the socket & interface
if (fSocket.Bind(fMulticastIF) == SOCKET_ERROR) {
jack_error("Can't bind the socket : %s", StrError(NET_ERROR_CODE));
return NET_SOCKET_ERROR;
}
} else {
// bind the socket
if (fSocket.Bind() == SOCKET_ERROR) {
@@ -719,8 +726,7 @@ namespace Jack
}

// send 'AVAILABLE' until 'SLAVE_SETUP' received
jack_info("Waiting for a master...");
jack_info("Waiting for a master on %s...",(fMulticastIF[0])?fMulticastIF:"default");
do {
// send 'available'
session_params_t net_params;


+ 4
- 0
common/JackNetInterface.h View File

@@ -26,7 +26,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
namespace Jack
{

// Should be registered at IANA perhaps
#define DEFAULT_MULTICAST_IP6 "FF05::139a"
#define DEFAULT_MULTICAST_IP "225.3.19.154"
#define DEFAULT_MULTICAST_IF "any"
#define DEFAULT_PORT 19000
#define DEFAULT_MTU 1500
#define MAX_MTU 9000
@@ -60,6 +63,7 @@ namespace Jack
session_params_t fParams;
JackNetSocket fSocket;
char fMulticastIP[32];
char fMulticastIF[32];

// headers
packet_header_t fTxHeader;


+ 24
- 5
common/JackNetManager.cpp View File

@@ -505,7 +505,7 @@ namespace Jack
if (out) {
memset(out, 0, sizeof(float) * fParams.fPeriodSize);
}
fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out)));
fNetAudioPlaybackBuffer->SetBuffer(audio_port_index, out);
#endif
}

@@ -660,6 +660,13 @@ namespace Jack
strcpy(fMulticastIP, DEFAULT_MULTICAST_IP);
}

const char* default_multicast_if = getenv("JACK_NETJACK_INTERFACE");
if (default_multicast_if) {
strcpy(fMulticastIF, default_multicast_if);
} else {
strcpy(fMulticastIF, DEFAULT_MULTICAST_IF);
}

for (node = params; node; node = jack_slist_next(node)) {

param = (const jack_driver_param_t*) node->data;
@@ -672,6 +679,14 @@ namespace Jack
}
break;

case 'f' :
if (strlen(param->value.str) < 32) {
strcpy(fMulticastIF, param->value.str);
} else {
jack_error("Can't use multicast interface %s, using default %s", param->value.ui, DEFAULT_MULTICAST_IF);
}
break;

case 'p':
fSocket.SetPort(param->value.ui);
break;
@@ -761,7 +776,7 @@ namespace Jack
{
JackNetMasterManager* master_manager = static_cast<JackNetMasterManager*>(arg);
jack_info("Starting Jack NetManager");
jack_info("Listening on '%s:%d'", master_manager->fMulticastIP, master_manager->fSocket.GetPort());
jack_info("Listening on '%s:%d%%%s'", master_manager->fMulticastIP, master_manager->fSocket.GetPort(),master_manager->fMulticastIF);
master_manager->Run();
return NULL;
}
@@ -783,8 +798,8 @@ namespace Jack
return;
}

//socket
if (fSocket.NewSocket() == SOCKET_ERROR) {
//socket: we need to have socket probed first if we want to use multicast
if (fSocket.NewSocket(fMulticastIP) == SOCKET_ERROR) {
jack_error("Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE));
return;
}
@@ -797,7 +812,7 @@ namespace Jack
}

//join multicast group
if (fSocket.JoinMCastGroup(fMulticastIP) == SOCKET_ERROR) {
if (fSocket.JoinMCastGroup(fMulticastIP,fMulticastIF) == SOCKET_ERROR) {
jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
}

@@ -843,6 +858,7 @@ namespace Jack
}
break;
default:
jack_log("JackNetMasterManager::Run: read: %d; type: %d; peer: %s",rx_bytes,host_params.fPacketID,host_params.fName);
break;
}
}
@@ -949,6 +965,9 @@ extern "C"
strcpy(value.str, DEFAULT_MULTICAST_IP);
jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address", NULL);

strcpy(value.str, DEFAULT_MULTICAST_IF);
jack_driver_descriptor_add_parameter(desc, &filler, "multicast-if", 'f', JackDriverParamString, &value, NULL, "Multicast interface", "Multicast interface to bind to. ('all' - all ip ifs; 'any' (default) kernel chosen; ifname i.e. eth0)");

value.i = DEFAULT_PORT;
jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL);



+ 1
- 0
common/JackNetManager.h View File

@@ -112,6 +112,7 @@ namespace Jack
jack_client_t* fClient;
const char* fName;
char fMulticastIP[32];
char fMulticastIF[32];
JackNetSocket fSocket;
jack_native_thread_t fThread;
master_list_t fMasterList;


+ 0
- 2
common/JackNetTool.h View File

@@ -56,8 +56,6 @@ namespace Jack
typedef struct _session_params session_params_t;
typedef struct _packet_header packet_header_t;
typedef struct _net_transport_data net_transport_data_t;
typedef struct sockaddr socket_address_t;
typedef struct in_addr address_t;
typedef jack_default_audio_sample_t sample_t;

enum JackNetEncoder {


+ 386
- 113
posix/JackNetUnixSocket.cpp View File

@@ -20,11 +20,27 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "JackNetUnixSocket.h"
#include "JackError.h"

#include <arpa/inet.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <unistd.h>
#include <fcntl.h>

using namespace std;

// See RFC 3493; The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 Edition
#define _sock4(x) (*(struct sockaddr_in *)&x)
#define _sock6(x) (*(struct sockaddr_in6*)&x)
#define _ss_addr_p(x) ((fFamily==AF_INET6) ? \
(void*)&(((struct sockaddr_in6*)&x)->sin6_addr) \
: (void*)&(((struct sockaddr_in *)&x)->sin_addr))
#define JNS_UNSPEC 0x0
#define JNS_PROBED 0x1
#define JNS_BOUND 0x2
#define JNS_CONNCD 0x4
#define JNS_MCAST 0x10

namespace Jack
{
//utility *********************************************************************************************************
@@ -40,40 +56,23 @@ namespace Jack

//construct/destruct***********************************************************************************************
JackNetUnixSocket::JackNetUnixSocket()
: fFamily(AF_UNSPEC), fSockfd(0), fState(JNS_UNSPEC), fPort(0), fTimeOut(0)
{
fSockfd = 0;
fPort = 0;
fTimeOut = 0;
fSendAddr.sin_family = AF_INET;
fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&fSendAddr.sin_zero, 0, 8);
fRecvAddr.sin_family = AF_INET;
fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&fRecvAddr.sin_zero, 0, 8);
Reset();
}

JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
: fFamily(AF_UNSPEC), fSockfd(0), fState(JNS_UNSPEC), fPort(0), fTimeOut(0)
{
fSockfd = 0;
Reset();
fPort = port;
fTimeOut = 0;
fSendAddr.sin_family = AF_INET;
fSendAddr.sin_port = htons(port);
inet_aton(ip, &fSendAddr.sin_addr);
memset(&fSendAddr.sin_zero, 0, 8);
fRecvAddr.sin_family = AF_INET;
fRecvAddr.sin_port = htons(port);
fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&fRecvAddr.sin_zero, 0, 8);
if(NewSocket(ip)==SOCKET_ERROR)
jack_error("JackNetUnixSocket::JackNetUnixSocket Cannot initialize (%s:%d): %s",ip,port,strerror(NET_ERROR_CODE));
}

JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
{
fSockfd = 0;
fTimeOut = 0;
fPort = socket.fPort;
fSendAddr = socket.fSendAddr;
fRecvAddr = socket.fRecvAddr;
Clone(socket);
}

JackNetUnixSocket::~JackNetUnixSocket()
@@ -83,23 +82,106 @@ namespace Jack

JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket)
{
if (this != &socket) {
fSockfd = 0;
fPort = socket.fPort;
fSendAddr = socket.fSendAddr;
fRecvAddr = socket.fRecvAddr;
}
if (this != &socket)
Clone(socket);
return *this;
}

//socket***********************************************************************************************************
void JackNetUnixSocket::Clone(const JackNetUnixSocket& socket)
{
fSockfd = 0;
fTimeOut = 0;
fPort = socket.fPort;
fFamily = socket.fFamily;
fState = socket.fState;
fState &= (JNS_MCAST | JNS_PROBED); // Reset all fields except mcast and probed
memcpy(&fSendAddr, & socket.fSendAddr, sizeof(fSendAddr));
memcpy(&fRecvAddr, & socket.fRecvAddr, sizeof(fRecvAddr));
}
/* When using Multicast always create socket with new (mip,port) or call NewSocket(mip) for autoinitialized sockets first.
* This makes sure proper workarounds for Multicast incompatibility will be activated while setting up address family.
*/
int JackNetUnixSocket::ProbeAF(const char* ip, struct sockaddr_storage *addr, int (*call)(int,const struct sockaddr*,socklen_t))
{
struct addrinfo hint,*res, *ri;
char sport[6];
int ret;

snprintf(sport,6,"%d",fPort);
memset(&hint,0,sizeof(hint));
hint.ai_family = fFamily;
hint.ai_socktype = SOCK_DGRAM;
hint.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICSERV;
if(ip == NULL) hint.ai_flags |= AI_PASSIVE;
ret = getaddrinfo(ip,sport,&hint,&res);
if(ret) {
jack_error("JackNetUnixSocket::ProbeAF getaddrinfo(%s:%s): %s",ip,sport,gai_strerror(ret));
return ret;
}
#define GLIBC_BUG
// An ugly GLIBC bug, which one may argue to be RFC bug. See http://sourceware.org/bugzilla/show_bug.cgi?id=14967
#ifdef GLIBC_BUG
// Of course gai configuration can say to have v4 having precedence explicitly but... here we prefer ipv6. period
if(!ip && res->ai_family == AF_INET && res->ai_next && res->ai_next->ai_family == AF_INET6) {
jack_log("JackNetUnixSocket::ProbeAF swapping addrinfo entries to work around GLIBC getaddrinfo bug: AF_INET<->AF_INET6");
// Swapping first two entries
ri = res->ai_next;
res->ai_next = ri->ai_next;
ri->ai_next = res;
res = ri;
} else // << Remove up to this very line including once GLIBC is fixed <<
#endif
ri = res;
do {
jack_log("JackNetUnixSocket::ProbeAF trying AF[%d], TYPE[%d], PROTO[%d]",
ri->ai_family,ri->ai_socktype,ri->ai_protocol);
ret = socket(ri->ai_family, ri->ai_socktype, ri->ai_protocol);
if(ret < 0)
continue;
if(!(*call)(ret, ri->ai_addr, ri->ai_addrlen))
break;
close(ret);
jack_log("JackNetUnixSocket::ProbeAF failed for AF[%d], %s",ri->ai_family,(ri->ai_next)?"trying next":"giving up");
} while((ri = ri->ai_next) != NULL);
// probe successfully made a *call on socket for ip represented by ri
if(ri) {
fSockfd = ret;
fFamily = ri->ai_family;
memcpy(addr,ri->ai_addr,ri->ai_addrlen);
jack_log("JackNetUnixSocket::ProbeAF probed[%d] AF[%d] for %s",ret,fFamily,ip);
fState |= JNS_PROBED;
if(fFamily == AF_INET6 && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr))
fState |= JNS_MCAST;
} else
ret = SOCKET_ERROR;
freeaddrinfo(res);
return ret;
}

int JackNetUnixSocket::NewSocket()
{
return NewSocket(NULL);
}
int JackNetUnixSocket::NewSocket(const char *ip)
{
if(fFamily == AF_UNSPEC) {
if(ip) {
if(ProbeAF(ip,&fSendAddr,connect)<0)
return SOCKET_ERROR;
} else {
if(ProbeAF(ip,&fRecvAddr,bind)<0)
return SOCKET_ERROR;
// It should be with AF/port/ANY after bind
memcpy(&fSendAddr,&fRecvAddr,sizeof(fRecvAddr));
}
// Now re-create the fd to get a brand-new unnamed socket
}
if (fSockfd) {
Close();
Reset();
}
fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
fSockfd = socket(fFamily, SOCK_DGRAM, 0);

/* Enable address reuse */
int res, on = 1;
@@ -139,58 +221,117 @@ namespace Jack
{
if (strcmp(ip, "127.0.0.1") == 0) {
return true;
}
} else if(!strcmp(ip,"::1"))
return true;

char host_name[32];
gethostname(host_name, sizeof(host_name));
struct ifaddrs *ifas, *ifa;
socklen_t len;

struct hostent* host = gethostbyname(host_name);
if (host) {
for (int i = 0; host->h_addr_list[i] != 0; ++i) {
struct in_addr addr;
memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
if (strcmp(inet_ntoa(addr), ip) == 0) {
return true;
}
}
return false;
} else {
return false;
if (getifaddrs(&ifas) == -1) {
jack_error("JackNetUnixSocket::IsLocal error in getifaddrs");
return false;
}
for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue; // Address is mandatory
len = (ifa->ifa_addr->sa_family==AF_INET)?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6);
if(!getnameinfo(ifa->ifa_addr, len, f_addr_buff, INET6_ADDRSTRLEN, NULL,0, NI_NUMERICSERV | NI_DGRAM | NI_NUMERICSERV | NI_DGRAM | NI_NUMERICHOST))
if(!strcmp(f_addr_buff,ip))
break;
}
freeifaddrs(ifas);
return (ifa != NULL);
}

int JackNetUnixSocket::Bind()
{
return ::bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
int yes=1;
if(fState & JNS_BOUND) return 0;
// Multicast is incompatible with V4MAPPED or V4COMPAT addresses, if probe detected MC we need V6ONLY
if(fFamily == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&_sock6(fRecvAddr).sin6_addr) && fState & JNS_MCAST)
if(SetOption(IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) return SOCKET_ERROR;
if(::bind(fSockfd, reinterpret_cast<struct sockaddr*>(&fRecvAddr), sizeof(fRecvAddr))) return SOCKET_ERROR;
fState |= JNS_BOUND;
return 0;
}
int JackNetUnixSocket::Bind(const char *if_name)
{
int ret = Bind();
if(!ret && strcmp(if_name,"any")) {
if(fFamily == AF_INET) {
// 'all' for this case will lead to 'last valid interface', which is not that one might expect
if(strcmp(if_name,"all"))
ret = BindMCastIface(if_name, IP_MULTICAST_IF, &_sock4(fSendAddr).sin_addr);
else
jack_error("Multicast Interface all not found, sending from default");
} else if(fFamily == AF_INET6) {
struct if_nameindex *if_ni = if_nameindex(); // In V6 world we do everything differently.
if(if_ni) {
int i;
for (i=0; if_ni[i].if_index > 0; i++) {
if(if_ni[i].if_index == 1)
continue; // Skip loopback
if(!strcmp(if_ni[i].if_name,if_name)) {
ret = SetOption(IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_ni[i].if_index, sizeof(if_ni[i].if_index));
jack_log("JackNetUnixSocket::Bind Multicasting from %s",if_ni[i].if_name);
break;
}
}
if(if_ni[i].if_index == 0) jack_error("Multicast Interface %s not found, sending from default",if_name);
if_freenameindex(if_ni);
}
}
}
return ret;
}

int JackNetUnixSocket::BindWith(const char* ip)
{
int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
if (addr_conv < 0) {
return addr_conv;
if(fFamily == AF_UNSPEC) {
if(!fPort) return SOCKET_ERROR;
if(ProbeAF(ip,&fRecvAddr,&bind)<0) return SOCKET_ERROR;
fState |= JNS_BOUND;
return 0;
} else {
if(SetRecvIP(ip)==-1) return SOCKET_ERROR;
return Bind();
}
return Bind();
}

int JackNetUnixSocket::BindWith(int port)
{
fRecvAddr.sin_port = htons(port);
return Bind();
if(fFamily == AF_UNSPEC) {
fPort = port;
if(ProbeAF(NULL,&fRecvAddr,&bind)<0) return SOCKET_ERROR;
fState |= JNS_BOUND;
return 0;
} else {
SetPort(port);
return Bind();
}
}

int JackNetUnixSocket::Connect()
{
return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
if(fFamily != AF_UNSPEC)
return connect(fSockfd, (struct sockaddr*)&fSendAddr,sizeof(fSendAddr));
jack_error("JackNetUnixSocket::Connect Family not initialized");
return SOCKET_ERROR;
}

int JackNetUnixSocket::ConnectTo(const char* ip)
{
int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
if (addr_conv < 0) {
return addr_conv;
socklen_t l=sizeof(fRecvAddr);
if(fPort==0) return SOCKET_ERROR;
if(fState & JNS_PROBED) {
Reset();
fFamily=AF_UNSPEC;
}
return Connect();
if(fSockfd)
Close();
if(ProbeAF(ip,&fSendAddr,&connect)<0) return SOCKET_ERROR;
fState |= JNS_CONNCD;
return getsockname(fSockfd, (struct sockaddr *)&fRecvAddr, &l);
}

void JackNetUnixSocket::Close()
@@ -199,18 +340,17 @@ namespace Jack
close(fSockfd);
}
fSockfd = 0;
fState = JNS_UNSPEC;
}

void JackNetUnixSocket::Reset()
{
fSendAddr.sin_family = AF_INET;
fSendAddr.sin_port = htons(fPort);
fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&fSendAddr.sin_zero, 0, 8);
fRecvAddr.sin_family = AF_INET;
fRecvAddr.sin_port = htons(fPort);
fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&fRecvAddr.sin_zero, 0, 8);
memset(&fSendAddr, 0, sizeof(fSendAddr));
fSendAddr.ss_family = fFamily;
memset(&fRecvAddr, 0, sizeof(fRecvAddr));
fRecvAddr.ss_family = fFamily;
if(fPort)
SetPort(fPort);
}

bool JackNetUnixSocket::IsSocket()
@@ -222,8 +362,18 @@ namespace Jack
void JackNetUnixSocket::SetPort(int port)
{
fPort = port;
fSendAddr.sin_port = htons(port);
fRecvAddr.sin_port = htons(port);
switch(fFamily) { // Playing dumb here, in fact port section of both sockaddrs is compatible
case AF_INET:
_sock4(fSendAddr).sin_port = htons(port);
_sock4(fRecvAddr).sin_port = htons(port);
break;
case AF_INET6:
_sock6(fSendAddr).sin6_port = htons(port);
_sock6(fRecvAddr).sin6_port = htons(port);
break;
default:
jack_info("JackNetUnixSocket::SetPort: Family not initialized");
}
}

int JackNetUnixSocket::GetPort()
@@ -234,22 +384,34 @@ namespace Jack
//address***********************************************************************************************************
int JackNetUnixSocket::SetAddress(const char* ip, int port)
{
int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
if (addr_conv < 0) {
return addr_conv;
if(fFamily == AF_UNSPEC) {
fPort=port;
return ProbeAF(ip,&fSendAddr,&connect);
} else {
SetPort(port);
return inet_pton(fFamily, ip, _ss_addr_p(fSendAddr));
}
fSendAddr.sin_port = htons(port);
return 0;
}
int JackNetUnixSocket::SetSendIP(const char *ip)
{
if(fFamily == AF_UNSPEC) return -1;
return inet_pton(fFamily, ip, _ss_addr_p(fSendAddr));
}

char* JackNetUnixSocket::GetSendIP()
{
return inet_ntoa(fSendAddr.sin_addr);
return (char*)inet_ntop(fFamily, _ss_addr_p(fSendAddr),f_addr_buff,INET6_ADDRSTRLEN);
}

int JackNetUnixSocket::SetRecvIP(const char *ip)
{
if(fFamily == AF_UNSPEC) return -1;
return inet_pton(fFamily, ip, _ss_addr_p(fRecvAddr));
}

char* JackNetUnixSocket::GetRecvIP()
{
return inet_ntoa(fRecvAddr.sin_addr);
return (char*)inet_ntop(fFamily, _ss_addr_p(fRecvAddr),f_addr_buff,INET6_ADDRSTRLEN);
}

//utility************************************************************************************************************
@@ -260,10 +422,111 @@ namespace Jack

int JackNetUnixSocket::JoinMCastGroup(const char* ip)
{
struct ip_mreq multicast_req;
inet_aton(ip, &multicast_req.imr_multiaddr);
multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req));
return JoinMCastGroup(ip,"any");
}
/** Glory and shame of IPv6 interoperability: Multicast
* Not only API is completely incompatible, but even socket is incompatible. I.e. you cannot use V4MAPPED/COMPATIBLE
* sockets/sockaddress for Multicast. Any V4 address is just a legacy unicast socket for IPv6. Moreover, IPv6 API
* implementation itself is a big mess even though there's no time anymore and way back. Here we're using POSIX API.
* When dealing with Multicast - Address Family should be set once and forever for used multicast address. This
* implies we cannot use V4 addresses on V6 sockets. So multicast should have V6ONLY soscket option set to allow v6
* adapter, master or manager coexist on the same host. See ProbeAF/Bind for these tricks.
*/
int JackNetUnixSocket::JoinMCastGroup(const char* ip, const char *if_name)
{
int level, option, length;
void *mreq;
char addr[sizeof(in6_addr)];
inet_pton(fFamily, ip, addr);
if(!strcmp(if_name,"any")) { // UNSPEC binding we can do in-place using void pointers
if(fFamily == AF_INET) {
struct ip_mreq multicast_req;
multicast_req.imr_multiaddr.s_addr = *(uint32_t*)(addr);
multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
level = IPPROTO_IP;
option = IP_ADD_MEMBERSHIP;
mreq=&multicast_req;
length = sizeof(ip_mreq);
} else if(fFamily == AF_INET6) {
struct ipv6_mreq mreq6;
memcpy(&mreq6.ipv6mr_multiaddr,addr,sizeof(in6_addr));
mreq6.ipv6mr_interface = 0;
level = IPPROTO_IPV6;
option = IPV6_ADD_MEMBERSHIP;
mreq = &mreq6;
length = sizeof(ipv6_mreq);
} else {
jack_error("Unsupported family[%d]",fFamily);
return -1;
}
return SetOption(level, option, mreq, length);
} else { // For anything more complex need to call family-specific routine
if(fFamily == AF_INET)
return BindMCastIface(if_name, IP_ADD_MEMBERSHIP, (struct in_addr *)addr);
else if(fFamily == AF_INET6)
return BindMCast6Iface(if_name, (struct in6_addr *)addr);
else {
jack_error("Unsupported family[%d]",fFamily);
return -1;
}
}
}
int JackNetUnixSocket::BindMCastIface(const char *if_name, const int option, struct in_addr *addr)
{
struct ifaddrs *ifas, *ifa;
struct ip_mreq mreq;
int specific = strcmp("all",if_name);
int ret=-1;
char *if_last=(char *)"any";

if (getifaddrs(&ifas) == -1) {
jack_error("JackNetUnixSocket::BindMCastIface error in getifaddrs");
return -1;
}
mreq.imr_multiaddr.s_addr = addr->s_addr;
for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue; // Address is mandatory
if(!ifa->ifa_name || !strcmp(if_last,ifa->ifa_name))
continue; // Name as well, also skip already enabled interface
if(!(ifa->ifa_flags & IFF_MULTICAST) || !(ifa->ifa_flags & IFF_RUNNING))
continue; // And non multicast or down interface
if(ifa->ifa_addr->sa_family != AF_INET)
continue; // And non-matching family
if(!specific || !strcmp(ifa->ifa_name,if_name)) {
mreq.imr_interface.s_addr = ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr;
ret = SetOption(IPPROTO_IP, option, &mreq, sizeof(struct ip_mreq));
if(ret)
break;
if_last = ifa->ifa_name;
jack_log("JackNetUnixSocket::BindMCastIface attaching to %s", if_last);
}
}
freeifaddrs(ifas);
if(!strcmp(if_last,"any"))
jack_error("JackNetUnixSocket::BindMCastIface cannot find valid interface");
return ret;
}
int JackNetUnixSocket::BindMCast6Iface(const char *if_name, struct in6_addr *mip)
{
int i, ret=-1, specific=strcmp("all",if_name);
struct if_nameindex *if_ni = if_nameindex();
struct ipv6_mreq mreq;
if(if_ni) {
memcpy(&mreq.ipv6mr_multiaddr, mip, sizeof(struct in6_addr));
for (i=0; if_ni[i].if_index > 0; i++) {
if(if_ni[i].if_index == 1)
continue; // Skip loopback
mreq.ipv6mr_interface = if_ni[i].if_index;
if(!specific || !strcmp(if_ni[i].if_name,if_name)) {
ret = SetOption(IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
if(ret < 0)
break;
}
}
if_freenameindex(if_ni);
}
return ret;
}

//options************************************************************************************************************
@@ -282,19 +545,19 @@ namespace Jack
#if defined(__sun__) || defined(sun)
int JackNetUnixSocket::SetTimeOut(int us)
{
int flags;
int flags;
fTimeOut = us;

if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
return -1;
}
jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
return -1;
}

flags |= O_NONBLOCK;
if (fcntl(fSockfd, F_SETFL, flags) < 0) {
jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
return 1;
}
flags |= O_NONBLOCK;
if (fcntl(fSockfd, F_SETFL, flags) < 0) {
jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
return 1;
}

return 0;
}
@@ -304,25 +567,25 @@ namespace Jack
if (fTimeOut > 0) {

struct timeval tv;
fd_set fdset;
ssize_t res;
fd_set fdset;
ssize_t res;

tv.tv_sec = fTimeOut / 1000000;
tv.tv_usec = fTimeOut % 1000000;
tv.tv_usec = fTimeOut % 1000000;

FD_ZERO(&fdset);
FD_SET(fSockfd, &fdset);
FD_ZERO(&fdset);
FD_SET(fSockfd, &fdset);

do {
res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
} while (res < 0 && errno == EINTR);

if (res < 0) {
return res;
if (res < 0) {
return res;
} else if (res == 0) {
errno = ETIMEDOUT;
return -1;
}
return -1;
}
}

return 0;
@@ -333,25 +596,25 @@ namespace Jack
if (fTimeOut > 0) {

struct timeval tv;
fd_set fdset;
ssize_t res;
fd_set fdset;
ssize_t res;

tv.tv_sec = fTimeOut / 1000000;
tv.tv_usec = fTimeOut % 1000000;

FD_ZERO(&fdset);
FD_SET(fSockfd, &fdset);
FD_ZERO(&fdset);
FD_SET(fSockfd, &fdset);

do {
res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
} while (res < 0 && errno == EINTR);

if (res < 0) {
return res;
if (res < 0) {
return res;
} else if (res == 0) {
errno = ETIMEDOUT;
return -1;
}
return -1;
}
}

return 0;
@@ -382,7 +645,16 @@ namespace Jack
int JackNetUnixSocket::SetLocalLoop()
{
char disable = 0;
return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
unsigned int dis6 = 0;
switch(fFamily) {
case AF_INET:
return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
case AF_INET6:
return SetOption(IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &dis6, sizeof(dis6));
default:
jack_error("JackNetUnixSocket::SetLocalLoop: Family not initialized");
return -1;
}
}

//network operations**************************************************************************************************
@@ -394,7 +666,7 @@ namespace Jack
}
#endif
int res;
if ((res = sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t))) < 0) {
if ((res = sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<struct sockaddr *>(&fSendAddr), sizeof(fSendAddr))) < 0) {
jack_error("SendTo fd = %ld err = %s", fSockfd, strerror(errno));
}
return res;
@@ -402,11 +674,11 @@ namespace Jack

int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
{
int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
int addr_conv = inet_pton(fFamily, ip, _ss_addr_p(fSendAddr));
if (addr_conv < 1) {
return addr_conv;
}
fSendAddr.sin_port = htons(fPort);
//fSendAddr.sin_port = htons(fPort);
#if defined(__sun__) || defined(sun)
if (WaitWrite() < 0) {
return -1;
@@ -431,14 +703,14 @@ namespace Jack

int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
{
socklen_t addr_len = sizeof(socket_address_t);
socklen_t addr_len = sizeof(fRecvAddr);
#if defined(__sun__) || defined(sun)
if (WaitRead() < 0) {
return -1;
}
#endif
int res;
if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fRecvAddr), &addr_len)) < 0) {
if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<struct sockaddr *>(&fRecvAddr), &addr_len)) < 0) {
jack_error("RecvFrom fd = %ld err = %s", fSockfd, strerror(errno));
}
return res;
@@ -460,14 +732,15 @@ namespace Jack

int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
{
socklen_t addr_len = sizeof(socket_address_t);
jack_log("JackNetUnixSocket::CatchHost");
socklen_t addr_len = sizeof(fSendAddr);
#if defined(__sun__) || defined(sun)
if (WaitRead() < 0) {
return -1;
}
#endif
int res;
if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len)) < 0) {
if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<struct sockaddr *>(&fSendAddr), &addr_len)) < 0) {
jack_log("CatchHost fd = %ld err = %s", fSockfd, strerror(errno));
}
return res;


+ 18
- 6
posix/JackNetUnixSocket.h View File

@@ -33,20 +33,27 @@ namespace Jack
#define SOCKET_ERROR -1
#define StrError strerror

typedef struct sockaddr socket_address_t;
typedef struct in_addr address_t;

//JackNetUnixSocket********************************************
class SERVER_EXPORT JackNetUnixSocket
{
private:
protected:

int fFamily;
int fSockfd;
int fState;
int fPort;
int fTimeOut;
struct sockaddr_storage fSendAddr;
struct sockaddr_storage fRecvAddr;
void Clone(const JackNetUnixSocket& socket);
int ProbeAF(const char* ip, struct sockaddr_storage *addr, int (*call)(int, const struct sockaddr*, socklen_t));
int BindMCastIface(const char *if_name, const int option, struct in_addr *addr);
int BindMCast6Iface(const char *if_name, struct in6_addr *addr);

private:

char f_addr_buff[INET6_ADDRSTRLEN];

struct sockaddr_in fSendAddr;
struct sockaddr_in fRecvAddr;
#if defined(__sun__) || defined(sun)
int WaitRead();
int WaitWrite();
@@ -62,8 +69,10 @@ namespace Jack
JackNetUnixSocket& operator=(const JackNetUnixSocket& socket);

//socket management
int NewSocket(const char *ip);
int NewSocket();
int Bind();
int Bind(const char *if_name);
int BindWith(const char* ip);
int BindWith(int port);
int Connect();
@@ -79,11 +88,14 @@ namespace Jack
//address management
int SetAddress(const char* ip, int port);
char* GetSendIP();
int SetSendIP(const char *ip);
char* GetRecvIP();
int SetRecvIP(const char *ip);

//utility
int GetName(char* name);
int JoinMCastGroup(const char* mcast_ip);
int JoinMCastGroup(const char* mcast_ip, const char* if_name);

//options management
int SetOption(int level, int optname, const void* optval, socklen_t optlen);


Loading…
Cancel
Save