singrdk/base/Kernel/Singularity.Directory/ProviderNode.sg

550 lines
22 KiB
Plaintext
Raw Normal View History

2008-03-05 09:52:00 -05:00
////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Directory.sg
//
// Note:
//
using System;
using System.Text;
using System.Collections;
using System.Threading;
using Microsoft.SingSharp;
using Microsoft.Singularity;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Directory;
using Microsoft.Singularity.Security;
using Microsoft.Singularity.Security.SDS;
#if !SINGULARITY_PROCESS
namespace Microsoft.Singularity.Directory
#else
namespace Microsoft.Application.DSP
#endif
{
// Although there currently are none, there might need to be access control
// checks at Bind time. Certainly, the Bind target can do an access check,
// but the Bind intermediary, here, might also make a check. See the discussion
// below.
public class ProviderNode : Node
{
public TRef<ServiceProviderContract.Imp:Start>! ServiceEndpoint;
private bool isDead;
public ProviderNode([Claims] ServiceProviderContract.Imp! imp, string! name, Node! parent)
requires imp.InState(ServiceProviderContract.Start.Value);
{
ServiceEndpoint = new TRef<ServiceProviderContract.Imp:Start>(imp);
isDead = false;
base(NodeType.ServiceProvider, name, parent);
}
public ServiceProviderContract.Imp:Start! GetServiceEndpoint() {
return this.ServiceEndpoint.Acquire();
}
/// <returns>
/// null on success, the service argument if it failed.
/// </returns>
public override ServiceContract.Exp Bind(StringBuilder! p,
string! fullPath,
Principal pr,
int curpos,
out int position,
out bool success,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link,
out string linkPrefix,
[Claims]
ServiceContract.Exp! service)
{
Kernel.Waypoint(3100);
reparse = false;
link = null;
linkPrefix = null;
success = false;
linkFound = false;
position = curpos;
if (p.Length != 0) {
if ( (p.Length == 1) && (p[0] == '/') ) {
// pass thru if it is just the delimiter character.
}
else {
// we have hit a non-leaf service provider
// send back a reparse message
error = ErrorCode.NotFound;
reparse = true;
link = p.ToString();
return service;
}
}
// There continues to be an inconsistency here with access control.
// We might do the access control here on Bind, in which case we know
// the caller. However, if we require the access control operation
// to be done on the other side of the Connect operation, then that
// code doesn't see the original invoker and moreover there is no
// appropriate AccessDenied failure on Connect.
// It seems a little weird to put access controls on the provider
// node, since such node are transient, but that is perhaps what we
// should do.
// If we decide to do ACL checks here, figure out how to get the
// permissions from the service endpoint!! No access check here until we do.
/*
if (!CheckNodeAccess(???, pr, service)) {
DebugStub.WriteLine("No access to bind");
error = ErrorCode.AccessDenied;
return service;
}
*/
lock (this) {
Kernel.Waypoint(3101);
if (isDead) {
success = false;
error = ErrorCode.NotFound;
return service;
}
ServiceProviderContract.Imp ep = this.ServiceEndpoint.Acquire();
assert ep.InState(ServiceProviderContract.Start.Value);
Tracing.Log(Tracing.Debug, "Connecting to Service Provider");
try {
ep.SendConnect(service);
switch receive {
case ep.AckConnect():
success = true;
error = ErrorCode.NoError;
return null;
case ep.NackConnect(rejectedEP):
Tracing.Log(Tracing.Debug,"nak connect ");
// REVIEW what should be returned here?
error = ErrorCode.ContractNotSupported;
return rejectedEP;
case ep.ChannelClosed():
Tracing.Log(Tracing.Debug,"channel closed");
// make this a zombie node
isDead = true;
error = ErrorCode.ChannelClosed;
success = false;
return null;
case unsatisfiable:
Tracing.Log(Tracing.Debug,"Unsatisfiable!!");
error = ErrorCode.Unsatisfiable;
success = false;
return null;
}
}
finally {
this.ServiceEndpoint.Release(ep);
}
Kernel.Waypoint(3102);
} // lock on node
}
/// <returns>
/// Inform caller if peer endpoint is closed
/// remove endpoint if it is
/// </returns>
public bool DeleteIfPeerClosed ()
{
ServiceProviderContract.Imp! service;
service = this.ServiceEndpoint.Acquire();
if (service == null ) return false;
if (service.PeerClosed) {
delete service;
return true;
}
else {
this.ServiceEndpoint.Release(service);
return false;
}
}
/// <returns>
/// replace current dead sp with other
/// </returns>
public ServiceProviderContract.Imp ReplaceProvider([Claims] ServiceProviderContract.Imp! sp)
{
DebugStub.WriteLine("replacing provider");
ServiceProviderContract.Imp! service;
service = this.ServiceEndpoint.Acquire();
if (service.PeerClosed) {
DebugStub.WriteLine("peer is closed. proceeding");
delete service;
this.ServiceEndpoint.Release(sp);
return null;
}
this.ServiceEndpoint.Release(service);
return sp;
}
/// <returns>
/// null on success, the sp argument if it failed.
/// </returns>
public override ServiceProviderContract.Imp Register(StringBuilder! p,
Principal pr,
[Claims]ServiceProviderContract.Imp! sp,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
position = curpos;
if (p.Length != 0) {
if ( (p.Length == 1) && (p[0] == '/') ) {
// pass thru if it is just the delimiter character.
}
else {
// we have hit a non-leaf service provider
// send back a reparse message
error = ErrorCode.Unknown;
reparse = true;
linkFound = false;
link = p.ToString();
return sp;
}
}
// check to see if this ep is stale.
// cannot register over an existing provider
reparse = false;
linkFound = false;
link = null;
error = ErrorCode.AlreadyExists;
return sp;
}
/// <returns>
/// The endpoint on success, null, if it fails.
/// </returns>
public override ServiceProviderContract.Imp:Start Deregister(StringBuilder! p,
Principal pr,
DirectoryServiceContract.Exp! ep,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
link = null;
linkFound = false;
reparse = false;
position = curpos;
if (p.Length != 0) {
if ( (p.Length == 1) && (p[0] == '/') ) {
// pass thru if it is just the delimiter character.
}
else {
// we have hit a non-leaf service provider
// send back a reparse message
error = ErrorCode.Unknown;
reparse = true;
linkFound = false;
link = p.ToString();
return null;
}
}
// Add the following access check on Deregister pursuant on the
// discussion about access controls on providers above.
/*
if (!CheckNodeAccess(DirPermissions.AccessModeRegister, pr, ep)){
error = ErrorCode.AccessDenied;
return null;
}
*/
// we are being removed
error = ErrorCode.NoError;
return this.ServiceEndpoint.Acquire();
}
/// <returns>
/// if true returns length and node type, otherwise error
/// </returns>
public override bool GetAttributes(StringBuilder! p,
Principal pr,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link,
out long length,
out NodeType nodeType
)
{
position =curpos;
if (p.Length != 0) {
if ( (p.Length == 1) && (p[0] == '/') ) {
// pass thru if it is just the delimiter character.
}
else {
// we have hit a non-leaf service provider
// send back a reparse message
error = ErrorCode.Unknown;
reparse = true;
linkFound = false;
length = 0;
link = p.ToString();
nodeType = NodeType.ServiceProvider;
return false;
}
}
linkFound = false;
reparse = false;
link = p.ToString();
nodeType = NodeType.ServiceProvider;
length = 0;
error = ErrorCode.Unknown;
return true;
}
/// <returns>
/// null on success, the imp argument if it failed.
/// </returns>
public override NotifyContract.Imp Notify(StringBuilder! p,
Principal pr,
string! pattern,
bool sendExisting,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link,
[Claims] NotifyContract.Imp! notifyImp)
{
linkFound = false;
error = ErrorCode.NotImplemented;
reparse = false;
link = null;
position = curpos;
if (p.Length != 0) {
if ( (p.Length == 1) && (p[0] == '/') ) {
// pass thru if it is just the delimiter character.
}
else {
// we have hit a non-leaf service provider
// send back a reparse message
error = ErrorCode.Unknown;
reparse = true;
linkFound = false;
link = p.ToString();
return notifyImp;
}
}
return notifyImp;
}
public override FileContract.Imp CreateAndBindFile(StringBuilder! p,
Principal pr,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
linkFound = false;
error = ErrorCode.NotImplemented;
reparse = false;
link = null;
position = curpos;
return null;
}
private bool CheckForTraverse (StringBuilder! p,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
linkFound = false;
error = ErrorCode.Unknown;
reparse = false;
link = null;
if (p.Length != 0) {
if ( (p.Length == 1) && (p[0] == '/') ){
// pass thru if it is just the delimiter character.
}
else {
// we have hit a non-leaf service provider
// send back a reparse message
error = ErrorCode.NoError;
reparse = true;
linkFound = false;
link = p.ToString();
if (p[0] == '/') link = link.Substring(1);
return false;
}
}
return false;
}
public override bool CreateDirectory(StringBuilder! p,
Principal pr,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
position = curpos;
return CheckForTraverse(p, out linkFound, out error, out reparse, out link);
}
public override bool CreateFile(StringBuilder! p,
Principal pr,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
position = curpos;
return CheckForTraverse(p, out linkFound, out error, out reparse, out link);
}
public override bool CreateLink(StringBuilder! p,
Principal pr,
string! value,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
position = curpos;
return CheckForTraverse(p, out linkFound, out error, out reparse, out link);
}
public override bool DeleteDirectory(StringBuilder! p,
Principal pr,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
position = curpos;
return CheckForTraverse(p, out linkFound, out error, out reparse, out link);
}
public override bool DeleteFile(StringBuilder! p,
Principal pr,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
position = curpos;
return CheckForTraverse(p, out linkFound, out error, out reparse, out link);
}
public override bool DeleteLink(StringBuilder! p,
Principal pr,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
position = curpos;
return CheckForTraverse(p, out linkFound, out error, out reparse, out link);
}
public override bool GetLinkValue(StringBuilder! p,
Principal pr,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
position = curpos;
return CheckForTraverse(p, out linkFound, out error, out reparse, out link);
}
public override bool QueryACL(StringBuilder! p,
bool effective,
Principal pr,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link,
out Acl acl
)
{
acl = new Acl();
position = curpos;
return CheckForTraverse(p, out linkFound, out error, out reparse, out link);
}
public override bool StoreACL(StringBuilder! p,
Principal pr,
Acl acl,
int curpos,
out int position,
out bool linkFound,
out ErrorCode error,
out bool reparse,
out string link
)
{
position = curpos;
return CheckForTraverse(p, out linkFound, out error, out reparse, out link);
}
}
}