summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Brand <tom@trellis.ch>2019-02-08 21:16:28 +0100
committerThomas Brand <tom@trellis.ch>2019-02-08 21:16:28 +0100
commit40cb345a38f120fac0fecd130fcd10424a03abfd (patch)
treede9ace5b6a55d045461524e6e985a0496ff6ac64
parenta752bfaa618457ea9ad366794f0751cc96ba2578 (diff)
downloadjack2-40cb345a38f120fac0fecd130fcd10424a03abfd.tar.gz
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();
-rw-r--r--common/JackNetAdapter.cpp21
-rw-r--r--common/JackNetDriver.cpp19
-rw-r--r--common/JackNetDriver.h2
-rw-r--r--common/JackNetInterface.cpp10
-rw-r--r--common/JackNetInterface.h4
-rw-r--r--common/JackNetManager.cpp29
-rw-r--r--common/JackNetManager.h1
-rw-r--r--common/JackNetTool.h2
-rw-r--r--posix/JackNetUnixSocket.cpp499
-rw-r--r--posix/JackNetUnixSocket.h24
10 files changed, 472 insertions, 139 deletions
diff --git a/common/JackNetAdapter.cpp b/common/JackNetAdapter.cpp
index 37dcd628..7e946360 100644
--- a/common/JackNetAdapter.cpp
+++ b/common/JackNetAdapter.cpp
@@ -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);
diff --git a/common/JackNetDriver.cpp b/common/JackNetDriver.cpp
index 3918582c..02de7648 100644
--- a/common/JackNetDriver.cpp
+++ b/common/JackNetDriver.cpp
@@ -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));
diff --git a/common/JackNetDriver.h b/common/JackNetDriver.h
index da65a13b..64f58c29 100644
--- a/common/JackNetDriver.h
+++ b/common/JackNetDriver.h
@@ -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();
diff --git a/common/JackNetInterface.cpp b/common/JackNetInterface.cpp
index fdf94fa1..c3063dbe 100644
--- a/common/JackNetInterface.cpp
+++ b/common/JackNetInterface.cpp
@@ -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;
diff --git a/common/JackNetInterface.h b/common/JackNetInterface.h
index c05979b0..6fb831cd 100644
--- a/common/JackNetInterface.h
+++ b/common/JackNetInterface.h
@@ -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;
diff --git a/common/JackNetManager.cpp b/common/JackNetManager.cpp
index 250c1237..7d62d678 100644
--- a/common/JackNetManager.cpp
+++ b/common/JackNetManager.cpp
@@ -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);
diff --git a/common/JackNetManager.h b/common/JackNetManager.h
index 80a66070..5bcca322 100644
--- a/common/JackNetManager.h
+++ b/common/JackNetManager.h
@@ -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;
diff --git a/common/JackNetTool.h b/common/JackNetTool.h
index b22061c3..127ce9bf 100644
--- a/common/JackNetTool.h
+++ b/common/JackNetTool.h
@@ -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 {
diff --git a/posix/JackNetUnixSocket.cpp b/posix/JackNetUnixSocket.cpp
index 20724089..4730e108 100644
--- a/posix/JackNetUnixSocket.cpp
+++ b/posix/JackNetUnixSocket.cpp
@@ -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;
diff --git a/posix/JackNetUnixSocket.h b/posix/JackNetUnixSocket.h
index 7bba0ed9..2038cda0 100644
--- a/posix/JackNetUnixSocket.h
+++ b/posix/JackNetUnixSocket.h
@@ -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);