libfreerdp-utils: add svc_plugin.
authorVic Lee <llyzs@163.com>
Sat, 9 Jul 2011 15:29:04 +0000 (23:29 +0800)
committerVic Lee <llyzs@163.com>
Sat, 9 Jul 2011 15:29:04 +0000 (23:29 +0800)
cmake/ConfigOptions.cmake
config.h.in
include/freerdp/utils/svc_plugin.h [new file with mode: 0644]
libfreerdp-utils/CMakeLists.txt
libfreerdp-utils/svc_plugin.c [new file with mode: 0644]

index 8c1f256..9c681f2 100644 (file)
@@ -1,2 +1,3 @@
 option(WITH_DEBUG_TRANSPORT "Print transport debug message." OFF)
 option(WITH_DEBUG_CHANMAN "Print channel manager debug message." OFF)
+option(WITH_DEBUG_SVC "Print static virtual channel debug message." OFF)
index 77cd75c..1d70425 100644 (file)
@@ -11,3 +11,4 @@
 /* Options */
 #cmakedefine WITH_DEBUG_TRANSPORT
 #cmakedefine WITH_DEBUG_CHANMAN
+#cmakedefine WITH_DEBUG_SVC
diff --git a/include/freerdp/utils/svc_plugin.h b/include/freerdp/utils/svc_plugin.h
new file mode 100644 (file)
index 0000000..0412047
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Static Virtual Channel Interface
+ *
+ * Copyright 2009-2011 Jay Sorg
+ * Copyright 2010-2011 Vic Lee
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SVC_PLUGIN_UTILS_H
+#define __SVC_PLUGIN_UTILS_H
+
+/* static channel plugin base implementation */
+
+#include <freerdp/svc.h>
+
+typedef struct rdp_svc_plugin_private rdpSvcPluginPrivate;
+typedef struct rdp_svc_plugin rdpSvcPlugin;
+struct rdp_svc_plugin
+{
+       CHANNEL_ENTRY_POINTS channel_entry_points;
+       CHANNEL_DEF channel_def;
+
+       void (*connect_callback)(rdpSvcPlugin* plugin);
+       void (*receive_callback)(rdpSvcPlugin* plugin, uint8* data, int size);
+       void (*terminate_callback)(rdpSvcPlugin* plugin);
+
+       rdpSvcPluginPrivate* priv;
+};
+
+void svc_plugin_init(rdpSvcPlugin* plugin);
+int svc_plugin_send(rdpSvcPlugin* plugin, uint8* data, int size);
+
+#endif /* __SVC_PLUGIN_UTILS_H */
index 4ef3760..fdec57e 100644 (file)
@@ -25,6 +25,7 @@ set(FREERDP_UTILS_SRCS
        mutex.c
        semaphore.c
        stream.c
+       svc_plugin.c
        unicode.c
        wait_obj.c)
 
