[PATCH] connection veto....

View: New views
1 Messages — Rating Filter:   Alert me  

[PATCH] connection veto....

by torbenh :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


maybe its possible, that the feedback to this patch can be constructive.

a) i layed out usecases for multiple veto clients.
b) its more complex, to implement a single vetoer.

patch is against jack1.


--
torben Hohn
http://galan.sourceforge.net -- The graphical Audio language

diff --git a/example-clients/Makefile.am b/example-clients/Makefile.am
index 8eddc4c..f16978f 100644
--- a/example-clients/Makefile.am
+++ b/example-clients/Makefile.am
@@ -6,7 +6,8 @@ bin_PROGRAMS = jack_simple_client \
        jack_metro \
        jack_showtime \
    jack_midisine \
-   jack_midiseq
+   jack_midiseq \
+   jack_veto_test
 
 if HAVE_SNDFILE
 # note! jackrec_CFLAGS syntax not supported by automake-1.4
@@ -44,6 +45,10 @@ jack_midisine_SOURCES = midisine.c
 jack_midisine_LDFLAGS = @OS_LDFLAGS@
 jack_midisine_LDADD = $(top_builddir)/libjack/libjack.la
 
+jack_veto_test_SOURCES = veto_test.c
+jack_veto_test_LDFLAGS = @OS_LDFLAGS@
+jack_veto_test_LDADD = $(top_builddir)/libjack/libjack.la
+
 #
 # sample in-process client(s)
 #
