singrdk/base/Libraries/Manifest/Binder.sg

297 lines
11 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: Binder.cs
//
// Note:
///////////////////////////////////////////////////////////////////////////////
using System;
using System.Text;
using System.GCs;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.SingSharp;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Directory;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.Xml;
using Microsoft.Singularity.V1.Types;
using EndpointImplementation = Microsoft.Singularity.Channels.Endpoint;
namespace Microsoft.Singularity.Applications
{
[CLSCompliant(false)]
public class Binder
{
// duplicate of Directory Service consts
public const string ManifestFile = "manifest";
public const string ExecutableExtension = ".x86";
public const string ManifestExtension = ".manifest";
public const string ExecutablesNamespace = "init";
private static StringBuilder sb;
private static bool isInitialized = false;
const string NameXmlTag = "name";
const string StartStatedIdXmlAttribute = "startStateId";
const string EndpointClassName = "Microsoft.Singularity.Channels.Endpoint";
public static void Initialize()
{
if (isInitialized) return;
sb = new StringBuilder(512); // cache away a string form manipulation
isInitialized = true;
}
public static Manifest LoadManifest(DirectoryServiceContract.Imp:Ready! ds, String application)
{
if (application == null) return null;
application = (!)application.ToLower();
string folderName = application;
string appName = application;
// Open the directory containing the manifest and the .x86
// remove the ".x86" extension if present
if (application.EndsWith(ExecutableExtension)) {
folderName =(!)(application.Substring(0, application.Length - ((!)ExecutableExtension).Length));
appName = folderName;
}
if (folderName.Length == 0) {
// invalid application name
return null;
}
if (sb == null) {
sb = new StringBuilder(512); // cache away a string form manipulation
isInitialized = true;
}
// if the first character of the folder name is not "/",
// then we will redirect to the init namespace.
if (folderName[0] != '/') {
appName = folderName;
sb.Length = 0; //reset the buffer
sb.Append("/");
sb.Append(ExecutablesNamespace);
sb.Append("/");
sb.Append(appName);
folderName = (!)sb.ToString();
}
else {
// need to strip off all but last part.
appName = folderName.Substring(folderName.LastIndexOf('/')+1);
}
#if DEBUG2
DebugStub.WriteLine("Binder.LoadManifest: application={0},folder={1},appName={2}",
__arglist (application,folderName,appName));
#endif
DirectoryServiceContract.Imp:Ready dirEP = openDir(ds, folderName);
if (dirEP == null) {
#if DEBUG
DebugStub.WriteLine("Binder.LoadManifest: unable to open ,folder={0}",
__arglist (folderName));
#endif
return null;
}
Manifest man = GetManifest(ManifestFile, dirEP);
delete dirEP;
return man;
}
public static byte [] FindAndReadManifest(string! file,
DirectoryServiceContract.Imp:Ready! dirClient)
{
long size = 0;
NodeType nodeType;
ErrorCode errorOut;
long readSize = 4096;
bool ok = SdsUtils.GetAttributes(file,
dirClient,
out size,
out nodeType,
out errorOut );
if (!ok) return null;
// bind to file
FileContract.Imp! fileClient;
FileContract.Exp! fileServer;
FileContract.NewChannel(out fileClient, out fileServer);
ok = SdsUtils.Bind(file,dirClient,fileServer, out errorOut);
if (!ok) {
delete fileClient;
return null;
}
fileClient.RecvSuccess();
// Now read file
if (fileClient != null) {
// allocate memory and read file
byte [] region = new byte[size];
if (region == null) {
delete fileClient;
return null;
}
byte[] in ExHeap buf = new[ExHeap] byte[readSize];
long readOffset = 0;
while (true) {
// invariant: we own the non-null buffer buf at the
// loop head
// and we don't own the buffer at the loop exit.
//
Tracing.Log(Tracing.Debug,"FindImage pre SendRead");
fileClient.SendRead(buf, 0, readOffset, readSize);
switch receive {
case fileClient.AckRead(localbuf, bytesRead, error) :
Tracing.Log(Tracing.Debug,"FindImage Post SendRead");
Bitter.ToByteArray(localbuf, 0, (int)bytesRead,
region, (int)readOffset);
if (bytesRead == readSize) {
// see if there is more
readOffset += bytesRead;
buf = localbuf;
continue;
}
delete localbuf;
break;
case fileClient.ChannelClosed() :
break;
case unsatisfiable :
break;
}
// Get out of loop
break;
}
delete fileClient;
return region;
}
return null;
}
private static DirectoryServiceContract.Imp:Ready openDir(DirectoryServiceContract.Imp:Ready! ds, string! filePath)
{
assert ds != null;
DirectoryServiceContract.Imp! dirClient;
DirectoryServiceContract.Exp! dirServer;
DirectoryServiceContract.NewChannel(
out dirClient, out dirServer);
ErrorCode errorCode;
bool ok = SdsUtils.Bind(filePath, ds, dirServer, out errorCode);
if (!ok) {
delete dirClient;
return null;
}
dirClient.RecvSuccess();
return dirClient;
}
private static Manifest GetManifest(string! name,
DirectoryServiceContract.Imp:Ready! dirEP)
{
Manifest manifest = null;
Tracing.Log(Tracing.Debug, "Binder.GetManifest: path={0}", name);
try {
byte [] manifestMemory = FindAndReadManifest(name,dirEP);
if (manifestMemory != null) {
manifest = new Manifest(manifestMemory);
}
else {
DebugStub.WriteLine(" no manifest! file={0}",__arglist(name));
}
}
catch (Exception e) {
DebugStub.WriteLine("Exception in GetManifest: {0}", __arglist(e.Message));
Tracing.Log(Tracing.Debug, "Exception in GetManifest: {0}", e.Message);
}
return manifest;
}
// utility function for getting SystemTypes from strings in the manifest
private static SystemType GetEndpointType(XmlNode! metadata)
{
// everything must derive from Endpoint
SystemType epSystemType = typeof(Channels.Endpoint).GetSystemType();
// now traverse the metadata to the types, in order:
foreach (XmlNode! child in metadata.Children) {
string! name = (!)child.GetAttribute(NameXmlTag, "");
long lower, upper;
// [TODO] the encoding of types will change, and when
// it does, this will need to change. Right now, we create the
// type name of foo.imp as foo+foo.imp (same for exp)
if (name.EndsWith(".Exp") || name.EndsWith(".Imp")) {
name = name.Remove(name.Length - 4, 4) + "+" + name;
}
// get the hash for this type:
System.RuntimeTypeHash.ComputeHash(name, out lower, out upper);
// If this isn't the base of our derivation, get the type
if (name != EndpointClassName) {
epSystemType = EndpointImplementation.RegisterSystemType(name,lower, upper, epSystemType);
}
}
return epSystemType;
}
/// <summary>
/// Given information in the application manifest attempt to create and bind a channel to
/// a service conforming to the contract specified. This routine parses the manifest
/// metadata then makes an ABI call to generate the endpoints, connect them, add the
/// imp endpoint to the process StartupEndpoint array at "index", and attempt to bind
/// the exp endpoint to a service provider using system policy.
/// </summary>
public static bool BindServiceUser(Process! process,
int index,
string! contract,
XmlNode! metadata)
{
// get the metadata for both sides of the channel
XmlNode! impNode = (!)metadata.GetChild("imp");
XmlNode! expNode = (!)metadata.GetChild("exp");
// get the initial state as an integer
int initialState = metadata.GetAttribute(StartStatedIdXmlAttribute, 0);
// now get the SystemType of each endpoint's type (we don't actually
// know the type in the kernel, but we can discern it using the
// fullname from the metadata)
SystemType impType = GetEndpointType(impNode);
SystemType expType = GetEndpointType(expNode);
bool ok = process.BindToService(impType, expType, contract, initialState, index);
return ok;
}
}
}