Index: ChangeLog
===================================================================
--- ChangeLog	(revision 5573)
+++ ChangeLog	(revision 5576)
@@ -8,4 +8,5 @@
 	* Disable building of roard plugins on windows as PE doesn't
 	  support them (Closes: #274)
+	* Support a common protocol interface (Closes: #257)
 
 v. 1.0beta3 - Sun Jul 15 2012 26:08 CEST
Index: include/libroar/roardl.h
===================================================================
--- include/libroar/roardl.h	(revision 5512)
+++ include/libroar/roardl.h	(revision 5576)
@@ -339,4 +339,28 @@
 
 
+// Common protocol interface:
+struct roar_dl_proto {
+ const int proto;
+ const char * description;
+ const int flags;
+ int (*set_proto)(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * para, ssize_t paralen);
+ int (*unset_proto)(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * para, ssize_t paralen);
+ int (*handle)(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * para, ssize_t paralen);
+ int (*flush)(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * para, ssize_t paralen);
+ int (*flushed)(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * para, ssize_t paralen);
+ int (*status)(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * para, ssize_t paralen);
+};
+
+#define ROAR_DL_PROTO_FLAGS_NONE         0
+
+#define ROAR_DL_PROTO_STATUS_RX_READY    0x0001
+#define ROAR_DL_PROTO_STATUS_TX_READY    0x0002
+#define ROAR_DL_PROTO_STATUS_WAIT_NOTIFY 0x0004
+
+// Parameters for FNREG registration:
+#define ROAR_DL_PROTO_SUBTYPE  1 /* 0 = roard */
+#define ROAR_DL_PROTO_VERSION  0
+#define ROAR_DL_PROTO_SIZE     sizeof(struct roar_dl_proto)
+
 // Reg FN:
 
Index: include/libroar/roarfeatures.h
===================================================================
--- include/libroar/roarfeatures.h	(revision 5381)
+++ include/libroar/roarfeatures.h	(revision 5576)
@@ -59,4 +59,6 @@
 #define ROAR_FT_FEATURE_HASH_API
 #define ROAR_FT_FEATURE_RANDOM_NONCE
+#define ROAR_FT_FEATURE_UUID         /* see #230 */
+#define ROAR_FT_FEATURE_COMMON_PROTO /* see #257 */
 
 // libroar2 features:
Index: roard/clients.c
===================================================================
--- roard/clients.c	(revision 5574)
+++ roard/clients.c	(revision 5576)
@@ -144,5 +144,5 @@
  const struct roard_proto_handle * protohandle;
  struct roar_vio_calls    vio;
- struct roar_client * c;
+ struct roar_client_server * cs;
  int supported = 0;
  int client;
@@ -174,6 +174,5 @@
    case -2: return  0; break;
    default: // TODO: write error handling
-     clients_get(client, &c);
-     fh = c->fh;
+     fh = ROAR_CLIENT(cs)->fh;
     break;
   }
@@ -200,12 +199,15 @@
  }
 
