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;
   }
 
