Conflicts: common/JackEngine.cpp common/JackServer.cpptags/v1.9.10
@@ -82,4 +82,6 @@ | |||
#define EMPTY 0xFFFD | |||
#define FREE 0xFFFC | |||
#define JACK_DEFAULT_SELF_CONNECT_MODE JackSelfConnectIgnoreAll | |||
#endif |
@@ -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) | |||
{ | |||
@@ -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; | |||
} | |||
@@ -803,10 +805,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 | |||
@@ -874,7 +876,7 @@ int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index) | |||
assert(client); | |||
// 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) { | |||
@@ -886,6 +888,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); | |||
@@ -926,7 +994,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); | |||
} | |||
@@ -969,15 +1042,21 @@ int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t ds | |||
} | |||
return res; | |||
} 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) | |||
@@ -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(); | |||
@@ -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() | |||
{} | |||
@@ -40,8 +40,7 @@ namespace Jack | |||
//---------------- | |||
// Server control | |||
//---------------- | |||
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); | |||
@@ -51,7 +50,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 | |||
@@ -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(); | |||
// Server control | |||
@@ -47,10 +47,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(); | |||
} | |||
@@ -336,7 +337,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(); | |||
@@ -60,7 +60,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(); | |||
}; | |||
@@ -50,4 +50,14 @@ typedef enum { | |||
Finished, | |||
} jack_client_state_t; | |||
enum JackSelfConnectMode | |||
{ | |||
JackSelfConnectAllow, | |||
JackSelfConnectFailExternalOnly, | |||
JackSelfConnectIgnoreExternalOnly, | |||
JackSelfConnectFailAll, | |||
JackSelfConnectIgnoreAll, | |||
}; | |||
#endif |
@@ -203,8 +203,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 | |||
@@ -234,6 +234,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 } | |||
}; | |||
@@ -296,6 +297,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<jackctl_parameter_get_enum_constraints_count( param ); k++ ) { | |||
value = jackctl_parameter_get_enum_constraint_value( param, k ); | |||
if( value.c == optarg[0] ) | |||
value_valid = true; | |||
} | |||
if( value_valid ) { | |||
value.c = optarg[0]; | |||
jackctl_parameter_set_value(param, &value); | |||
} else { | |||
usage(stdout); | |||
goto destroy_server; | |||
} | |||
} | |||
break; | |||
case 'd': | |||
master_driver_name = optarg; | |||
break; | |||