+ if ( clients_get_server(client, &cs) == -1 ) {
+  clients_delete(client);
+  return -1;
+ }
+
  if ( update_nnode ) {
-  if ( clients_get(client, &c) != -1 ) {
-   if ( roar_nnode_free(&(c->nnode)) != -1 ) {
-    if ( sockaddr != NULL && addrlen != 0 ) {
-     roar_nnode_new_from_sockaddr(&(c->nnode), sockaddr, addrlen);
-    } else {
-     roar_nnode_new_from_fh(&(c->nnode), fh, 1);
-    }
+  if ( roar_nnode_free(&(ROAR_CLIENT(cs)->nnode)) != -1 ) {
+   if ( sockaddr != NULL && addrlen != 0 ) {
+    roar_nnode_new_from_sockaddr(&(ROAR_CLIENT(cs)->nnode), sockaddr, addrlen);
+   } else {
+    roar_nnode_new_from_fh(&(ROAR_CLIENT(cs)->nnode), fh, 1);
    }
   }
@@ -266,4 +268,6 @@
     supported = 0;
     if ( protohandle != NULL ) {
+     if ( protohandle->lhandle != NULL )
+      roar_dl_context_restore(protohandle->lhandle);
      switch (protohandle->type) {
       case ROARD_PROTO_TYPE_BUILDIN:
@@ -280,5 +284,15 @@
         }
        break;
+      case ROARD_PROTO_TYPE_COMMON:
+        supported = 1;
+        if ( protohandle->impl.common->set_proto != NULL ) {
+         if ( protohandle->impl.common->set_proto(client, &vio, &(cs->outbuf), &(cs->protoinst), protohandle->para, protohandle->paralen) == -1 ) {
+          supported = 0;
+         }
+        }
+       break;
      }
+     if ( protohandle->lhandle != NULL )
+      roar_dl_context_store(protohandle->lhandle);
     }
 
@@ -298,4 +312,5 @@
  struct roar_client_server * cs;
  const struct roard_proto_handle * proto;
+ struct roar_vio_calls vio;
  int i;
  int close_client_fh = 1;
@@ -309,4 +324,6 @@
  proto = clients_get_protohandle(ROAR_CLIENT(cs)->proto);
  if ( proto != NULL ) {
+  if ( proto->lhandle != NULL )
+   roar_dl_context_restore(proto->lhandle);
   switch (proto->type) {
    case ROARD_PROTO_TYPE_BUILDIN:
@@ -317,5 +334,13 @@
       proto->impl.roardproto.delete_client(id);
     break;
-  }
+   case ROARD_PROTO_TYPE_COMMON:
+     if ( proto->impl.common->unset_proto != NULL ) {
+      roar_vio_open_fh_socket(&vio, clients_get_fh(id));
+      proto->impl.common->unset_proto(id, &vio, &(cs->outbuf), &(cs->protoinst), proto->para, proto->paralen);
+     }
+    break;
+  }
+  if ( proto->lhandle != NULL )
+   roar_dl_context_store(proto->lhandle);
  }
 
@@ -692,5 +717,5 @@
 
 int clients_check     (int id) {
- struct roar_client   * c;
+ struct roar_client_server * cs;
  struct roar_message    m;
  struct roar_connection con;
@@ -710,14 +735,14 @@
  _CHECK_CID(id);
 
- c = ROAR_CLIENT(g_clients[id]);
-
- if ( c->fh == -1 )
-  return -1;
-
- roar_connect_fh(&con, c->fh);
-
- ROAR_DBG("clients_check(id=%i): c->proto=%i", id, c->proto);
-
- switch (c->proto) {
+ cs = g_clients[id];
+
+ if ( ROAR_CLIENT(cs)->fh == -1 )
+  return -1;
+
+ roar_connect_fh(&con, ROAR_CLIENT(cs)->fh);
+
+ ROAR_DBG("clients_check(id=%i): c->proto=%i", id, ROAR_CLIENT(cs)->proto);
+
+ switch (ROAR_CLIENT(cs)->proto) {
   case ROAR_PROTO_ROARAUDIO:
     r = roar_recv_message(&con, &m, &data);
@@ -794,5 +819,5 @@
   default:
     rv = -1;
-    proto = clients_get_protohandle(c->proto);
+    proto = clients_get_protohandle(ROAR_CLIENT(cs)->proto);
     if ( proto != NULL ) {
      roar_vio_open_fh_socket(&vio, clients_get_fh(id));
@@ -807,4 +832,10 @@
         if ( proto->impl.roardproto.check_client != NULL )
          rv = proto->impl.roardproto.check_client(id, &vio);
+       break;
+      case ROARD_PROTO_TYPE_COMMON:
+        if ( proto->impl.common->handle != NULL )
+         rv = proto->impl.common->handle(id, &vio, &(cs->outbuf), &(cs->protoinst), proto->para, proto->paralen);
+        if ( rv == -1 )
+         rv = clients_delete(id);
        break;
      }
@@ -852,4 +883,14 @@
       roar_dl_context_restore(p->lhandle);
      rv = p->impl.roardproto.flush_client(id, &vio);
+     if ( p->lhandle != NULL )
+      roar_dl_context_store(p->lhandle);
+     return rv;
+    }
+   break;
+  case ROARD_PROTO_TYPE_COMMON:
+    if ( p->impl.common->flush != NULL ) {
+     if ( p->lhandle != NULL )
+      roar_dl_context_restore(p->lhandle);
+     rv = p->impl.common->flush(id, &vio, &(cs->outbuf), &(cs->protoinst), p->para, p->paralen);
      if ( p->lhandle != NULL )
       roar_dl_context_store(p->lhandle);
@@ -899,4 +940,14 @@
      }
     break;
+   case ROARD_PROTO_TYPE_COMMON:
+     if ( p->impl.common->flushed != NULL ) {
+      if ( p->lhandle != NULL )
+       roar_dl_context_restore(p->lhandle);
+      rv = p->impl.common->flushed(id, &vio, &(cs->outbuf), &(cs->protoinst), p->para, p->paralen);
+      if ( p->lhandle != NULL )
+       roar_dl_context_store(p->lhandle);
+      return rv;
+     }
+    break;
   }
  }
@@ -1037,4 +1088,30 @@
 }
 
