Skip to content
This repository has been archived by the owner on Nov 8, 2022. It is now read-only.

Commit

Permalink
Add support for Unix FD passing
Browse files Browse the repository at this point in the history
During compilation, this requires Mono.Posix from mono with commit
2225b6a260e1f0d469e37ec0df68a89e832688cd (i.e. mono 4.6 or later).
During runtime it will fall back to an implementation which does not support
Unix FD passing when the Mono.Posix version is too old.

An example showing how to pass file descriptors can be found in
examples/UnixFD*.cs
  • Loading branch information
steffen-kiess committed Jun 5, 2017
1 parent 2686c4f commit 9ff5f77
Show file tree
Hide file tree
Showing 29 changed files with 1,266 additions and 223 deletions.
142 changes: 142 additions & 0 deletions examples/UnixFDClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright 2017 Steffen Kiess <[email protected]>
// This software is made available under the MIT License
// See COPYING for details

using System;

using DBus;
using org.freedesktop.DBus;

using Mono.Unix;
using Mono.Unix.Native;

class SignalsImpl : Signals {
public event Action<UnixFD> GotFD;

public void CallGotFD (UnixFD fd) {
var handler = GotFD;
if (handler != null)
handler (fd);
}
}

public class ManagedDBusTest
{
public static void Main (string[] args)
{
Bus conn;

if (args.Length == 0)
conn = Bus.Session;
else {
if (args[0] == "--session")
conn = Bus.Session;
else if (args[0] == "--system")
conn = Bus.System;
else
conn = Bus.Open (args[0]);
}

IBus bus = conn.GetObject<IBus> ("org.freedesktop.DBus", new ObjectPath ("/org/freedesktop/DBus"));
Console.WriteLine (bus.ListNames ().Length);

var obj = conn.GetObject<Interface> (Constants.BusName, Constants.ObjectPath);
var obj2 = conn.GetObject<Interface2> (Constants.BusName, Constants.ObjectPath);
var objIntr = conn.GetObject<Introspectable> (Constants.BusName, Constants.ObjectPath);
obj.Ping ();
Console.WriteLine (obj.GetBytes (3).Length);

Console.WriteLine ("conn.UnixFDSupported = " + conn.UnixFDSupported);
if (!conn.UnixFDSupported)
return;

using (var disposableList = new DisposableList ()) {
var res = obj.GetFD (disposableList, false);
Console.WriteLine ("Got FD:");
Mono.Unix.Native.Stdlib.system ("ls -l /proc/$PPID/fd/" + res.Handle);
}
using (var disposableList = new DisposableList ()) {
var res = obj.GetFDList (disposableList, false);
Console.WriteLine ("Got FDs:");
foreach (var fd in res)
Mono.Unix.Native.Stdlib.system ("ls -l /proc/$PPID/fd/" + fd.Handle);
}
using (var disposableList = new DisposableList ()) {
var res = (UnixFD[]) obj.GetFDListVariant (disposableList, false);
Console.WriteLine ("Got FDs as variant:");
foreach (var fd in res)
Mono.Unix.Native.Stdlib.system ("ls -l /proc/$PPID/fd/" + fd.Handle);
}

using (var disposableList = new DisposableList ()) {
try {
obj.GetFD (disposableList, true);
throw new Exception ("Expected an exception");
} catch (Exception e) {
if (!e.Message.Contains ("Throwing an exception after creating a UnixFD object"))
throw;
}
}
using (var disposableList = new DisposableList ()) {
try {
obj.GetFDList (disposableList, true);
throw new Exception ("Expected an exception");
} catch (Exception e) {
if (!e.Message.Contains ("Throwing an exception after creating a UnixFD object"))
throw;
}
}
using (var disposableList = new DisposableList ()) {
try {
obj.GetFDListVariant (disposableList, true);
throw new Exception ("Expected an exception");
} catch (Exception e) {
if (!e.Message.Contains ("Throwing an exception after creating a UnixFD object"))
throw;
}
}

// Check whether this leaks an FD
obj.GetFD (null, false);
obj.GetFDList (null, false);
obj.GetFDListVariant (null, false);
try { obj.GetFD (null, true); } catch {}
try { obj.GetFDList (null, true); } catch {}
try { obj.GetFDListVariant (null, true); } catch {}
obj2.GetFD (false);
obj2.GetFDList (false);
obj2.GetFDListVariant (false);
try { obj2.GetFD (true); } catch {}
try { obj2.GetFDList (true); } catch {}
try { obj2.GetFDListVariant (true); } catch {}

var fd_ = Syscall.open ("/dev/null", OpenFlags.O_RDWR, 0);
if (fd_ < 0)
UnixMarshal.ThrowExceptionForLastError ();
using (var fd = new UnixFD (fd_)) {
obj.SendFD (fd);
obj.SendFD (fd);
obj.SendFDList (new UnixFD[] { fd, fd });
obj.SendFDListVariant (new UnixFD[] { fd, fd });

var impl = new SignalsImpl ();
var spath = new ObjectPath ("/mono_dbus_sharp_test/Signals");
conn.Register (spath, impl);
obj.RegisterSignalInterface (conn.UniqueName, spath);
impl.CallGotFD (fd);
}

Console.WriteLine (objIntr.Introspect ().Length);

obj.ListOpenFDs ();
Console.WriteLine ("Open FDs:");
Mono.Unix.Native.Stdlib.system ("ls -l /proc/$PPID/fd/");
}
}

