tags:

views:

126

answers:

4

I'm working on an application that loads untrusted assemblies via an interface. Each of those assemblies should be able to add one or more GameAction objects to a thread-safe queue used by the server.

The first iteration of design was to just pass the queue--something like this:

public interface IGameClient
{
  void HandleStateChange(IGameState gameState, 
                         ref Queue<IGameAction> actionQueue);
}

But, the problem with this is that it gives an untrusted assembly access to a shared queue, allowing it to manipulate other members of the queue and discover information about other queue actions.

The second pass was:

public interface IGameClient
{
  void HandleStateChange(IGameState gameState);
  GameActionDelegate event HasNewEvent; // passes IGameAction as a parameter
}

The problem with this is that it doesn't necessarily allow for the ordering or grouping of actions.

What I'm really hoping for is to be able to pass a reference to an object that encapsulates the thread-safe queue, but only exposes Enqueue(). But, I'm afraid that an untrusted assembly could manipulate a private Queue object using reflection.

So, what's the best way to handle this?

+2  A: 

Thoughts in no particular order:

1) Events do guarantee ordering (or at least, your implementation could guarantee whatever ordering you want, and the simplest implementations will preserve ordering).

2) I don't see why you'd want to pass the queue by reference in the first example of the interface. It may be worth checking that you understand parameter passing and "ref".

3) If you come up with an interface which only exposes Enqueue then the implementation presumably won't be a Queue<T>. It might contain a Queue<T>, but if you really don't trust assemblies not to mess around with your private members, you should load them in such a way that you don't grant them the relevant reflection permissions.

Another alternative might be to pass in an Action<IGameAction> which the client can call when it wants to add an item to the queue. The delegate would be created from whatever Enqueue method you've got.

Jon Skeet
The "ref" isn't because it's necessary. It's meant to be a cue to the third-party developer that "this is meant to be manipulated" (and it was a first sketch.)
Jekke
Please don't use ref like that - it's not what it's there for, and would have allowed the method to replace your queue with their own one!
Jon Skeet
+2  A: 

Don't expose the queue at all--simply expose a method on a facade that allows the GameClient to submit an entry that the GameServer will place on the internal queue.

Rob Williams
A: 

You could make the HandleStateChange method return an IEnumerable<IGameAction>, IList<IGameAction> or IGameAction[]:

public interface IGameClient
{
  IGameAction[] HandleStateChange(IGameState gameState);
}

Then use that return value to add actions to the queue.

Vojislav Stojkovic
A: 

Pass a newly-created instance of queue, and when the HandleStateChange returns, merge the stuff from your dummy queue into the real queue.

Arkadiy