diff --git a/common/JackNetAdapter.cpp b/common/JackNetAdapter.cpp index 37dcd628..4f550490 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,6 +131,8 @@ 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); @@ -424,6 +429,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, any or all", "Multicast interface to send probes from (any - kernel chosen (default), all - all available, if_name - explicit bind)"); + 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..b230bb74 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, any or all", "Multicast interface to send probes from (any - kernel chosen (default), all - all available, if_name - explicit bind)"); + 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 f1f7d509..99bd2504 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..95212390 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 dce0f19e..9a50a0a1 100644 --- a/common/JackNetInterface.h +++ b/common/JackNetInterface.h @@ -27,6 +27,7 @@ namespace Jack { #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 +61,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..9a1afa0a 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(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; } @@ -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 31e81827..5db34e19 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/posix/JackNetUnixSocket.cpp b/posix/JackNetUnixSocket.cpp index 7a5585ef..ce8269ce 100644 --- a/posix/JackNetUnixSocket.cpp +++ b/posix/JackNetUnixSocket.cpp @@ -20,6 +20,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "JackNetUnixSocket.h" #include "JackError.h" +#include +#include +#include +#include #include #include @@ -171,6 +175,16 @@ namespace Jack { return bind(fSockfd, reinterpret_cast(&fRecvAddr), sizeof(socket_address_t)); } + int JackNetUnixSocket::Bind(const char *if_name) + { + struct ip_mreq multicast_req; + int ret = Bind(); + if(!ret && strcmp(if_name,"any")) { + multicast_req.imr_multiaddr.s_addr = fSendAddr.sin_addr.s_addr; + ret = BindMCastIface(if_name, IP_MULTICAST_IF, &multicast_req); + } + return ret; + } int JackNetUnixSocket::BindWith(const char* ip) { @@ -267,11 +281,53 @@ namespace Jack } int JackNetUnixSocket::JoinMCastGroup(const char* ip) + { + return JoinMCastGroup(ip,"any"); + } + int JackNetUnixSocket::JoinMCastGroup(const char* ip, const char *if_name) { 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)); + if(!strcmp(if_name,"any")) { + multicast_req.imr_interface.s_addr = htonl(INADDR_ANY); + return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req)); + } else { + return BindMCastIface(if_name, IP_ADD_MEMBERSHIP, &multicast_req); + } + } + int JackNetUnixSocket::BindMCastIface(const char *if_name, const int option, struct ip_mreq *mreq) + { + struct ifaddrs *ifas, *ifa; + int specific = strcmp("all",if_name); + int ret=-1; + char *if_last="any"; + + if (getifaddrs(&ifas) == -1) { + jack_error("JackNetUnixSocket::BindMCastIface error in getifaddrs"); + return -1; + } + 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 for the moment we're dealing with IPv4 only + 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; } //options************************************************************************************************************ @@ -468,6 +524,7 @@ namespace Jack int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags) { + jack_log("JackNetUnixSocket::CatchHost"); socklen_t addr_len = sizeof(socket_address_t); #if defined(__sun__) || defined(sun) if (WaitRead() < 0) { diff --git a/posix/JackNetUnixSocket.h b/posix/JackNetUnixSocket.h index 7bba0ed9..78fddd4d 100644 --- a/posix/JackNetUnixSocket.h +++ b/posix/JackNetUnixSocket.h @@ -64,6 +64,7 @@ namespace Jack //socket management int NewSocket(); int Bind(); + int Bind(const char *if_name); int BindWith(const char* ip); int BindWith(int port); int Connect(); @@ -84,6 +85,8 @@ namespace Jack //utility int GetName(char* name); int JoinMCastGroup(const char* mcast_ip); + int JoinMCastGroup(const char* mcast_ip, const char* if_name); + int BindMCastIface(const char *if_name, const int option, struct ip_mreq *mreq); //options management int SetOption(int level, int optname, const void* optval, socklen_t optlen);