dbus/mono/Handler.cs
Joe Shaw 2958e723fc 2005-03-08 Joe Shaw <joeshaw@novell.com>
Fix a bunch of lifecycle and memory management problems
	in the mono bindings.

	* mono/Arguments.cs (Arguments): Implement IDisposable

	* mono/Bus.cs (Bus): Don't allow public instantiation.  This is
	strictly a static class.

	* mono/Connection.cs: Move the DBusObjectPathVTable and associated
	delegates into this file.
	(Connection): Implement IDisposable.
	(Dispose): Disconnect the connection and set the raw connection
	pointer to IntPtr.Zero.
	(~Connection): Call Dispose().
	(RegisterObjectPath): Added.  Manages the registration of object
	paths so we can cleanly disconnect them at dispose/finalize time.
	(UnregisterObjectPath): Ditto.
	(set_RawConnection): Unregister all of the object paths when
	changing the underlying DBusConnection.  Add them back onto the
	new connection, if any.

	* mono/Handler.cs: Don't implement IDisposable; it doesn't use any
	more unmanaged resources anymore, so it's not necessary.  Move all
	the DBusObjectPathVTable stuff out of here.
	(Handler): Save references to our delegates so that they don't get
	finalized.  Call Connection.RegisterObjectPath() instead of
	dbus_connection_register_object_path() directly.
	(Message_Called): Dispose the message after we're finished with
	it.

	* mono/Message.cs (Message): Implement IDisposable.
	(Dispose): Dispose the Arguments, and set the RawMessage to
	IntPtr.Zero.
	(SendWithReplyAndBlock): We own the ref to the reply that comes
	back from dbus_connection_send_with_reply_and_block() so add a
	comment about that and unref it after we've constructed a managed
	MethodReturn class around it.  Fixes a big, big leak.

	* mono/ProxyBuilder.cs: Reflect into Message to get the Dispose
	method.
	(BuildSignalHandler): After we've sent the Signal message, dispose
	of it.
	(BuildMethod): Dispose of the method call and reply messages after
	we've sent the message and extracted the data we want from the
	reply.

	* mono/Service.cs (UnregisterObject): Don't call handler.Dispose()
	anymore.
	(Service_FilterCalled): Dispose of the message after we're
	finished with it.
2005-03-09 04:36:15 +00:00

172 lines
4.1 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
{
private string path = null;
private Introspector introspector = null;
private object handledObject = null;
private DBusObjectPathVTable vTable;
private Connection connection;
private Service service;
// We need to hold extra references to these callbacks so that they don't
// get garbage collected before they are called back into from unmanaged
// code.
private DBusObjectPathUnregisterFunction unregister_func;
private DBusObjectPathMessageFunction message_func;
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
this.unregister_func = new DBusObjectPathUnregisterFunction (Unregister_Called);
this.message_func = new DBusObjectPathMessageFunction (Message_Called);
vTable = new DBusObjectPathVTable (this.unregister_func, this.message_func);
Connection.RegisterObjectPath (Path, vTable);
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;
// 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);
Result res = Result.NotYetHandled;
switch (message.Type) {
case Message.MessageType.MethodCall:
res = HandleMethod ((MethodCall) message);
break;
case Message.MessageType.Signal:
// We're not interested in signals here because we're the ones
// that generate them!
break;
}
message.Dispose ();
return (int) res;
}
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);
Message.Push (methodCall);
// Now call the method. FIXME: Error handling
object [] args = methodCall.Arguments.GetParameters(method);
object retVal = method.Invoke(this.handledObject, args);
Message.Pop ();
// 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;
}
}
}
}