diff options
author | Thomas Brand <tom@trellis.ch> | 2019-02-08 21:16:28 +0100 |
---|---|---|
committer | Thomas Brand <tom@trellis.ch> | 2019-02-08 21:16:28 +0100 |
commit | 40cb345a38f120fac0fecd130fcd10424a03abfd (patch) | |
tree | de9ace5b6a55d045461524e6e985a0496ff6ac64 | |
parent | a752bfaa618457ea9ad366794f0751cc96ba2578 (diff) | |
download | jack2-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.cpp | 21 | ||||
-rw-r--r-- | common/JackNetDriver.cpp | 19 | ||||
-rw-r--r-- | common/JackNetDriver.h | 2 | ||||
-rw-r--r-- | common/JackNetInterface.cpp | 10 | ||||
-rw-r--r-- | common/JackNetInterface.h | 4 | ||||
-rw-r--r-- | common/JackNetManager.cpp | 29 | ||||
-rw-r--r-- | common/JackNetManager.h | 1 | ||||
-rw-r--r-- | common/JackNetTool.h | 2 | ||||
-rw-r--r-- | posix/JackNetUnixSocket.cpp | 499 | ||||
-rw-r--r-- | posix/JackNetUnixSocket.h | 24 |
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); |