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, 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. and then JackNetSlaveInterface will be filled with proper values.
*/ */
char multicast_ip[32];
char multicast_ip[32],multicast_if[32];
uint udp_port; uint udp_port;
GetHostName(fParams.fName, JACK_CLIENT_NAME_SIZE); GetHostName(fParams.fName, JACK_CLIENT_NAME_SIZE);
fSocket.GetName(fParams.fSlaveNetName); fSocket.GetName(fParams.fSlaveNetName);
@@ -58,11 +58,10 @@ namespace Jack
udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT; udp_port = (default_udp_port) ? atoi(default_udp_port) : DEFAULT_PORT;


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


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


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


// If not set, takes default // If not set, takes default
@@ -424,6 +428,9 @@ extern "C"
strcpy(value.str, DEFAULT_MULTICAST_IP); 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); 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; value.i = DEFAULT_PORT;
jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL); 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 namespace Jack
{ {
JackNetDriver::JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, 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, char* net_name, uint transport_sync, int network_latency,
int celt_encoding, int opus_encoding, bool auto_save) int celt_encoding, int opus_encoding, bool auto_save)
: JackWaiterDriver(name, alias, engine, table), JackNetSlaveInterface(ip, udp_port) : JackWaiterDriver(name, alias, engine, table), JackNetSlaveInterface(ip, udp_port)
@@ -39,6 +39,8 @@ namespace Jack
if (strcmp(net_name, "") == 0) { if (strcmp(net_name, "") == 0) {
GetHostName(net_name, JACK_CLIENT_NAME_SIZE); GetHostName(net_name, JACK_CLIENT_NAME_SIZE);
} }
if(strcmp(mcif,DEFAULT_MULTICAST_IF))
strcpy(fMulticastIF,mcif);


fParams.fMtu = mtu; fParams.fMtu = mtu;
@@ -676,6 +678,9 @@ namespace Jack
strcpy(value.str, DEFAULT_MULTICAST_IP); 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); 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; value.i = DEFAULT_PORT;
jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL); 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) SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
{ {
char multicast_if[32];
char multicast_ip[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 udp_port;
int mtu = DEFAULT_MTU; int mtu = DEFAULT_MTU;
// Desactivated for now... // Desactivated for now...
@@ -747,6 +753,9 @@ Deactivated for now..
const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST"); const char* default_multicast_ip = getenv("JACK_NETJACK_MULTICAST");
strcpy(multicast_ip, (default_multicast_ip) ? default_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);

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


Jack::JackDriverClientInterface* driver = new Jack::JackWaitThreadedDriver( 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, midi_input_ports, midi_output_ports,
net_name, transport_sync, net_name, transport_sync,
network_latency, celt_encoding, opus_encoding, auto_save)); network_latency, celt_encoding, opus_encoding, auto_save));


+ 1
- 1
common/JackNetDriver.h View File

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


JackNetDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, 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, char* net_name, uint transport_sync, int network_latency, int celt_encoding,
int opus_encoding, bool auto_save); int opus_encoding, bool auto_save);
virtual ~JackNetDriver(); virtual ~JackNetDriver();


+ 8
- 2
common/JackNetInterface.cpp View File

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