// vim: noexpandtab
// Local Variables:
// tab-width: 4
// c-basic-offset: 4
// indent-tabs-mode: t
// End:
61 changes: 61 additions & 0 deletions examples/UnixFDInterface.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2017 Steffen Kiess <[email protected]>
// This software is made available under the MIT License
// See COPYING for details

using System;
using DBus;

public static class Constants {
public const string BusName = "mono_dbus_sharp_test.UnixFDService";
public static readonly ObjectPath ObjectPath = new ObjectPath ("/mono_dbus_sharp_test/UnixFDService");
}

[DBus.Interface ("mono_dbus_sharp_test.UnixFDService")]
public interface Interface {
void Ping ();

void ListOpenFDs ();

byte[] GetBytes (int len);

UnixFD GetFD (DisposableList disposableList, bool throwError);
UnixFD[] GetFDList (DisposableList disposableList, bool throwError);
object GetFDListVariant (DisposableList disposableList, bool throwError);

void SendFD (UnixFD fd);
void SendFDList (UnixFD[] fds);
void SendFDListVariant (object fds);

void RegisterSignalInterface (string busName, ObjectPath path);
}

[DBus.Interface ("mono_dbus_sharp_test.UnixFDService")]
public interface Interface2 {
void Ping ();

void ListOpenFDs ();

byte[] GetBytes (int len);

UnixFD GetFD (bool throwError);
UnixFD[] GetFDList (bool throwError);
object GetFDListVariant (bool throwError);

void SendFD (UnixFD fd);
void SendFDList (UnixFD[] fds);
void SendFDListVariant (object fds);

void RegisterSignalInterface (string busName, ObjectPath path);
}

[DBus.Interface ("mono_dbus_sharp_test.UnixFDSignals")]
public interface Signals {
event Action<UnixFD> GotFD;
}

// vim: noexpandtab
// Local Variables:
// tab-width: 4
// c-basic-offset: 4
// indent-tabs-mode: t
// End:
137 changes: 137 additions & 0 deletions examples/UnixFDService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright 2017 Steffen Kiess <[email protected]>
// This software is made available under the MIT License
// See COPYING for details

/*
PATH="$HOME/mono-master/bin:$PATH" ./autogen.sh && make -j8
make && ( cd examples && mcs -g UnixFDService.cs UnixFDInterface.cs -r ../src/dbus-sharp.dll -r Mono.Posix ) && MONO_PATH=src $HOME/mono-master/bin/mono --debug examples/UnixFDService.exe
make && ( cd examples && mcs -g UnixFDClient.cs UnixFDInterface.cs -r ../src/dbus-sharp.dll -r Mono.Posix ) && MONO_PATH=src $HOME/mono-master/bin/mono --debug examples/UnixFDClient.exe
python3
import dbus; dbus.SessionBus().get_object('mono_dbus_sharp_test.UnixFDService', '/mono_dbus_sharp_test/UnixFDService').GetBytes(3)
import dbus; f = dbus.SessionBus().get_object('mono_dbus_sharp_test.UnixFDService', '/mono_dbus_sharp_test/UnixFDService').GetFD ()
*/