diff --git a/libfreerdp-utils/svc_plugin.c b/libfreerdp-utils/svc_plugin.c
new file mode 100644 (file)
index 0000000..0d36be2
--- /dev/null
@@ -0,0 +1,233 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol client.
+ * Static Virtual Channel Interface
+ *
+ * Copyright 2009-2011 Jay Sorg
+ * Copyright 2010-2011 Vic Lee
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <freerdp/utils/memory.h>
+#include <freerdp/utils/mutex.h>
+#include <freerdp/utils/debug.h>
+#include <freerdp/utils/svc_plugin.h>
+
+#ifdef WITH_DEBUG_SVC
+#define DEBUG_SVC(fmt, ...) DEBUG_CLASS(SVC, fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_SVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
+#endif
+
+/* The list of all plugin instances. */
+typedef struct rdp_svc_plugin_list rdpSvcPluginList;
+struct rdp_svc_plugin_list
+{
+       rdpSvcPlugin* plugin;
+       rdpSvcPluginList* next;
+};
+
+static rdpSvcPluginList* g_svc_plugin_list = NULL;
+
+/* For locking the global resources */
+static freerdp_mutex g_mutex = NULL;
+
+struct rdp_svc_plugin_private
+{
+       void* init_handle;
+       uint32 open_handle;
+};
+
+static rdpSvcPlugin* svc_plugin_find_by_init_handle(void* init_handle)
+{
+       rdpSvcPluginList * list;
+       rdpSvcPlugin * plugin;
+
+       freerdp_mutex_lock(g_mutex);
+       for (list = g_svc_plugin_list; list; list = list->next)
+       {
+               plugin = list->plugin;
+               if (plugin->priv->init_handle == init_handle)
+               {
+                       freerdp_mutex_unlock(g_mutex);
+                       return plugin;
+               }
+       }
+       freerdp_mutex_unlock(g_mutex);
+       return NULL;
+}
+
+static rdpSvcPlugin* svc_plugin_find_by_open_handle(uint32 open_handle)
+{
+       rdpSvcPluginList * list;
+       rdpSvcPlugin * plugin;
+
+       freerdp_mutex_lock(g_mutex);
+       for (list = g_svc_plugin_list; list; list = list->next)
+       {
+               plugin = list->plugin;
+               if (plugin->priv->open_handle == open_handle)
+               {
+                       freerdp_mutex_unlock(g_mutex);
+                       return plugin;
+               }
+       }
+       freerdp_mutex_unlock(g_mutex);
+       return NULL;
+}
+
+static void svc_plugin_remove(rdpSvcPlugin* plugin)
+{
+       rdpSvcPluginList* list;
+       rdpSvcPluginList* prev;
+
+       /* Remove from global list */
+       freerdp_mutex_lock(g_mutex);
+       for (prev = NULL, list = g_svc_plugin_list; list; prev = list, list = list->next)
+       {
+               if (list->plugin == plugin)
+                       break;
+       }
+       if (list)
+       {
+               if (prev)
+                       prev->next = list->next;
+               else
+                       g_svc_plugin_list = list->next;
+               xfree(list);
+       }
+       freerdp_mutex_unlock(g_mutex);
+}
+
+static void svc_plugin_process_received(rdpSvcPlugin* plugin, void* pData, uint32 dataLength,
+       uint32 totalLength, uint32 dataFlags)
+{
+       plugin->receive_callback(plugin, (uint8*)pData, dataLength);
+}
+
+static void svc_plugin_open_event(uint32 openHandle, uint32 event, void* pData, uint32 dataLength,
+       uint32 totalLength, uint32 dataFlags)
+{
+       rdpSvcPlugin* plugin;
+
+       DEBUG_SVC("event %d dataLength %d", event, dataLength);
+
+       plugin = (rdpSvcPlugin*)svc_plugin_find_by_open_handle(openHandle);
+       if (plugin == NULL)
+       {
+               printf("svc_plugin_open_event: error no match\n");
+               return;
+       }
+       switch (event)
+       {
+               case CHANNEL_EVENT_DATA_RECEIVED:
+                       svc_plugin_process_received(plugin, pData, dataLength, totalLength, dataFlags);
+                       break;
+               case CHANNEL_EVENT_WRITE_COMPLETE:
+                       xfree(pData);
+                       break;
+       }
+}
+
+static void svc_plugin_process_connected(rdpSvcPlugin* plugin, void* pData, uint32 dataLength)
+{
+       uint32 error;
+
+       error = plugin->channel_entry_points.pVirtualChannelOpen(plugin->priv->init_handle, &plugin->priv->open_handle,
+               plugin->channel_def.name, svc_plugin_open_event);
+       if (error != CHANNEL_RC_OK)
+       {
+               printf("svc_plugin_process_connected: open failed\n");
+               return;
+       }
+       plugin->connect_callback(plugin);
+}
+
+static void svc_plugin_process_terminated(rdpSvcPlugin* plugin)
+{
+       plugin->channel_entry_points.pVirtualChannelClose(plugin->priv->open_handle);
+       svc_plugin_remove(plugin);
+       xfree(plugin->priv);
+       plugin->priv = NULL;
+       plugin->terminate_callback(plugin);
+}
+
+static void svc_plugin_init_event(void* pInitHandle, uint32 event, void* pData, uint32 dataLength)
+{
+       rdpSvcPlugin* plugin;
+
+       DEBUG_SVC("event %d", event);
+
+       plugin = (rdpSvcPlugin*)svc_plugin_find_by_init_handle(pInitHandle);
+       if (plugin == NULL)
+       {
+               printf("svc_plugin_init_event: error no match\n");
+               return;
+       }
+       switch (event)
+       {
+               case CHANNEL_EVENT_CONNECTED:
+                       svc_plugin_process_connected(plugin, pData, dataLength);
+                       break;
+               case CHANNEL_EVENT_DISCONNECTED:
+                       break;
+               case CHANNEL_EVENT_TERMINATED:
+                       svc_plugin_process_terminated(plugin);
+                       break;
+       }
+}
+
+void svc_plugin_init(rdpSvcPlugin* plugin)
+{
+       rdpSvcPluginList* list;
+
+       /**
+        * The channel manager will guarantee only one thread can call
+        * VirtualChannelInit at a time. So this should be safe.
+        */
+       if (g_mutex == NULL)
+               g_mutex = freerdp_mutex_new();
+
+       plugin->priv = (rdpSvcPluginPrivate*)xmalloc(sizeof(rdpSvcPluginPrivate));
+       memset(plugin->priv, 0, sizeof(rdpSvcPluginPrivate));
+
+       /* Add it to the global list */
+       list = (rdpSvcPluginList*)xmalloc(sizeof(rdpSvcPluginList));
+       list->plugin = plugin;
+
+       freerdp_mutex_lock(g_mutex);
+       list->next = g_svc_plugin_list;
+       g_svc_plugin_list = list;
+       freerdp_mutex_unlock(g_mutex);
+
+       plugin->channel_entry_points.pVirtualChannelInit(&plugin->priv->init_handle,
+               &plugin->channel_def, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, svc_plugin_init_event);
+}
+
+int svc_plugin_send(rdpSvcPlugin* plugin, uint8* data, int size)
+{
+       uint32 error = 0;
+
+       DEBUG_SVC("size %d", size);
+
+       error = plugin->channel_entry_points.pVirtualChannelWrite(plugin->priv->open_handle,
+               data, size, data);
+       if (error != CHANNEL_RC_OK)
+               printf("svc_plugin_send: VirtualChannelWrite failed %d", error);
+
+       return error;
+}