+int clients_register_proto_common(const struct roar_dl_proto * proto, struct roar_dl_lhandle * lhandle) {
+ const size_t len = sizeof(__protos)/sizeof(*__protos);
+ size_t i;
+
+ ROAR_DBG("clients_register_proto_common(proto=%p, lhandle=%p) = ?", proto, lhandle);
+
+ if ( proto == NULL )
+  return -1;
+
+ for (i = 0; __protos[i].proto != -1; i++);
+
+ // i is now at pos of current EOS entry.
+
+ // test if we have space for one more entry:
+ if ( (i+1) >= len )
+  return -1;
+
+ __protos[i].impl.common = proto;
+
+ __protos[i].proto   = proto->proto;
+ __protos[i].type    = ROARD_PROTO_TYPE_COMMON;
+ __protos[i].lhandle = lhandle;
+
+ return 0;
+}
+
 int clients_unregister_proto(int proto) {
  size_t i;
@@ -1105,26 +1182,30 @@
    continue;
 
-  // protocols of type BUILDIN are handled above.
-  if ( p->type == ROARD_PROTO_TYPE_BUILDIN )
-   continue;
-
   strncpy(subsys, "      ", 6);
   description = "(none)";
 
-  if ( p->type == ROARD_PROTO_TYPE_ROARDPROTO ) {
-   if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_WAVEFORM )
-    subsys[0] = 'W';
-   if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_MIDI )
-    subsys[1] = 'M';
-   if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_CB )
-    subsys[2] = 'C';
-   if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_LIGHT )
-    subsys[3] = 'L';
-   if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_RAW )
-    subsys[4] = 'R';
-   if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_COMPLEX )
-    subsys[5] = 'X';
-
-   description = p->impl.roardproto.description;
+  switch (p->type) {
+   case ROARD_PROTO_TYPE_BUILDIN:
+     continue;
+    break;
+   case ROARD_PROTO_TYPE_ROARDPROTO:
+     if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_WAVEFORM )
+      subsys[0] = 'W';
+     if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_MIDI )
+      subsys[1] = 'M';
+     if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_CB )
+      subsys[2] = 'C';
+     if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_LIGHT )
+      subsys[3] = 'L';
+     if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_RAW )
+      subsys[4] = 'R';
+     if ( p->impl.roardproto.subsystems & ROAR_SUBSYS_COMPLEX )
+      subsys[5] = 'X';
+
+     description = p->impl.roardproto.description;
+    break;
+   case ROARD_PROTO_TYPE_COMMON:
+     description = p->impl.common->description;
+    break;
   }
 
Index: roard/include/client.h
===================================================================
--- roard/include/client.h	(revision 5571)
+++ roard/include/client.h	(revision 5576)
@@ -97,8 +97,11 @@
  struct roar_dl_lhandle * lhandle;
  enum roard_proto_type type;
+ const struct roar_keyval * para;
+ ssize_t paralen;
  union {
   int buildin; // dummy
   struct roard_proto roardproto;
   // add common here when ready.
+  const struct roar_dl_proto * common;
  } impl;
 };
@@ -139,4 +142,5 @@
 // proto support
 const struct roard_proto_handle * clients_get_protohandle(const int proto);
+int clients_register_proto_common(const struct roar_dl_proto * proto, struct roar_dl_lhandle * lhandle);
 int clients_register_proto  (struct roard_proto * proto, struct roar_dl_lhandle * lhandle);
 int clients_unregister_proto(int proto);