diff --git a/example-clients/veto_test.c b/example-clients/veto_test.c
new file mode 100644
index 0000000..ad9e094
--- /dev/null
+++ b/example-clients/veto_test.c
@@ -0,0 +1,106 @@
+/** @file simple_client.c
+ *
+ * @brief This simple client demonstrates the most basic features of JACK
+ * as they would be used by many applications.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <jack/jack.h>
+
+jack_client_t *client;
+
+
+int veto_cb( const char *req_client, jack_port_id_t a, jack_port_id_t b, int connect, void *arg )
+{
+ const char *name_a = jack_port_name( jack_port_by_id( client, a ) );
+ const char *name_b = jack_port_name( jack_port_by_id( client, b ) );
+
+ if( connect )
+ printf( "connection attempt... requestor: %s   ( %s -> %s )\n", req_client, name_a, name_b );
+ else
+ printf( "disconnection attempt... requestor: %s   ( %s -> %s )\n", req_client, name_a, name_b );
+
+ if( strcmp( req_client, "ardour" ) && strcmp( req_client, "qjackctl" ) ) {
+ // its not ardour, and its not qjack... lets veto :)
+ return 1;
+ } else {
+ // ok... ardour of qjack.
+ return 0;
+ }
+}
+
+/**
+ * JACK calls this shutdown_callback if the server ever shuts down or
+ * decides to disconnect the client.
+ */
+void
+jack_shutdown (void *arg)
+{
+ exit (1);
+}
+
+int
+main (int argc, char *argv[])
+{
+ const char *client_name = "veto";
+ const char *server_name = NULL;
+ jack_options_t options = JackNullOption;
+ jack_status_t status;
+
+ /* open a client connection to the JACK server */
+
+ client = jack_client_open (client_name, options, &status, server_name);
+ if (client == NULL) {
+ fprintf (stderr, "jack_client_open() failed, "
+ "status = 0x%2.0x\n", status);
+ if (status & JackServerFailed) {
+ fprintf (stderr, "Unable to connect to JACK server\n");
+ }
+ exit (1);
+ }
+ if (status & JackServerStarted) {
+ fprintf (stderr, "JACK server started\n");
+ }
+ if (status & JackNameNotUnique) {
+ client_name = jack_get_client_name(client);
+ fprintf (stderr, "unique name `%s' assigned\n", client_name);
+ }
+
+ /* tell the JACK server to call `process()' whenever
+   there is work to be done.
+ */
+
+ jack_set_connection_veto_callback (client, veto_cb, 0);
+
+ /* tell the JACK server to call `jack_shutdown()' if
+   it ever shuts down, either entirely, or if it
+   just decides to stop calling us.
+ */
+
+ jack_on_shutdown (client, jack_shutdown, 0);
+
+ /* display the current sample rate.
+ */
+
+ if (jack_activate (client)) {
+ fprintf (stderr, "cannot activate client");
+ exit (1);
+ }
+
+ /* keep running until stopped by the user */
+
+ sleep (-1);
+
+ /* this is never reached but if the program
+   had some other way to exit besides being killed,
+   they would be important to call.
+ */
+
+ jack_client_close (client);
+ exit (0);
+}
diff --git a/jack/internal.h b/jack/internal.h
index b51ef44..a5fc559 100644
--- a/jack/internal.h
+++ b/jack/internal.h
@@ -217,7 +217,9 @@ typedef enum  {
   StartFreewheel,
   StopFreewheel,
   ClientRegistered,
-  ClientUnregistered
+  ClientUnregistered,
+  PortConnectVeto,
+  PortDisconnectVeto
 } JackEventType;
 
 typedef struct {
@@ -233,6 +235,9 @@ typedef struct {
  jack_port_type_id_t ptid;
  jack_port_id_t other_id;
     } y;
+    union {
+ jack_port_id_t port_id;
+    } z;
 } POST_PACKED_STRUCTURE jack_event_t;
 
 typedef enum {
@@ -291,6 +296,7 @@ typedef volatile struct {
     volatile uint8_t timebase_cb_cbset;
     volatile uint8_t freewheel_cb_cbset;
     volatile uint8_t client_register_cbset;
+    volatile uint8_t connect_veto_cbset;
     volatile uint8_t thread_cb_cbset;
 
 } POST_PACKED_STRUCTURE jack_client_control_t;
@@ -389,6 +395,7 @@ struct _jack_request {
  struct {
     char source_port[JACK_PORT_NAME_SIZE];
     char destination_port[JACK_PORT_NAME_SIZE];
+    jack_client_id_t client_id;
  } POST_PACKED_STRUCTURE connect;
  struct {
     int32_t nports;
diff --git a/jack/jack.h b/jack/jack.h
index 64ba8a7..2cd66bf 100644
--- a/jack/jack.h
+++ b/jack/jack.h
@@ -365,6 +365,16 @@ int jack_set_graph_order_callback (jack_client_t *,
 int jack_set_xrun_callback (jack_client_t *,
     JackXRunCallback xrun_callback, void *arg);
 
+/**
+ * Tell the JACK server to call @a veto_callback whenever there is an
+ * attempt to connect or disconnect a port.
+ *
+ * @return 0 on success, otherwise a non-zero error code
+ */
+
+int jack_set_connection_veto_callback(jack_client_t *client,
+      JackConnectVetoCallback veto_callback,
+      void *arg);
 /*@}*/
 
 /**
diff --git a/jack/types.h b/jack/types.h
index 020a51b..9e90a0b 100644
--- a/jack/types.h
+++ b/jack/types.h
@@ -186,6 +186,20 @@ typedef void (*JackPortConnectCallback)(jack_port_id_t a, jack_port_id_t b, int
 
 /**
  * Prototype for the client supplied function that is called
+ * whenever a Connection or Disconnection is made.
+ * if it returns non-zero, it means a veto against the process,
+ * and the connection/disconnection, will not be made.
+ *
+ * @param a one of two ports connected or disconnected
+ * @param b one of two ports connected or disconnected
+ * @param connect non-zero if ports were connected
+ *                    zero if ports were disconnected
+ * @param arg pointer to a client supplied data
+ */
+typedef int (*JackConnectVetoCallback)(const char *req_client, jack_port_id_t a, jack_port_id_t b, int connect, void* arg);
+
+/**
+ * Prototype for the client supplied function that is called
  * whenever jackd starts or stops freewheeling.
  *
  * @param starting non-zero if we start starting to freewheel, zero otherwise
diff --git a/jackd/clientengine.c b/jackd/clientengine.c
index 5de971f..b5db3b5 100644
--- a/jackd/clientengine.c
+++ b/jackd/clientengine.c
@@ -538,6 +538,7 @@ jack_setup_client_control (jack_engine_t *engine, int fd,
  client->control->graph_order_cbset = FALSE;
  client->control->client_register_cbset = FALSE;
  client->control->thread_cb_cbset = FALSE;
+ client->control->connect_veto_cbset = FALSE;
 
 #if 0
  if (type != ClientExternal) {
diff --git a/jackd/engine.c b/jackd/engine.c
index d3f7263..b38a6c7 100644
--- a/jackd/engine.c
+++ b/jackd/engine.c
@@ -89,10 +89,10 @@ static int  jack_rechain_graph (jack_engine_t *engine);
 static void jack_clear_fifos (jack_engine_t *engine);
 static int  jack_port_do_connect (jack_engine_t *engine,
   const char *source_port,
-  const char *destination_port);
+  const char *destination_port, jack_client_id_t req_id);
 static int  jack_port_do_disconnect (jack_engine_t *engine,
      const char *source_port,
-     const char *destination_port);
+     const char *destination_port, jack_client_id_t req_id);
 static int  jack_port_do_disconnect_all (jack_engine_t *engine,
  jack_port_id_t);
 static int  jack_port_do_unregister (jack_engine_t *engine, jack_request_t *);
@@ -1229,7 +1229,7 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd)
  case ConnectPorts:
  req->status = jack_port_do_connect
  (engine, req->x.connect.source_port,
- req->x.connect.destination_port);
+ req->x.connect.destination_port, req->x.connect.client_id);
  break;
 
  case DisconnectPort:
@@ -1240,7 +1240,7 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd)
  case DisconnectPorts:
  req->status = jack_port_do_disconnect
  (engine, req->x.connect.source_port,
- req->x.connect.destination_port);
+ req->x.connect.destination_port, req->x.connect.client_id);
  break;
 
  case ActivateClient:
@@ -2423,6 +2423,37 @@ jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event)
  jack_unlock_graph (engine);
 }
 
+static int
+jack_query_veto_clients (jack_engine_t *engine, jack_client_id_t requestor, jack_port_id_t a, jack_port_id_t b, int connected)
+{
+ JSList *node;
+ jack_event_t event;
+  
+ int retval = 0;
+ int reply;
+
+ jack_client_internal_t* req_client = jack_client_internal_by_id (engine, requestor);
+
+ event.type = (connected ? PortConnectVeto : PortDisconnectVeto);
+ snprintf (event.x.name, sizeof (event.x.name), "%s", req_client->control->name);
+ event.y.other_id = a;
+ event.z.port_id = b;
+
+ /* GRAPH MUST BE LOCKED : see callers of jack_send_connection_notification()
+ */
+
+ for (node = engine->clients; node; node = jack_slist_next (node)) {
+ jack_client_internal_t* client = (jack_client_internal_t*) node->data;
+ if (client->control->connect_veto_cbset) {
+
+ reply = jack_deliver_event (engine, client, &event);
+ if( reply >= 0 )
+ retval |= reply;
+ }
+ }
+ return retval;
+}
+
 static void
 jack_notify_all_port_interested_clients (jack_engine_t *engine, jack_client_id_t src, jack_client_id_t dst, jack_port_id_t a, jack_port_id_t b, int connected)
 {
@@ -2453,7 +2484,7 @@ static int
 jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client,
     jack_event_t *event)
 {
- char status;
+ char status = -1;
 
  /* caller must hold the graph lock */
 
@@ -2603,7 +2634,7 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client,
     client->event_fd,
     pfd[0].revents,
     poll_timeout);
- status = 1;
+ status = -2;
 #ifdef __linux
  }
 #endif
@@ -2628,7 +2659,7 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client,
     event->type);
    }
 