if (fSocket.IsLocal(fMulticastIP)) { if (fSocket.IsLocal(fMulticastIP)) {
jack_info("Local IP is used..."); 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 { } else {
// bind the socket // bind the socket
if (fSocket.Bind() == SOCKET_ERROR) { if (fSocket.Bind() == SOCKET_ERROR) {
@@ -719,8 +726,7 @@ namespace Jack
} }


// send 'AVAILABLE' until 'SLAVE_SETUP' received // 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 { do {
// send 'available' // send 'available'
session_params_t net_params; 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 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_IP "225.3.19.154"
#define DEFAULT_MULTICAST_IF "any"
#define DEFAULT_PORT 19000 #define DEFAULT_PORT 19000
#define DEFAULT_MTU 1500 #define DEFAULT_MTU 1500
#define MAX_MTU 9000 #define MAX_MTU 9000
@@ -60,6 +63,7 @@ namespace Jack
session_params_t fParams; session_params_t fParams;
JackNetSocket fSocket; JackNetSocket fSocket;
char fMulticastIP[32]; char fMulticastIP[32];
char fMulticastIF[32];


// headers // headers
packet_header_t fTxHeader; packet_header_t fTxHeader;


+ 24
- 5
common/JackNetManager.cpp View File

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


@@ -660,6 +660,13 @@ namespace Jack
strcpy(fMulticastIP, DEFAULT_MULTICAST_IP); 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)) { for (node = params; node; node = jack_slist_next(node)) {


param = (const jack_driver_param_t*) node->data; param = (const jack_driver_param_t*) node->data;
@@ -672,6 +679,14 @@ namespace Jack
} }
break; 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': case 'p':
fSocket.SetPort(param->value.ui); fSocket.SetPort(param->value.ui);
break; break;
@@ -761,7 +776,7 @@ namespace Jack
{ {
JackNetMasterManager* master_manager = static_cast<JackNetMasterManager*>(arg); JackNetMasterManager* master_manager = static_cast<JackNetMasterManager*>(arg);
jack_info("Starting Jack NetManager"); 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(); master_manager->Run();
return NULL; return NULL;
} }
@@ -783,8 +798,8 @@ namespace Jack
return; 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)); jack_error("Can't create NetManager input socket : %s", StrError(NET_ERROR_CODE));
return; return;
} }
@@ -797,7 +812,7 @@ namespace Jack
} }


//join multicast group //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)); jack_error("Can't join multicast group : %s", StrError(NET_ERROR_CODE));
} }


@@ -843,6 +858,7 @@ namespace Jack
} }
break; break;
default: default:
jack_log("JackNetMasterManager::Run: read: %d; type: %d; peer: %s",rx_bytes,host_params.fPacketID,host_params.fName);
break; break;
} }
} }
@@ -949,6 +965,9 @@ extern "C"
strcpy(value.str, DEFAULT_MULTICAST_IP); strcpy(value.str, DEFAULT_MULTICAST_IP);
jack_driver_descriptor_add_parameter(desc, &filler, "multicast-ip", 'a', JackDriverParamString, &value, NULL, "Multicast address", NULL); 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; value.i = DEFAULT_PORT;
jack_driver_descriptor_add_parameter(desc, &filler, "udp-net-port", 'p', JackDriverParamInt, &value, NULL, "UDP port", NULL); 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; jack_client_t* fClient;
const char* fName; const char* fName;
char fMulticastIP[32]; char fMulticastIP[32];
char fMulticastIF[32];
JackNetSocket fSocket; JackNetSocket fSocket;
jack_native_thread_t fThread; jack_native_thread_t fThread;
master_list_t fMasterList; 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 _session_params session_params_t;
typedef struct _packet_header packet_header_t; typedef struct _packet_header packet_header_t;
typedef struct _net_transport_data net_transport_data_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; typedef jack_default_audio_sample_t sample_t;


enum JackNetEncoder { 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 "JackNetUnixSocket.h"
#include "JackError.h" #include "JackError.h"


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


using namespace std; 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 namespace Jack
{ {
//utility ********************************************************************************************************* //utility *********************************************************************************************************
@@ -40,40 +56,23 @@ namespace Jack


//construct/destruct*********************************************************************************************** //construct/destruct***********************************************************************************************
JackNetUnixSocket::JackNetUnixSocket() 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) JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
: fFamily(AF_UNSPEC), fSockfd(0), fState(JNS_UNSPEC), fPort(0), fTimeOut(0)
{ {
fSockfd = 0;
Reset();
fPort = port; 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) JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
{ {
fSockfd = 0;
fTimeOut = 0;
fPort = socket.fPort;
fSendAddr = socket.fSendAddr;
fRecvAddr = socket.fRecvAddr;
Clone(socket);
} }


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


JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket) 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; return *this;
} }


//socket*********************************************************************************************************** //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() 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) { if (fSockfd) {
Close(); Close();
Reset(); Reset();
} }
fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
fSockfd = socket(fFamily, SOCK_DGRAM, 0);


