dbus/mono/Handler.cs

234 lines
5.7 KiB
C#

namespace DBus
{
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;
using System.Collections;
internal enum Result
{
Handled = 0,
NotYetHandled = 1,
NeedMemory = 2
}
internal class Handler : IDisposable
{
private string path = null;
private Introspector introspector = null;
private object handledObject = null;
private DBusObjectPathVTable vTable;
private Connection connection;
private Service service;
private bool disposed = false;
internal delegate void DBusObjectPathUnregisterFunction(IntPtr rawConnection,
IntPtr userData);
internal delegate int DBusObjectPathMessageFunction(IntPtr rawConnection,
IntPtr rawMessage,
IntPtr userData);
[StructLayout (LayoutKind.Sequential)]
private struct DBusObjectPathVTable
{
public DBusObjectPathUnregisterFunction unregisterFunction;
public DBusObjectPathMessageFunction messageFunction;
public IntPtr padding1;
public IntPtr padding2;
public IntPtr padding3;
public IntPtr padding4;
public DBusObjectPathVTable(DBusObjectPathUnregisterFunction unregisterFunction,
DBusObjectPathMessageFunction messageFunction)
{
this.unregisterFunction = unregisterFunction;
this.messageFunction = messageFunction;
this.padding1 = IntPtr.Zero;
this.padding2 = IntPtr.Zero;
this.padding3 = IntPtr.Zero;
this.padding4 = IntPtr.Zero;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed) {
if (disposing) {
// Clean up managed resources
}
service = null;
// Clean up unmanaged resources
if (Connection != null && Connection.RawConnection != IntPtr.Zero && Path != null) {
dbus_connection_unregister_object_path(Connection.RawConnection,
Path);
}
connection = null;
introspector = null;
handledObject = null;
}
disposed = true;
}
~Handler()
{
Dispose(false);
}
public Handler(object handledObject,
string path,
Service service)
{
Service = service;
Connection = service.Connection;
HandledObject = handledObject;
this.path = path;
// Create the vTable and register the path
vTable = new DBusObjectPathVTable(new DBusObjectPathUnregisterFunction(Unregister_Called),
new DBusObjectPathMessageFunction(Message_Called));
if (!dbus_connection_register_object_path(Connection.RawConnection,
Path,
ref vTable,
IntPtr.Zero))
throw new OutOfMemoryException();
RegisterSignalHandlers();
}
private void RegisterSignalHandlers()
{
ProxyBuilder proxyBuilder = new ProxyBuilder(Service, HandledObject.GetType(), Path);
foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
foreach (DictionaryEntry signalEntry in interfaceProxy.Signals) {
EventInfo eventE = (EventInfo) signalEntry.Value;
Delegate del = Delegate.CreateDelegate(eventE.EventHandlerType, proxyBuilder.GetSignalProxy(), "Proxy_" + eventE.Name);
eventE.AddEventHandler(HandledObject, del);
}
}
}
public object HandledObject
{
get {
return this.handledObject;
}
set {
this.handledObject = value;
object[] attributes;
// Register the methods
this.introspector = Introspector.GetIntrospector(value.GetType());
}
}
public void Unregister_Called(IntPtr rawConnection,
IntPtr userData)
{
if (service != null) {
service.UnregisterObject(HandledObject);
}
path = null;
}
private int Message_Called(IntPtr rawConnection,
IntPtr rawMessage,
IntPtr userData)
{
Message message = Message.Wrap(rawMessage, Service);
switch (message.Type) {
case Message.MessageType.Signal:
// We're not interested in signals here because we're the ones
// that generate them!
break;
case Message.MessageType.MethodCall:
return (int) HandleMethod((MethodCall) message);
}
return (int) Result.NotYetHandled;
}
private Result HandleMethod(MethodCall methodCall)
{
methodCall.Service = service;
InterfaceProxy interfaceProxy = this.introspector.GetInterface(methodCall.InterfaceName);
if (interfaceProxy == null || !interfaceProxy.HasMethod(methodCall.Key)) {
// No such interface here.
return Result.NotYetHandled;
}
MethodInfo method = interfaceProxy.GetMethod(methodCall.Key);
// Now call the method. FIXME: Error handling
object [] args = methodCall.Arguments.GetParameters(method);
object retVal = method.Invoke(this.handledObject, args);
// Create the reply and send it
MethodReturn methodReturn = new MethodReturn(methodCall);
methodReturn.Arguments.AppendResults(method, retVal, args);
methodReturn.Send();
return Result.Handled;
}
internal string Path
{
get
{
return path;
}
}
internal Connection Connection
{
get
{
return connection;
}
set
{
this.connection = value;
}
}
public Service Service
{
get
{
return service;
}
set
{
this.service = value;
}
}
[DllImport ("dbus-1")]
private extern static bool dbus_connection_register_object_path (IntPtr rawConnection, string path, ref DBusObjectPathVTable vTable, IntPtr userData);
[DllImport ("dbus-1")]
private extern static void dbus_connection_unregister_object_path (IntPtr rawConnection, string path);
}
}