dbus/mono/Message.cs

438 lines
11 KiB
C#
Raw Normal View History

2004-03-23 12:10:32 +00:00
namespace DBus
{
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
2004-03-23 12:10:32 +00:00
using System.Collections;
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
public class Message : IDisposable
2004-03-23 12:10:32 +00:00
{
private static Stack stack = new Stack ();
static public Message Current {
get
{
return stack.Count > 0 ? (Message) stack.Peek () : null;
}
}
static internal void Push (Message message)
{
stack.Push (message);
}
static internal void Pop ()
{
stack.Pop ();
}
2004-03-23 12:10:32 +00:00
/// <summary>
/// A pointer to the underlying Message structure
/// </summary>
private IntPtr rawMessage;
/// <summary>
/// The current slot number
/// </summary>
private static int slot = -1;
// Keep in sync with C
public enum MessageType
{
Invalid = 0,
MethodCall = 1,
MethodReturn = 2,
Error = 3,
Signal = 4
}
2004-03-23 12:10:32 +00:00
private Arguments arguments = null;
protected Service service = null;
protected string pathName = null;
protected string interfaceName = null;
protected string name = null;
private string key= null;
2004-03-23 12:10:32 +00:00
protected Message()
{
// An empty constructor for the sake of sub-classes which know how to construct theirselves.
}
protected Message(IntPtr rawMessage, Service service)
{
RawMessage = rawMessage;
this.service = service;
}
protected Message(MessageType messageType)
{
// the assignment bumps the refcount
2004-03-23 12:10:32 +00:00
RawMessage = dbus_message_new((int) messageType);
if (RawMessage == IntPtr.Zero) {
throw new OutOfMemoryException();
}
dbus_message_unref(RawMessage);
}
2004-03-23 12:10:32 +00:00
protected Message(MessageType messageType, Service service) : this(messageType)
{
this.service = service;
}
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
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
2004-03-23 12:10:32 +00:00
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
public void Dispose (bool disposing)
2004-03-23 12:10:32 +00:00
{
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
if (disposing) {
if (this.arguments != null)
this.arguments.Dispose ();
}
2004-03-23 12:10:32 +00:00
RawMessage = IntPtr.Zero; // free the native object
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
}
~Message()
{
Dispose (false);
2004-03-23 12:10:32 +00:00
}
public static Message Wrap(IntPtr rawMessage, Service service)
{
if (slot > -1) {
// If we already have a Message object associated with this rawMessage then return it
IntPtr rawThis = dbus_message_get_data(rawMessage, slot);
if (rawThis != IntPtr.Zero)
return (DBus.Message) ((GCHandle)rawThis).Target;
}
// If it doesn't exist then create a new Message around it
Message message = null;
2004-03-26 15:25:59 +00:00
MessageType messageType = (MessageType) dbus_message_get_type(rawMessage);
2004-03-23 12:10:32 +00:00
2004-03-26 15:25:59 +00:00
switch (messageType) {
2004-03-23 12:10:32 +00:00
case MessageType.Signal:
message = new Signal(rawMessage, service);
break;
case MessageType.MethodCall:
message = new MethodCall(rawMessage, service);
break;
2004-03-26 15:25:59 +00:00
case MessageType.MethodReturn:
message = new MethodReturn(rawMessage, service);
break;
case MessageType.Error:
message = new ErrorMessage(rawMessage, service);
break;
default:
throw new ApplicationException("Unknown message type to wrap: " + messageType);
}
2004-03-23 12:10:32 +00:00
return message;
}
internal IntPtr RawMessage
{
get
{
return rawMessage;
}
set
{
if (value == rawMessage)
return;
if (rawMessage != IntPtr.Zero)
{
// Get the reference to this
IntPtr rawThis = dbus_message_get_data(rawMessage, Slot);
Debug.Assert (rawThis != IntPtr.Zero);
// Blank over the reference
dbus_message_set_data(rawMessage, Slot, IntPtr.Zero, IntPtr.Zero);
// Free the reference
((GCHandle) rawThis).Free();
// Unref the connection
dbus_message_unref(rawMessage);
}
this.rawMessage = value;
if (rawMessage != IntPtr.Zero)
{
GCHandle rawThis;
dbus_message_ref(rawMessage);
// We store a weak reference to the C# object on the C object
rawThis = GCHandle.Alloc(this, GCHandleType.WeakTrackResurrection);
dbus_message_set_data(rawMessage, Slot, (IntPtr) rawThis, IntPtr.Zero);
}
}
}
public void Send(ref int serial)
{
if (!dbus_connection_send (Service.Connection.RawConnection, RawMessage, ref serial))
throw new OutOfMemoryException ();
2004-03-26 15:25:59 +00:00
Service.Connection.Flush();
2004-03-23 12:10:32 +00:00
}
public void Send()
{
int ignored = 0;
Send(ref ignored);
}
2004-03-23 12:10:32 +00:00
public void SendWithReply()
{
IntPtr rawPendingCall = IntPtr.Zero;
2004-03-23 12:10:32 +00:00
if (!dbus_connection_send_with_reply (Service.Connection.RawConnection, RawMessage, rawPendingCall, Service.Connection.Timeout))
throw new OutOfMemoryException();
}
2004-03-23 12:10:32 +00:00
public MethodReturn SendWithReplyAndBlock()
{
Error error = new Error();
error.Init();
2004-03-23 12:10:32 +00:00
IntPtr rawMessage = dbus_connection_send_with_reply_and_block(Service.Connection.RawConnection,
RawMessage,
Service.Connection.Timeout,
ref error);
if (rawMessage != IntPtr.Zero) {
MethodReturn methodReturn = new MethodReturn(rawMessage, Service);
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
// Ownership of a ref is passed onto us from
// dbus_connection_send_with_reply_and_block(). It gets reffed as
// a result of being passed into the MethodReturn ctor, so unref
// the extra one here.
dbus_message_unref (rawMessage);
2004-03-23 12:10:32 +00:00
return methodReturn;
} else {
throw new DBusException(error);
}
}
2004-03-23 12:10:32 +00:00
public MessageType Type
{
get
{
return (MessageType) dbus_message_get_type(RawMessage);
}
}
2004-03-23 12:10:32 +00:00
public Service Service
{
set
{
if (this.service != null && (value.Name != this.service.Name)) {
if (!dbus_message_set_destination(RawMessage, value.Name)) {
throw new OutOfMemoryException();
}
}
this.service = value;
}
get
{
return this.service;
}
}
2004-03-23 12:10:32 +00:00
protected virtual string PathName
{
set
{
if (value != this.pathName)
{
if (!dbus_message_set_path(RawMessage, value)) {
throw new OutOfMemoryException();
}
this.pathName = value;
}
}
get
{
if (this.pathName == null) {
this.pathName = Marshal.PtrToStringAnsi(dbus_message_get_path(RawMessage));
}
return this.pathName;
}
}
protected virtual string InterfaceName
{
set
{
if (value != this.interfaceName)
{
dbus_message_set_interface (RawMessage, value);
this.interfaceName = value;
}
}
get
{
if (this.interfaceName == null) {
this.interfaceName = Marshal.PtrToStringAnsi(dbus_message_get_interface(RawMessage));
}
2004-03-23 12:10:32 +00:00
return this.interfaceName;
}
}
2004-03-23 12:10:32 +00:00
protected virtual string Name
{
2004-03-26 15:25:59 +00:00
set {
if (value != this.name) {
dbus_message_set_member(RawMessage, value);
this.name = value;
2004-03-23 12:10:32 +00:00
}
2004-03-26 15:25:59 +00:00
}
get {
if (this.name == null) {
this.name = Marshal.PtrToStringAnsi(dbus_message_get_member(RawMessage));
2004-03-23 12:10:32 +00:00
}
2004-03-26 15:25:59 +00:00
return this.name;
}
2004-03-23 12:10:32 +00:00
}
public string Key
{
get {
if (this.key == null) {
this.key = Name + " " + Arguments;
}
return this.key;
}
}
2004-03-23 12:10:32 +00:00
public Arguments Arguments
{
get
{
if (this.arguments == null) {
this.arguments = new Arguments(this);
}
return this.arguments;
}
}
public string Sender
{
get
{
return Marshal.PtrToStringAnsi(dbus_message_get_sender(RawMessage));
}
}
public string Destination
{
get
{
return Marshal.PtrToStringAnsi(dbus_message_get_destination(RawMessage));
}
}
2004-03-23 12:10:32 +00:00
protected int Slot
{
get
{
if (slot == -1)
{
// We need to initialize the slot
if (!dbus_message_allocate_data_slot (ref slot))
throw new OutOfMemoryException ();
Debug.Assert (slot >= 0);
}
return slot;
}
}
[DllImport ("dbus-1", EntryPoint="dbus_message_new")]
protected extern static IntPtr dbus_message_new (int messageType);
[DllImport ("dbus-1", EntryPoint="dbus_message_unref")]
protected extern static void dbus_message_unref (IntPtr ptr);
[DllImport ("dbus-1", EntryPoint="dbus_message_ref")]
protected extern static void dbus_message_ref (IntPtr ptr);
[DllImport ("dbus-1", EntryPoint="dbus_message_allocate_data_slot")]
protected extern static bool dbus_message_allocate_data_slot (ref int slot);
[DllImport ("dbus-1", EntryPoint="dbus_message_free_data_slot")]
protected extern static void dbus_message_free_data_slot (ref int slot);
2004-03-23 12:10:32 +00:00
[DllImport ("dbus-1", EntryPoint="dbus_message_set_data")]
protected extern static bool dbus_message_set_data (IntPtr ptr,
int slot,
IntPtr data,
IntPtr free_data_func);
[DllImport ("dbus-1", EntryPoint="dbus_message_get_data")]
protected extern static IntPtr dbus_message_get_data (IntPtr ptr,
int slot);
[DllImport ("dbus-1", EntryPoint="dbus_connection_send")]
private extern static bool dbus_connection_send (IntPtr ptr,
IntPtr message,
ref int client_serial);
[DllImport ("dbus-1", EntryPoint="dbus_connection_send_with_reply")]
private extern static bool dbus_connection_send_with_reply (IntPtr rawConnection, IntPtr rawMessage, IntPtr rawPendingCall, int timeout);
2004-03-23 12:10:32 +00:00
[DllImport ("dbus-1", EntryPoint="dbus_connection_send_with_reply_and_block")]
private extern static IntPtr dbus_connection_send_with_reply_and_block (IntPtr rawConnection, IntPtr message, int timeout, ref Error error);
2004-03-23 12:10:32 +00:00
[DllImport("dbus-1")]
private extern static int dbus_message_get_type(IntPtr rawMessage);
2004-03-23 12:10:32 +00:00
[DllImport("dbus-1")]
private extern static bool dbus_message_set_path(IntPtr rawMessage, string pathName);
2004-03-23 12:10:32 +00:00
[DllImport("dbus-1")]
private extern static IntPtr dbus_message_get_path(IntPtr rawMessage);
[DllImport("dbus-1")]
private extern static bool dbus_message_set_interface (IntPtr rawMessage, string interfaceName);
[DllImport("dbus-1")]
private extern static IntPtr dbus_message_get_interface(IntPtr rawMessage);
[DllImport("dbus-1")]
2004-03-26 15:25:59 +00:00
private extern static bool dbus_message_set_member(IntPtr rawMessage, string name);
2004-03-23 12:10:32 +00:00
[DllImport("dbus-1")]
private extern static IntPtr dbus_message_get_member(IntPtr rawMessage);
2004-03-23 12:10:32 +00:00
[DllImport("dbus-1")]
private extern static bool dbus_message_set_destination(IntPtr rawMessage, string serviceName);
2004-03-23 12:10:32 +00:00
[DllImport("dbus-1")]
private extern static IntPtr dbus_message_get_destination(IntPtr rawMessage);
[DllImport("dbus-1")]
private extern static IntPtr dbus_message_get_sender(IntPtr rawMessage);
}
}