/* Enable address reuse */ /* Enable address reuse */
int res, on = 1; int res, on = 1;
@@ -139,58 +221,117 @@ namespace Jack
{ {
if (strcmp(ip, "127.0.0.1") == 0) { if (strcmp(ip, "127.0.0.1") == 0) {
return true; 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() 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 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) 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() 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 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() void JackNetUnixSocket::Close()
@@ -199,18 +340,17 @@ namespace Jack
close(fSockfd); close(fSockfd);
} }
fSockfd = 0; fSockfd = 0;
fState = JNS_UNSPEC;
} }


void JackNetUnixSocket::Reset() 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() bool JackNetUnixSocket::IsSocket()
@@ -222,8 +362,18 @@ namespace Jack
void JackNetUnixSocket::SetPort(int port) void JackNetUnixSocket::SetPort(int port)
{ {
fPort = 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() int JackNetUnixSocket::GetPort()
@@ -234,22 +384,34 @@ namespace Jack
//address*********************************************************************************************************** //address***********************************************************************************************************
int JackNetUnixSocket::SetAddress(const char* ip, int port) 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() 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() char* JackNetUnixSocket::GetRecvIP()
{ {
return inet_ntoa(fRecvAddr.sin_addr);
return (char*)inet_ntop(fFamily, _ss_addr_p(fRecvAddr),f_addr_buff,INET6_ADDRSTRLEN);
} }


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


int JackNetUnixSocket::JoinMCastGroup(const char* ip) 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************************************************************************************************************ //options************************************************************************************************************
@@ -282,19 +545,19 @@ namespace Jack
#if defined(__sun__) || defined(sun) #if defined(__sun__) || defined(sun)
int JackNetUnixSocket::SetTimeOut(int us) int JackNetUnixSocket::SetTimeOut(int us)
{ {
int flags;
int flags;
fTimeOut = us; fTimeOut = us;


if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) { 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; return 0;
} }
@@ -304,25 +567,25 @@ namespace Jack
if (fTimeOut > 0) { if (fTimeOut > 0) {


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


tv.tv_sec = fTimeOut / 1000000; 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 { do {
res = select(fSockfd + 1, &fdset, NULL, NULL, &tv); res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
} while (res < 0 && errno == EINTR); } while (res < 0 && errno == EINTR);


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


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


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


tv.tv_sec = fTimeOut / 1000000; 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 { do {
res = select(fSockfd + 1, NULL, &fdset, NULL, &tv); res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
} while (res < 0 && errno == EINTR); } while (res < 0 && errno == EINTR);


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


return 0; return 0;
@@ -382,7 +645,16 @@ namespace Jack
int JackNetUnixSocket::SetLocalLoop() int JackNetUnixSocket::SetLocalLoop()
{ {
char disable = 0; 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************************************************************************************************** //network operations**************************************************************************************************
@@ -394,7 +666,7 @@ namespace Jack
} }
#endif #endif
int res; 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)); jack_error("SendTo fd = %ld err = %s", fSockfd, strerror(errno));
} }
return res; return res;
@@ -402,11 +674,11 @@ namespace Jack


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


int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags) 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 defined(__sun__) || defined(sun)
if (WaitRead() < 0) { if (WaitRead() < 0) {
return -1; return -1;
} }
#endif #endif
int res; 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)); jack_error("RecvFrom fd = %ld err = %s", fSockfd, strerror(errno));
} }
return res; return res;
@@ -460,14 +732,15 @@ namespace Jack


int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags) 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 defined(__sun__) || defined(sun)
if (WaitRead() < 0) { if (WaitRead() < 0) {
return -1; return -1;
} }
#endif #endif
int res; 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)); jack_log("CatchHost fd = %ld err = %s", fSockfd, strerror(errno));
} }
return res; return res;


+ 18
- 6
posix/JackNetUnixSocket.h View File

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


typedef struct sockaddr socket_address_t;
typedef struct in_addr address_t;

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


int fFamily;
int fSockfd; int fSockfd;
int fState;
int fPort; int fPort;
int fTimeOut; 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) #if defined(__sun__) || defined(sun)
int WaitRead(); int WaitRead();
int WaitWrite(); int WaitWrite();
@@ -62,8 +69,10 @@ namespace Jack
JackNetUnixSocket& operator=(const JackNetUnixSocket& socket); JackNetUnixSocket& operator=(const JackNetUnixSocket& socket);


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


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


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


Loading…
Cancel
Save