Index: ChangeLog
===================================================================
--- ChangeLog	(revision 5565)
+++ ChangeLog	(revision 5567)
@@ -2,4 +2,5 @@
 	* Stop building roard with -rdynamic on win32 (Closes: #269)
 	* Renamed protocol plugins for roard to protocol-* (Closes: #258)
+	* roard now tries to auto load missing protocols as plugins (Closes: #275)
 
 v. 1.0beta3 - Sun Jul 15 2012 26:08 CEST
Index: roard/clients.c
===================================================================
--- roard/clients.c	(revision 5452)
+++ roard/clients.c	(revision 5567)
@@ -32,20 +32,22 @@
 // declared 'extern'
 struct roar_client_server * g_clients[ROAR_CLIENTS_MAX];
-struct roard_proto g_proto[MAX_PROTOS];
-
-
-struct roard_proto g_proto[MAX_PROTOS] = {
-#ifndef ROAR_WITHOUT_DCOMP_EMUL_ESD
-#ifdef ROAR_HAVE_H_ESD
- {ROAR_PROTO_ESOUND, ROAR_SUBSYS_WAVEFORM, "EsounD emulation", NULL, NULL, NULL, emul_esd_check_client, NULL, NULL},
-#endif
+
+static struct roard_proto_handle __protos[MAX_PROTOS] = {
+ {.proto = ROAR_PROTO_ROARAUDIO, .lhandle = NULL, .type = ROARD_PROTO_TYPE_BUILDIN,
+ .impl = {.buildin = 0}},
+#if !defined(ROAR_WITHOUT_DCOMP_EMUL_ESD) && defined(ROAR_HAVE_H_ESD)
+ {.proto = ROAR_PROTO_ESOUND, .lhandle = NULL, .type = ROARD_PROTO_TYPE_ROARDPROTO,
+ .impl = {.roardproto = {ROAR_PROTO_ESOUND, ROAR_SUBSYS_WAVEFORM, "EsounD emulation", NULL, NULL, NULL, emul_esd_check_client, NULL, NULL}}},
 #endif
 #ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
- {ROAR_PROTO_RPLAY, ROAR_SUBSYS_WAVEFORM, "RPlay emulation", NULL, NULL, NULL, emul_rplay_check_client, NULL, NULL},
+ {.proto = ROAR_PROTO_RPLAY, .lhandle = NULL, .type = ROARD_PROTO_TYPE_ROARDPROTO,
+ .impl = {.roardproto = {ROAR_PROTO_RPLAY, ROAR_SUBSYS_WAVEFORM, "RPlay emulation", NULL, NULL, NULL, emul_rplay_check_client, NULL, NULL}}},
 #endif
 #ifndef ROAR_WITHOUT_DCOMP_EMUL_GOPHER
- {ROAR_PROTO_GOPHER, ROAR_SUBSYS_WAVEFORM, "The Internet Gopher Protocol", NULL, NULL, NULL, emul_gopher_check_client, NULL, emul_gopher_flushed_client},
-#endif
- {-1, 0, NULL, NULL, NULL, NULL, NULL, NULL}
+ {.proto = ROAR_PROTO_GOPHER, .lhandle = NULL, .type = ROARD_PROTO_TYPE_ROARDPROTO,
+ .impl = {.roardproto = {ROAR_PROTO_GOPHER, ROAR_SUBSYS_WAVEFORM, "The Internet Gopher Protocol", NULL, NULL, NULL, emul_gopher_check_client, NULL,
+ emul_gopher_flushed_client}}},
+#endif
+ {.proto = -1}
 };
 
@@ -59,8 +61,8 @@
   g_clients[i] = NULL;
 
- for (i = 0; g_proto[i].proto != -1; i++);
+ for (i = 0; __protos[i].proto != -1; i++);
 
  for (; i < MAX_PROTOS; i++)
-  g_proto[i].proto = -1;
+  __protos[i].proto = -1;
 
  return 0;
@@ -164,4 +166,5 @@
 int clients_delete (int id) {
  struct roar_client_server * cs;
+ const struct roard_proto_handle * proto;
  int i;
  int close_client_fh = 1;
@@ -173,9 +176,14 @@
  cs = g_clients[id];
 
- for (i = 0; g_proto[i].proto != -1; i++) {
-  if ( g_proto[i].proto == ROAR_CLIENT(cs)->proto ) {
-   if ( g_proto[i].delete_client != NULL ) {
-    g_proto[i].delete_client(id);
-   }
+ proto = clients_get_protohandle(ROAR_CLIENT(cs)->proto);
+ if ( proto != NULL ) {
+  switch (proto->type) {
+   case ROARD_PROTO_TYPE_BUILDIN:
+     /* noop */
+    break;
+   case ROARD_PROTO_TYPE_ROARDPROTO:
+     if ( proto->impl.roardproto.delete_client != NULL )
+      proto->impl.roardproto.delete_client(id);
+    break;
   }
  }
@@ -558,4 +566,5 @@
  struct roar_vio_calls  vio;
  struct roar_error_state errstate;
+ const struct roard_proto_handle * proto;
  int command_error;
  char * data = NULL;
@@ -565,5 +574,4 @@
  uint32_t flags[2] = {COMMAND_FLAG_NONE, COMMAND_FLAG_NONE};
  uint32_t event;
- size_t i;
 
  ROAR_DBG("clients_check(id=%i) = ?", id);
@@ -655,13 +663,22 @@
   default:
     rv = -1;
-    for (i = 0; g_proto[i].proto != -1; i++) {
-     if ( g_proto[i].proto == c->proto ) {
-      roar_vio_open_fh_socket(&vio, clients_get_fh(id));
-      if ( g_proto[i].lhandle != NULL )
-       roar_dl_context_restore(g_proto[i].lhandle);
-      rv = g_proto[i].check_client(id, &vio);
-      if ( g_proto[i].lhandle != NULL )
-       roar_dl_context_store(g_proto[i].lhandle);
+    proto = clients_get_protohandle(c->proto);
+    if ( proto != NULL ) {
+     roar_vio_open_fh_socket(&vio, clients_get_fh(id));
+     if ( proto->lhandle != NULL )
+      roar_dl_context_restore(proto->lhandle);
+
+     switch (proto->type) {
+      case ROARD_PROTO_TYPE_BUILDIN:
+        ROAR_WARN("clients_check(id=%i): proto(%i) marked as buildin but isn't. BAD.", id, proto->proto);
+       break;
+      case ROARD_PROTO_TYPE_ROARDPROTO:
+        if ( proto->impl.roardproto.check_client != NULL )
+         rv = proto->impl.roardproto.check_client(id, &vio);
+       break;
      }
+
+     if ( proto->lhandle != NULL )
+      roar_dl_context_store(proto->lhandle);
     }
  }
@@ -675,12 +692,12 @@
 
 int clients_flush      (int id) {
- struct roar_vio_calls         vio;
- struct roar_client_server   * cs;
- struct roar_client          * c;
- struct roard_proto          * p = NULL;
- size_t i;
+ struct roar_vio_calls             vio;
+ struct roar_client_server       * cs;
+ struct roar_client              * c;
+ const struct roard_proto_handle * p;
  size_t len;
  ssize_t ret;
  void * buf;
+ int rv;
 
  _CHECK_CID(id);
@@ -688,22 +705,25 @@
  c = ROAR_CLIENT(cs = g_clients[id]);
 
- for (i = 0; g_proto[i].proto != -1; i++) {
-  if ( g_proto[i].proto == c->proto ) {
-   p = &(g_proto[i]);
+ p = clients_get_protohandle(c->proto);
+
+ if ( p == NULL )
+  return -1;
+
+ roar_vio_open_fh_socket(&vio, clients_get_fh(id));
+
+ switch (p->type) {
+  case ROARD_PROTO_TYPE_BUILDIN:
+    /* noop */
    break;
-  }
- }
-
- if ( p == NULL )
-  return -1;
-
- roar_vio_open_fh_socket(&vio, clients_get_fh(id));
-
- if ( p->flush_client != NULL ) {
-  if ( p->lhandle != NULL )
-   roar_dl_context_restore(p->lhandle);
-  return p->flush_client(id, &vio);
-  if ( p->lhandle != NULL )
-   roar_dl_context_store(p->lhandle);
+  case ROARD_PROTO_TYPE_ROARDPROTO:
+    if ( p->impl.roardproto.flush_client != NULL ) {
+     if ( p->lhandle != NULL )
+      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;
  }
 
@@ -734,10 +754,18 @@
 
  if ( cs->outbuf == NULL ) {
-  if ( p->flushed_client != NULL ) {
-   if ( p->lhandle != NULL )
-    roar_dl_context_restore(p->lhandle);
-   return p->flushed_client(id, &vio);
-   if ( p->lhandle != NULL )
-    roar_dl_context_store(p->lhandle);
+  switch (p->type) {
+   case ROARD_PROTO_TYPE_BUILDIN:
+     /* noop */
+    break;
+   case ROARD_PROTO_TYPE_ROARDPROTO:
+     if ( p->impl.roardproto.flushed_client != NULL ) {
+      if ( p->lhandle != NULL )
+       roar_dl_context_restore(p->lhandle);
+      rv = p->impl.roardproto.flushed_client(id, &vio);
+      if ( p->lhandle != NULL )
+       roar_dl_context_store(p->lhandle);
+      return rv;
+     }
+    break;
   }
  }
@@ -836,6 +864,22 @@
 
 // proto support
+const struct roard_proto_handle * clients_get_protohandle(const int proto) {
+ size_t i;
+
+ if ( proto < 0 ) {
+  roar_err_set(ROAR_ERROR_INVAL);
+  return NULL;
+ }
+
+ for (i = 0; i < (sizeof(__protos)/sizeof(*__protos)); i++)
+  if ( __protos[i].proto == proto )
+   return &(__protos[i]);
+
+ roar_err_set(ROAR_ERROR_NOENT);
+ return NULL;
+}
+
 int clients_register_proto(struct roard_proto * proto, struct roar_dl_lhandle * lhandle) {
- const size_t len = sizeof(g_proto)/sizeof(*g_proto);
+ const size_t len = sizeof(__protos)/sizeof(*__protos);
  size_t i;
 
@@ -843,5 +887,5 @@
   return -1;
 
- for (i = 0; g_proto[i].proto != -1; i++);
+ for (i = 0; __protos[i].proto != -1; i++);
 
  // i is now at pos of current EOS entry.
@@ -851,7 +895,11 @@
   return -1;
 
- memcpy(&(g_proto[i]), proto, sizeof(*g_proto));
-
- g_proto[i].lhandle = lhandle;
+ memcpy(&(__protos[i].impl.roardproto), proto, sizeof(__protos[i].impl.roardproto));
+
+ __protos[i].impl.roardproto.lhandle = lhandle;
+
+ __protos[i].proto   = proto->proto;
+ __protos[i].type    = ROARD_PROTO_TYPE_ROARDPROTO;
+ __protos[i].lhandle = lhandle;
 
  return 0;
@@ -859,5 +907,4 @@
 
 int clients_unregister_proto(int proto) {
- const size_t len = sizeof(g_proto)/sizeof(*g_proto);
  size_t i;
 
@@ -867,8 +914,8 @@
  }
 
- for (i = 0; i < len; i++) {
-  if ( g_proto[i].proto == proto ) {
-   memset(&(g_proto[i]), 0, sizeof(*g_proto));
-   g_proto[i].proto = -1;
+ for (i = 0; i < (sizeof(__protos)/sizeof(*__protos)); i++) {
+  if ( __protos[i].proto == proto ) {
+   memset(&(__protos[i]), 0, sizeof(*__protos));
+   __protos[i].proto = -1;
    return 0;
   }
@@ -880,7 +927,7 @@
 
 void print_protolist        (enum output_format format) {
- const size_t len = sizeof(g_proto)/sizeof(*g_proto);
- struct roard_proto * p;
+ struct roard_proto_handle * p;
  char subsys[7] = "      ";
+ const char * description;
  size_t i;
 
@@ -922,33 +969,38 @@
  }
 
- for (i = 0; i < len; i++) {
-  p = &(g_proto[i]);
+ for (i = 0; i < (sizeof(__protos)/sizeof(*__protos)); i++) {
+  p = &(__protos[i]);
   if ( p->proto == -1 )
    continue;
 
   strncpy(subsys, "      ", 6);
-
-  if ( p->subsystems & ROAR_SUBSYS_WAVEFORM )
-   subsys[0] = 'W';
-  if ( p->subsystems & ROAR_SUBSYS_MIDI )
-   subsys[1] = 'M';
-  if ( p->subsystems & ROAR_SUBSYS_CB )
-   subsys[2] = 'C';
-  if ( p->subsystems & ROAR_SUBSYS_LIGHT )
-   subsys[3] = 'L';
-  if ( p->subsystems & ROAR_SUBSYS_RAW )
-   subsys[4] = 'R';
-  if ( p->subsystems & ROAR_SUBSYS_COMPLEX )
-   subsys[5] = 'X';
+  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 (format) {
    case FORMAT_NATIVE:
-     printf("  %-13s %s - %s\n", roar_proto2str(p->proto), subsys, p->description);
+     printf("  %-13s %s - %s\n", roar_proto2str(p->proto), subsys, description);
     break;
    case FORMAT_WIKI:
-     printf("||%s || ||%s ||%s ||\n", roar_proto2str(p->proto), subsys, p->description);
+     printf("||%s || ||%s ||%s ||\n", roar_proto2str(p->proto), subsys, description);
     break;
    case FORMAT_CSV:
-     printf("%s,,%s,%s\n", roar_proto2str(p->proto), subsys, p->description);
+     printf("%s,,%s,%s\n", roar_proto2str(p->proto), subsys, description);
     break;
   }
Index: roard/include/client.h
===================================================================
--- roard/include/client.h	(revision 5448)
+++ roard/include/client.h	(revision 5567)
@@ -87,6 +87,22 @@
 };
 
+enum roard_proto_type {
+ ROARD_PROTO_TYPE_BUILDIN = 0,
+ ROARD_PROTO_TYPE_ROARDPROTO = 1,
+ ROARD_PROTO_TYPE_COMMON = 2
+};
+
+struct roard_proto_handle {
+ int proto;
+ struct roar_dl_lhandle * lhandle;
+ enum roard_proto_type type;
+ union {
+  int buildin; // dummy
+  struct roard_proto roardproto;
+  // add common here when ready.
+ } impl;
+};
+
 #define MAX_PROTOS 8
-extern struct roard_proto g_proto[MAX_PROTOS];
 
 // basic functions
@@ -119,4 +135,5 @@
 
 // proto support
+const struct roard_proto_handle * clients_get_protohandle(const int proto);
 int clients_register_proto  (struct roard_proto * proto, struct roar_dl_lhandle * lhandle);
 int clients_unregister_proto(int proto);
Index: roard/network.c
===================================================================
--- roard/network.c	(revision 5381)
+++ roard/network.c	(revision 5567)
@@ -70,4 +70,5 @@
 
 int net_get_new_client (struct roard_listen * lsock) {
+ const struct roard_proto_handle * proto;
  int fh;
  int client;
@@ -77,5 +78,4 @@
  struct sockaddr_storage  addr;
  socklen_t                addrlen = sizeof(addr);
- size_t i;
  int supported = 0;
 
@@ -191,13 +191,21 @@
      return -1;
 
-    for (i = 0; g_proto[i].proto != -1; i++) {
-     //printf("g_proto[i=%i].proto=%i, lsock->proto=%i\n", (int)i, g_proto[i].proto, lsock->proto);
-     if ( g_proto[i].proto == lsock->proto ) {
-      supported = 1;
-      if ( g_proto[i].new_client != NULL ) {
-       if ( g_proto[i].new_client(client, &vio, lsock) == -1 ) {
+    proto = clients_get_protohandle(lsock->proto);
+    supported = 0;
+    if ( proto != NULL ) {
+     switch (proto->type) {
+      case ROARD_PROTO_TYPE_BUILDIN:
+        //this should not end up here.
+        ROAR_WARN("net_get_new_client(lsock=%p): proto(%i) marked as buildin but isn't. BAD.", lsock, lsock->proto);
         supported = 0;
-       }
-      }
+       break;
+      case ROARD_PROTO_TYPE_ROARDPROTO:
+        supported = 1;
+        if ( proto->impl.roardproto.new_client != NULL ) {
+         if ( proto->impl.roardproto.new_client(client, &vio, lsock) == -1 ) {
+          supported = 0;
+         }
+        }
+       break;
      }
     }
Index: roard/plugins.c
===================================================================
--- roard/plugins.c	(revision 5427)
+++ roard/plugins.c	(revision 5567)
@@ -35,4 +35,6 @@
 static struct _roard_plugin * _pp = NULL;
 
+static int _plugins_inited = 0;
+
 static struct _roard_plugin * _find_free(void) {
  int i;
@@ -78,32 +80,47 @@
 }
 
+static int plugins_init_one(struct _roard_plugin * plugin) {
+ if ( plugin == NULL )
+  return -1;
+
+ _pp = plugin;
+ _pp->sched = NULL;
+
+ if ( roar_dl_ra_init(plugin->lhandle, NULL, NULL) == -1 ) {
+  ROAR_WARN("plugins_init(void): Can not RA init lib at %p: %s", plugin->lhandle, roar_error2str(roar_error));
+  plugins_delete(plugin);
+  return -1;
+ }
+
+ if ( plugin->sched != NULL ) {
+  if ( plugin->sched->init != NULL ) {
+   roar_dl_context_restore(plugin->lhandle);
+   plugin->sched->init();
+   roar_dl_context_store(plugin->lhandle);
+  }
+ }
+
+ roar_dl_appsched_trigger(plugin->lhandle, ROAR_DL_APPSCHED_INIT);
+
+ _pp = NULL;
+
+ return 0;
+}
+
 int plugins_init  (void) {
- int i;
+ size_t i;
+
+ if ( _plugins_inited ) {
+  roar_err_set(ROAR_ERROR_BUSY);
+  return -1;
+ }
 
  for (i = 0; i < MAX_PLUGINS; i++) {
   if ( g_plugins[i].lhandle != NULL ) {
-   _pp = &(g_plugins[i]);
-
-   _pp->sched = NULL;
-
-   if ( roar_dl_ra_init(g_plugins[i].lhandle, NULL, NULL) == -1 ) {
-    ROAR_WARN("plugins_init(void): Can not RA init lib at %p: %s", g_plugins[i].lhandle, roar_error2str(roar_error));
-    plugins_delete(&(g_plugins[i]));
-    continue;
-   }
-
-   if ( g_plugins[i].sched != NULL ) {
-    if ( g_plugins[i].sched->init != NULL ) {
-     roar_dl_context_restore(g_plugins[i].lhandle);
-     g_plugins[i].sched->init();
-     roar_dl_context_store(g_plugins[i].lhandle);
-    }
-   }
-
-   roar_dl_appsched_trigger(g_plugins[i].lhandle, ROAR_DL_APPSCHED_INIT);
-
-   _pp = NULL;
-  }
- }
+   plugins_init_one(&(g_plugins[i]));
+  }
+ }
+
+ _plugins_inited = 1;
 
  return 0;
@@ -169,4 +186,7 @@
  }
 
+ if ( _plugins_inited )
+  return plugins_init_one(next);
+
  return 0;
 }
Index: roard/roard.c
===================================================================
--- roard/roard.c	(revision 5566)
+++ roard/roard.c	(revision 5567)
@@ -953,4 +953,49 @@
  return 0;
 }
+
+static int check_listen(void) {
+ const struct roard_proto_handle * proto;
+ const char * protoname;
+ char buffer[80];
+ size_t i, j;
+
+ for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) {
+  if ( g_listen[i].used ) {
+   proto = clients_get_protohandle(g_listen[i].proto);
+   if ( proto != NULL )
+    continue;
+   protoname = roar_proto2str(g_listen[i].proto);
+   if ( protoname == NULL ) {
+    ROAR_ERR("check_listen(void): protocol %i is unknown (protocol ID not assigned?).");
+   } else {
+    ROAR_DBG("check_listen(void): Unknown protocol %s(%i) is used.", protoname, g_listen[i].proto);
+    snprintf(buffer, sizeof(buffer), "protocol-%s", protoname);
+    for (j = 0; buffer[j]; j++)
+     buffer[j] = tolower(buffer[j]);
+
+    ROAR_DBG("check_listen(void): Trying to load plugin \"%s\"", buffer);
+    if ( plugins_load(buffer, NULL) == -1 ) {
+     ROAR_WARN("check_listen(void): unabled to load plugin: %s: %s", buffer, roar_errorstring);
+    }
+   }
+
+   // recheck:
+   proto = clients_get_protohandle(g_listen[i].proto);
+   if ( proto == NULL ) {
+    ROAR_WARN("check_listen(void): Protocol %s(%i) is still unknown. Deleting listen socket.", protoname, g_listen[i].proto);
+    roar_vio_close(&(g_listen[i].sock));
+#ifdef ROAR_HAVE_UNIX
+    if ( server[i] != NULL )
+     if ( server[i][0] == '/' )
+      unlink(server[i]);
+#endif
+    g_listen[i].used = 0;
+    server[i] = NULL;
+   }
+  }
+ }
+
+ return 0;
+}
 #endif
 
@@ -2400,4 +2445,8 @@
  }
 
+ if ( check_listen() == -1 ) {
+  ROAR_ERR("Can not check listen sockets. BAD.");
+  return 1;
+ }
 
  // we should handle this on microcontrollers, too.
