diff --git a/common/JackConstants.h b/common/JackConstants.h index 59f6b6d..eb97a9a 100644 --- a/common/JackConstants.h +++ b/common/JackConstants.h @@ -82,4 +82,6 @@ #define EMPTY 0xFFFD #define FREE 0xFFFC +#define JACK_DEFAULT_SELF_CONNECT_MODE JackSelfConnectIgnoreAll + #endif diff --git a/common/JackControlAPI.cpp b/common/JackControlAPI.cpp index 3cc1141..c4d8168 100644 --- a/common/JackControlAPI.cpp +++ b/common/JackControlAPI.cpp @@ -47,6 +47,13 @@ using namespace Jack; +#define SELF_CONNECT_MODE_ALLOW_CHAR ' ' +#define SELF_CONNECT_MODE_FAIL_EXTERNAL_ONLY_CHAR 'E' +#define SELF_CONNECT_MODE_IGNORE_EXTERNAL_ONLY_CHAR 'e' +#define SELF_CONNECT_MODE_FAIL_ALL_CHAR 'A' +#define SELF_CONNECT_MODE_IGNORE_ALL_CHAR 'a' +#define SELF_CONNECT_MODES_COUNT 5 + struct jackctl_server { JSList * drivers; @@ -94,6 +101,12 @@ struct jackctl_server /* bool, synchronous or asynchronous engine mode */ union jackctl_parameter_value sync; union jackctl_parameter_value default_sync; + + /* char enum, self connect mode mode */ + union jackctl_parameter_value self_connect_mode; + union jackctl_parameter_value default_self_connect_mode; + jack_driver_param_value_enum_t self_connect_mode_possible_values[SELF_CONNECT_MODES_COUNT]; + jack_driver_param_constraint_desc_t self_connect_mode_constraint; }; struct jackctl_driver @@ -869,6 +882,40 @@ SERVER_EXPORT jackctl_server_t * jackctl_server_create( goto fail_free_parameters; } + server_ptr->self_connect_mode_constraint.flags = JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE; + server_ptr->self_connect_mode_constraint.constraint.enumeration.count = SELF_CONNECT_MODES_COUNT; + server_ptr->self_connect_mode_constraint.constraint.enumeration.possible_values_array = server_ptr->self_connect_mode_possible_values; + + server_ptr->self_connect_mode_possible_values[0].value.c = SELF_CONNECT_MODE_ALLOW_CHAR; + strcpy(server_ptr->self_connect_mode_possible_values[0].short_desc, "Don't restrict self connect requests"); + + server_ptr->self_connect_mode_possible_values[1].value.c = SELF_CONNECT_MODE_FAIL_EXTERNAL_ONLY_CHAR ; + strcpy(server_ptr->self_connect_mode_possible_values[1].short_desc, "Fail self connect requests to external ports only"); + + server_ptr->self_connect_mode_possible_values[2].value.c = SELF_CONNECT_MODE_IGNORE_EXTERNAL_ONLY_CHAR; + strcpy(server_ptr->self_connect_mode_possible_values[2].short_desc, "Ignore self connect requests to external ports only"); + + server_ptr->self_connect_mode_possible_values[3].value.c = SELF_CONNECT_MODE_FAIL_ALL_CHAR; + strcpy(server_ptr->self_connect_mode_possible_values[3].short_desc, "Fail all self connect requests"); + + server_ptr->self_connect_mode_possible_values[4].value.c = SELF_CONNECT_MODE_IGNORE_ALL_CHAR; + strcpy(server_ptr->self_connect_mode_possible_values[4].short_desc, "Ignore all self connect requests"); + + value.c = SELF_CONNECT_MODE_ALLOW_CHAR; + if (jackctl_add_parameter( + &server_ptr->parameters, + "self-connect-mode", + "Self connect mode.", + "Whether JACK clients are allowed to connect their own ports", + JackParamChar, + &server_ptr->self_connect_mode, + &server_ptr->default_self_connect_mode, + value, + &server_ptr->self_connect_mode_constraint) == NULL) + { + goto fail_free_parameters; + } + JackServerGlobals::on_device_acquire = on_device_acquire; JackServerGlobals::on_device_release = on_device_release; @@ -953,6 +1000,7 @@ jackctl_server_open( jackctl_server *server_ptr, jackctl_driver *driver_ptr) { + JackSelfConnectMode self_connect_mode; JSList * paramlist = NULL; try { @@ -986,6 +1034,27 @@ jackctl_server_open( server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */ } + switch (server_ptr->self_connect_mode.c) + { + case SELF_CONNECT_MODE_ALLOW_CHAR: + self_connect_mode = JackSelfConnectAllow; + break; + case SELF_CONNECT_MODE_FAIL_EXTERNAL_ONLY_CHAR: + self_connect_mode = JackSelfConnectFailExternalOnly; + break; + case SELF_CONNECT_MODE_IGNORE_EXTERNAL_ONLY_CHAR: + self_connect_mode = JackSelfConnectIgnoreExternalOnly; + break; + case SELF_CONNECT_MODE_FAIL_ALL_CHAR: + self_connect_mode = JackSelfConnectFailAll; + break; + case SELF_CONNECT_MODE_IGNORE_ALL_CHAR: + self_connect_mode = JackSelfConnectIgnoreAll; + break; + default: + self_connect_mode = JACK_DEFAULT_SELF_CONNECT_MODE; + } + /* check port max value before allocating server */ if (server_ptr->port_max.ui > PORT_NUM_MAX) { jack_error("Jack server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX); @@ -1002,6 +1071,7 @@ jackctl_server_open( server_ptr->port_max.ui, server_ptr->verbose.b, (jack_timer_type_t)server_ptr->clock_source.ui, + self_connect_mode, server_ptr->name.str); if (server_ptr->engine == NULL) { diff --git a/common/JackEngine.cpp b/common/JackEngine.cpp index 43b50b3..5bdb5b5 100644 --- a/common/JackEngine.cpp +++ b/common/JackEngine.cpp @@ -38,13 +38,15 @@ namespace Jack JackEngine::JackEngine(JackGraphManager* manager, JackSynchro* table, - JackEngineControl* control) + JackEngineControl* control, + JackSelfConnectMode self_connect_mode) : JackLockAble(control->fServerName), fSignal(control->fServerName) { fGraphManager = manager; fSynchroTable = table; fEngineControl = control; + fSelfConnectMode = self_connect_mode; for (int i = 0; i < CLIENT_NUM; i++) { fClientTable[i] = NULL; } @@ -816,10 +818,10 @@ int JackEngine::ClientDeactivate(int refnum) // First disconnect all ports for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) { - PortDisconnect(refnum, input_ports[i], ALL_PORTS); + PortDisconnect(-1, input_ports[i], ALL_PORTS); } for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) { - PortDisconnect(refnum, output_ports[i], ALL_PORTS); + PortDisconnect(-1, output_ports[i], ALL_PORTS); } // Then issue port registration notification @@ -875,7 +877,7 @@ int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index) JackClientInterface* client = fClientTable[refnum]; // Disconnect port ==> notification is sent - PortDisconnect(refnum, port_index, ALL_PORTS); + PortDisconnect(-1, port_index, ALL_PORTS); if (fGraphManager->ReleasePort(refnum, port_index) == 0) { if (client->GetClientControl()->fActive) { @@ -887,6 +889,72 @@ int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index) } } +// this check is to prevent apps to self connect to other apps +// TODO: make this work with multiple clients per app +int JackEngine::CheckPortsConnect(int refnum, jack_port_id_t src, jack_port_id_t dst) +{ + JackPort* src_port = fGraphManager->GetPort(src); + JackPort* dst_port = fGraphManager->GetPort(dst); + + jack_log("CheckPortsConnect(caller = %d, src = %d, dst = %d)", refnum, src_port->GetRefNum(), dst_port->GetRefNum()); + + int src_self = src_port->GetRefNum() == refnum ? 1 : 0; + int dst_self = dst_port->GetRefNum() == refnum ? 1 : 0; + + jack_log("src_self is %s", src_self ? "true" : "false"); + jack_log("dst_self is %s", dst_self ? "true" : "false"); + + // 0 means client is connecting other client ports (i.e. control app patchbay functionality) + // 1 means client is connecting its own port to port of other client (i.e. self hooking into system app) + // 2 means client is connecting its own ports (i.e. for app internal functionality) + // TODO: Make this check an engine option and more tweakable (return error or success) + // MAYBE: make the engine option changable on the fly and expose it through client or control API + + switch (fSelfConnectMode) + { + case JackSelfConnectFailExternalOnly: + if (src_self + dst_self == 1) + { + jack_info("rejecting port self connect request to external port (%s -> %s)", src_port->GetName(), dst_port->GetName()); + return -1; + } + + return 1; + + case JackSelfConnectIgnoreExternalOnly: + if (src_self + dst_self == 1) + { + jack_info("ignoring port self connect request to external port (%s -> %s)", src_port->GetName(), dst_port->GetName()); + return 0; + } + + return 1; + + case JackSelfConnectFailAll: + if (src_self + dst_self != 0) + { + jack_info("rejecting port self connect request (%s -> %s)", src_port->GetName(), dst_port->GetName()); + return -1; + } + + return 1; + + case JackSelfConnectIgnoreAll: + if (src_self + dst_self != 0) + { + jack_info("ignoring port self connect request (%s -> %s)", src_port->GetName(), dst_port->GetName()); + return 0; + } + + return 1; + + case JackSelfConnectAllow: // fix warning + return 1; + } + + return 1; +} + int JackEngine::PortConnect(int refnum, const char* src, const char* dst) { jack_log("JackEngine::PortConnect src = %s dst = %s", src, dst); @@ -927,7 +995,12 @@ int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst) return -1; } - int res = fGraphManager->Connect(src, dst); + int res = CheckPortsConnect(refnum, src, dst); + if (res != 1) { + return res; + } + + res = fGraphManager->Connect(src, dst); if (res == 0) { NotifyPortConnect(src, dst, true); } @@ -970,15 +1043,21 @@ int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t ds } return ret; - } else if (fGraphManager->CheckPorts(src, dst) < 0) { - return -1; - } else if (fGraphManager->Disconnect(src, dst) == 0) { - // Notifications - NotifyPortConnect(src, dst, false); - return 0; - } else { + } + + if (fGraphManager->CheckPorts(src, dst) < 0) { return -1; } + + int res = CheckPortsConnect(refnum, src, dst); + if (res != 1) { + return res; + } + + res = fGraphManager->Disconnect(src, dst); + if (res == 0) + NotifyPortConnect(src, dst, false); + return res; } int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name) diff --git a/common/JackEngine.h b/common/JackEngine.h index ebd3eb1..3393e1c 100644 --- a/common/JackEngine.h +++ b/common/JackEngine.h @@ -49,6 +49,7 @@ class SERVER_EXPORT JackEngine : public JackLockAble JackGraphManager* fGraphManager; JackEngineControl* fEngineControl; + JackSelfConnectMode fSelfConnectMode; JackClientInterface* fClientTable[CLIENT_NUM]; JackSynchro* fSynchroTable; JackServerNotifyChannel fChannel; /*! To communicate between the RT thread and server */ @@ -94,9 +95,11 @@ class SERVER_EXPORT JackEngine : public JackLockAble return (refnum >= 0 && refnum < CLIENT_NUM && fClientTable[refnum] != NULL); } + int CheckPortsConnect(int refnum, jack_port_id_t src, jack_port_id_t dst); + public: - JackEngine(JackGraphManager* manager, JackSynchro* table, JackEngineControl* controler); + JackEngine(JackGraphManager* manager, JackSynchro* table, JackEngineControl* controler, JackSelfConnectMode self_connect_mode); ~JackEngine(); int Open(); diff --git a/common/JackLockedEngine.h b/common/JackLockedEngine.h index a1dc807..a02c83c 100644 --- a/common/JackLockedEngine.h +++ b/common/JackLockedEngine.h @@ -83,8 +83,8 @@ class SERVER_EXPORT JackLockedEngine public: - JackLockedEngine(JackGraphManager* manager, JackSynchro* table, JackEngineControl* controler): - fEngine(manager, table, controler) + JackLockedEngine(JackGraphManager* manager, JackSynchro* table, JackEngineControl* controler, JackSelfConnectMode self_connect_mode): + fEngine(manager, table, controler, self_connect_mode) {} ~JackLockedEngine() {} diff --git a/common/JackServer.cpp b/common/JackServer.cpp index b7e7639..5247104 100644 --- a/common/JackServer.cpp +++ b/common/JackServer.cpp @@ -37,7 +37,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. namespace Jack { -JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int priority, int port_max, bool verbose, jack_timer_type_t clock, const char* server_name) +JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int priority, int port_max, bool verbose, jack_timer_type_t clock, JackSelfConnectMode self_connect_mode, const char* server_name) { if (rt) { jack_info("JACK server starting in realtime mode with priority %ld", priority); @@ -47,7 +47,7 @@ JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int prio fGraphManager = JackGraphManager::Allocate(port_max); fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name); - fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); + fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl, self_connect_mode); // A distinction is made between the threaded freewheel driver and the // regular freewheel driver because the freewheel driver needs to run in diff --git a/common/JackServer.h b/common/JackServer.h index 0403272..f288d05 100644 --- a/common/JackServer.h +++ b/common/JackServer.h @@ -64,7 +64,7 @@ class SERVER_EXPORT JackServer public: - JackServer(bool sync, bool temporary, int timeout, bool rt, int priority, int port_max, bool verbose, jack_timer_type_t clock, const char* server_name); + JackServer(bool sync, bool temporary, int timeout, bool rt, int priority, int port_max, bool verbose, jack_timer_type_t clock, JackSelfConnectMode self_connect_mode, const char* server_name); ~JackServer(); int Open(jack_driver_desc_t* driver_desc, JSList* driver_params); diff --git a/common/JackServerGlobals.cpp b/common/JackServerGlobals.cpp index 21feb7f..a10d7f2 100644 --- a/common/JackServerGlobals.cpp +++ b/common/JackServerGlobals.cpp @@ -48,10 +48,11 @@ int JackServerGlobals::Start(const char* server_name, int priority, int port_max, int verbose, - jack_timer_type_t clock) + jack_timer_type_t clock, + JackSelfConnectMode self_connect_mode) { jack_log("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld ", sync, time_out_ms, rt, priority, verbose); - new JackServer(sync, temporary, time_out_ms, rt, priority, port_max, verbose, clock, server_name); // Will setup fInstance and fUserCount globals + new JackServer(sync, temporary, time_out_ms, rt, priority, port_max, verbose, clock, self_connect_mode, server_name); // Will setup fInstance and fUserCount globals int res = fInstance->Open(driver_desc, driver_params); return (res < 0) ? res : fInstance->Start(); } @@ -335,7 +336,7 @@ bool JackServerGlobals::Init() free(argv[i]); } - int res = Start(server_name, driver_desc, master_driver_params, sync, temporary, client_timeout, realtime, realtime_priority, port_max, verbose_aux, clock_source); + int res = Start(server_name, driver_desc, master_driver_params, sync, temporary, client_timeout, realtime, realtime_priority, port_max, verbose_aux, clock_source, JACK_DEFAULT_SELF_CONNECT_MODE); if (res < 0) { jack_error("Cannot start server... exit"); Delete(); diff --git a/common/JackServerGlobals.h b/common/JackServerGlobals.h index 69b8979..47e9460 100644 --- a/common/JackServerGlobals.h +++ b/common/JackServerGlobals.h @@ -61,7 +61,8 @@ struct SERVER_EXPORT JackServerGlobals int priority, int port_max, int verbose, - jack_timer_type_t clock); + jack_timer_type_t clock, + JackSelfConnectMode self_connect_mode); static void Stop(); static void Delete(); }; diff --git a/common/JackTypes.h b/common/JackTypes.h index b4bad8d..a5a883e 100644 --- a/common/JackTypes.h +++ b/common/JackTypes.h @@ -55,4 +55,14 @@ typedef enum { Finished, } jack_client_state_t; + +enum JackSelfConnectMode +{ + JackSelfConnectAllow, + JackSelfConnectFailExternalOnly, + JackSelfConnectIgnoreExternalOnly, + JackSelfConnectFailAll, + JackSelfConnectIgnoreAll, +}; + #endif diff --git a/common/Jackdmp.cpp b/common/Jackdmp.cpp index 2aec190..b793c2a 100644 --- a/common/Jackdmp.cpp +++ b/common/Jackdmp.cpp @@ -184,8 +184,8 @@ int main(int argc, char** argv) jackctl_driver_t * master_driver_ctl; jackctl_driver_t * loopback_driver_ctl = NULL; int replace_registry = 0; - const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:" + "a:" #ifdef __linux__ "c:" #endif @@ -215,6 +215,7 @@ int main(int argc, char** argv) { "version", 0, 0, 'V' }, { "silent", 0, 0, 's' }, { "sync", 0, 0, 'S' }, + { "autoconnect", 1, 0, 'a' }, { 0, 0, 0, 0 } }; @@ -277,6 +278,26 @@ int main(int argc, char** argv) break; #endif + case 'a': + param = jackctl_get_parameter(server_parameters, "self-connect-mode"); + if (param != NULL) { + bool value_valid = false; + for (uint32_t k=0; k