Index: roard/plugins.c
===================================================================
--- roard/plugins.c	(revision 5567)
+++ roard/plugins.c	(revision 5576)
@@ -37,4 +37,13 @@
 static int _plugins_inited = 0;
 
+static int plugin_callback(enum roar_dl_fnreg_action action, int fn, int subtype, const void * object, size_t objectlen, int version, int options, void * userdata, struct roar_dl_lhandle * lhandle);
+static const struct roar_dl_fnreg _plugin_callbacks = {
+ .fn = -1,
+ .subtype = -1,
+ .version = -1,
+ .callback = plugin_callback,
+ .userdata = NULL
+};
+
 static struct _roard_plugin * _find_free(void) {
  int i;
@@ -115,4 +124,6 @@
   return -1;
  }
+
+ roar_dl_register_fn(ROAR_DL_HANDLE_APPLICATION, ROAR_DL_FN_REGFN, ROAR_DL_FNREG_SUBTYPE, &_plugin_callbacks, ROAR_DL_FNREG_SIZE, ROAR_DL_FNREG_VERSION, ROAR_DL_FNREG_OPT_NONE);
 
  for (i = 0; i < MAX_PLUGINS; i++) {
@@ -222,3 +233,41 @@
 }
 
+static int plugin_callback(enum roar_dl_fnreg_action action, int fn, int subtype, const void * object, size_t objectlen, int version, int options, void * userdata, struct roar_dl_lhandle * lhandle) {
+
+ ROAR_DBG("plugin_callback(action=%i, fn=%i, subtype=%i, object=%p, objectlen=%llu, version=%i, options=0x%x, userdata=%p, lhandle=%p) = ?", (int)action, fn, subtype, object, (long long unsigned int)objectlen, version, options, userdata, lhandle);
+
+ switch (fn) {
+  case ROAR_DL_FN_PROTO:
+    if ( subtype != ROAR_DL_PROTO_SUBTYPE ) {
+     ROAR_DBG("plugin_callback(action=%i, fn=%i, subtype=%i, object=%p, objectlen=%llu, version=%i, options=0x%x, userdata=%p, lhandle=%p) = -1 // error=TYPEMM", (int)action, fn, subtype, object, (long long unsigned int)objectlen, version, options, userdata, lhandle);
+
+     roar_err_set(ROAR_ERROR_TYPEMM);
+     return -1;
+    }
+    if ( objectlen != ROAR_DL_PROTO_SIZE ) {
+     ROAR_DBG("plugin_callback(action=%i, fn=%i, subtype=%i, object=%p, objectlen=%llu, version=%i, options=0x%x, userdata=%p, lhandle=%p) = -1 // error=BADLIB", (int)action, fn, subtype, object, (long long unsigned int)objectlen, version, options, userdata, lhandle);
+     roar_err_set(ROAR_ERROR_BADLIB);
+     return -1;
+    }
+    if ( version != ROAR_DL_PROTO_VERSION ) {
+     ROAR_DBG("plugin_callback(action=%i, fn=%i, subtype=%i, object=%p, objectlen=%llu, version=%i, options=0x%x, userdata=%p, lhandle=%p) = -1 // error=BADVERSION", (int)action, fn, subtype, object, (long long unsigned int)objectlen, version, options, userdata, lhandle);
+     roar_err_set(ROAR_ERROR_BADVERSION);
+     return -1;
+    }
+    switch (action) {
+     case ROAR_DL_FNREG:
+       return clients_register_proto_common(object, lhandle);
+      break;
+     case ROAR_DL_FNUNREG:
+       return clients_unregister_proto(((const struct roard_proto *)object)->proto);
+      break;
+    }
+   break;
+ }
+
+ ROAR_DBG("plugin_callback(action=%i, fn=%i, subtype=%i, object=%p, objectlen=%llu, version=%i, options=0x%x, userdata=%p, lhandle=%p) = -1 // error=NOTSUP", (int)action, fn, subtype, object, (long long unsigned int)objectlen, version, options, userdata, lhandle);
+ roar_err_set(ROAR_ERROR_NOTSUP);
+ return -1;
+}
+
 //ll