- if (status) {
+ if (status < 0) {
  client->error += JACK_ERROR_WITH_SOCKETS;
  jack_engine_signal_problems (engine);
  }
@@ -2636,7 +2667,7 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client,
  }
  DEBUG ("event delivered");
 
- return 0;
+ return status;
 }
 
 int
@@ -3202,7 +3233,8 @@ void jack_dump_configuration(jack_engine_t *engine, int take_lock)
 static int
 jack_port_do_connect (jack_engine_t *engine,
        const char *source_port,
-       const char *destination_port)
+       const char *destination_port,
+       jack_client_id_t req_id )
 {
  jack_connection_internal_t *connection;
  jack_port_internal_t *srcport, *dstport;
@@ -3291,6 +3323,15 @@ jack_port_do_connect (jack_engine_t *engine,
 
  jack_lock_graph (engine);
 
+ // XXX: do i really need to have the graph locked, las ?
+ if( jack_query_veto_clients( engine, req_id, src_id, dst_id, 1 ) ) {
+ // Connection vetoed... go to the UN if you dont like it.
+ free (connection);
+ jack_unlock_graph (engine);
+
+ // we return success here, because most dumb clients exit, when the connection fails
+ return 0;
+ }
  if (dstport->connections && !dstport->shared->has_mixdown) {
  jack_port_type_info_t *port_type =
  jack_port_type_info (engine, dstport);
@@ -3532,7 +3573,7 @@ jack_port_do_disconnect_all (jack_engine_t *engine,
 static int
 jack_port_do_disconnect (jack_engine_t *engine,
  const char *source_port,
- const char *destination_port)
+ const char *destination_port, jack_client_id_t req_id)
 {
  jack_port_internal_t *srcport, *dstport;
  int ret = -1;
@@ -3550,8 +3591,18 @@ jack_port_do_disconnect (jack_engine_t *engine,
  return -1;
  }
 
+ jack_port_id_t src_id = srcport->shared->id;
+ jack_port_id_t dst_id = dstport->shared->id;
+
  jack_lock_graph (engine);
 
+ // XXX: do i really need to have the graph locked, las ?
+ if( jack_query_veto_clients( engine, req_id, src_id, dst_id, 0 ) ) {
+ // Connection vetoed... go to the UN if you dont like it.
+ jack_unlock_graph (engine);
+ return -1;
+ }
+
  ret = jack_port_disconnect_internal (engine, srcport, dstport);
 
  jack_unlock_graph (engine);
diff --git a/libjack/client.c b/libjack/client.c
index ed0bee8..4b0f6db 100644
--- a/libjack/client.c
+++ b/libjack/client.c
@@ -468,6 +468,19 @@ jack_client_handle_port_connection (jack_client_t *client, jack_event_t *event)
  return 0;
 }
 
+int
+jack_client_handle_connect_veto (jack_client_t *client, jack_event_t *event)
+{
+ int retval = 0;
+
+ if (client->control->connect_veto_cbset) {
+ retval = client->connect_veto (event->x.name, event->y.other_id, event->z.port_id,
+       (event->type == PortConnectVeto ? 1 : 0),
+       client->connect_veto_arg);
+ }
+
+ return retval;
+}
 #if JACK_USE_MACH_THREADS
 
 static int
@@ -1412,6 +1425,12 @@ jack_client_process_events (jack_client_t* client)
  case StopFreewheel:
  jack_stop_freewheel (client);
  break;
+
+ case PortConnectVeto:
+ case PortDisconnectVeto:
+ status = jack_client_handle_connect_veto
+ (client, &event);
+ break;
  }
 
  DEBUG ("client has dealt with the event, writing "
@@ -2173,6 +2192,7 @@ jack_connect (jack_client_t *client, const char *source_port,
  snprintf (req.x.connect.destination_port,
   sizeof (req.x.connect.destination_port),
   "%s", destination_port);
+ req.x.connect.client_id = client->control->id;
 
  return jack_client_deliver_request (client, &req);
 }
@@ -2210,6 +2230,7 @@ jack_disconnect (jack_client_t *client, const char *source_port,
  snprintf (req.x.connect.destination_port,
   sizeof (req.x.connect.destination_port),
   "%s", destination_port);
+ req.x.connect.client_id = client->control->id;
 
  return jack_client_deliver_request (client, &req);
 }
@@ -2360,6 +2381,22 @@ jack_set_client_registration_callback(jack_client_t *client,
 }
 
 int
+jack_set_connection_veto_callback(jack_client_t *client,
+      JackConnectVetoCallback callback,
+      void *arg)
+{
+ if (client->control->active) {
+ jack_error ("You cannot set callbacks on an active client.");
+ return -1;
+ }
+ client->connect_veto_arg = arg;
+ client->connect_veto = callback;
+ client->control->connect_veto_cbset = (callback != NULL);
+ return 0;
+}
+
+
+int
 jack_set_process_thread(jack_client_t* client, JackThreadCallback callback, void *arg)
 {
  if (client->control->active) {
diff --git a/libjack/local.h b/libjack/local.h
index 7ee4bbb..95f714b 100644
--- a/libjack/local.h
+++ b/libjack/local.h
@@ -68,7 +68,9 @@ struct _jack_client {
     void *freewheel_arg;
     JackClientRegistrationCallback client_register;
     void *client_register_arg;
- JackThreadCallback thread_cb;
+    JackConnectVetoCallback connect_veto;
+    void *connect_veto_arg;
+    JackThreadCallback thread_cb;
     void *thread_cb_arg;
 
     /* external clients: set by libjack

_______________________________________________
Jack-Devel mailing list
Jack-Devel@...
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org