using System;

using Mono.Unix;
using Mono.Unix.Native;

using DBus;
using org.freedesktop.DBus;

public class Impl : Interface {
Connection conn;

public Impl (Connection conn)
{
this.conn = conn;
}

public void Ping ()
{
}

public void ListOpenFDs ()
{
Console.WriteLine ("Open FDs:");
Mono.Unix.Native.Stdlib.system ("ls -l /proc/$PPID/fd/");
}

public UnixFD GetFD (DisposableList disposableList, bool throwError)
{
var fd_ = Syscall.open ("/dev/null", OpenFlags.O_RDWR, 0);
if (fd_ < 0)
UnixMarshal.ThrowExceptionForLastError ();
var fd = new UnixFD (fd_);
disposableList.Add (fd);

if (throwError)
throw new Exception ("Throwing an exception after creating a UnixFD object");

return fd;
}

public UnixFD[] GetFDList (DisposableList disposableList, bool throwError)
{
return new UnixFD[] {
GetFD (disposableList, false), GetFD (disposableList, throwError), GetFD (disposableList, false)
};
}

public object GetFDListVariant (DisposableList disposableList, bool throwError)
{
return GetFDList (disposableList, throwError);
}

public byte[] GetBytes (int len)
{
return new byte[len];
}

public void SendFD (UnixFD fd)
{
Console.WriteLine ("Got FD as parameter:");
Mono.Unix.Native.Stdlib.system ("ls -l /proc/$PPID/fd/" + fd.Handle);
}

public void SendFDList (UnixFD[] fds)
{
Console.WriteLine ("Got FDs as parameter:");
foreach (var fd in fds)
Mono.Unix.Native.Stdlib.system ("ls -l /proc/$PPID/fd/" + fd.Handle);
}

public void SendFDListVariant (object fds)
{
Console.WriteLine ("Got FDs as variant parameter:");
foreach (var fd in (UnixFD[]) fds)
Mono.Unix.Native.Stdlib.system ("ls -l /proc/$PPID/fd/" + fd.Handle);
}

public void RegisterSignalInterface (string busName, ObjectPath path)
{
Console.WriteLine ("Register for GotFD event at {0} / {1}", busName, path);
conn.GetObject<Signals> (busName, path).GotFD += fd => {
Console.WriteLine ("Got FD from signal:");
Mono.Unix.Native.Stdlib.system ("ls -l /proc/$PPID/fd/" + fd.Handle);
};
}
}

public class UnixFDService
{
public static void Main (string[] args)
{
Bus conn;

if (args.Length == 0)
conn = Bus.Session;
else {
if (args[0] == "--session")
conn = Bus.Session;
else if (args[0] == "--system")
conn = Bus.System;
else
conn = Bus.Open (args[0]);
}

conn.Register (Constants.ObjectPath, new Impl (conn));

if (conn.RequestName (Constants.BusName) != org.freedesktop.DBus.RequestNameReply.PrimaryOwner)
throw new Exception ("Could not request name");

Console.WriteLine ("Waiting for requests...");

while (conn.IsConnected) {
conn.Iterate ();
}
}
}

// vim: noexpandtab
// Local Variables:
// tab-width: 4
// c-basic-offset: 4
// indent-tabs-mode: t
// End:
10 changes: 10 additions & 0 deletions src/Authentication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ public virtual bool Run (IEnumerable<AuthCommand> commands)
class SaslClient : SaslPeer
{
public string Identity = String.Empty;
public bool TransportSupportsUnixFD = false;
public bool UnixFDSupported = false;

//static Regex rejectedRegex = new Regex (@"^REJECTED(\s+(\w+))*$");

Expand Down Expand Up @@ -387,6 +389,14 @@ public override IEnumerator<AuthCommand> GetEnumerator ()
else
ActualId = UUID.Parse (reply[1]);

if (TransportSupportsUnixFD) {
yield return new AuthCommand ("NEGOTIATE_UNIX_FD");
if (!replies.MoveNext ())
yield break;
reply = replies.Current;
UnixFDSupported = reply[0] == "AGREE_UNIX_FD";
}

yield return new AuthCommand ("BEGIN");
yield break;
}
Expand Down
Loading

0 comments on commit 9ff5f77

Please sign in to comment.