// ---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // ---------------------------------------------------------------------------- // // author: Glenn Peterson // using System; using System.Runtime.CompilerServices; using System.Text; #if !SINGULARITY using System.Net; #endif using Microsoft.Contracts; using Microsoft.Singularity; using Microsoft.Singularity.Eventing; using Microsoft.Singularity.NetStack.Events; namespace NetStack.Runtime { /// /// A class-only attribute to denote an Event Logging Source. /// [AttributeUsage(AttributeTargets.Class)] public sealed class EventLogSourceAttribute : Attribute { private string id = String.Empty; private bool fieldRegistrationErrorFatal = true; /// /// Sole constructor requiring the source Identifier as the only parameter. /// /// /// A string identifier for the particular event logging source. /// public EventLogSourceAttribute(string id) { this.id = id; } /// /// A string identifier for the particular event logging source. /// public string Id { get { return this.id; } set { this.id = value; } } /// /// A Boolean that dictates the handling of a field registration errors. /// If true (the default), any field registration error causes /// the entire registration, and therefore the Create method, to fail. /// public bool FieldRegistationErrorFatal { get { return this.fieldRegistrationErrorFatal; } set { this.fieldRegistrationErrorFatal = value; } } } /// /// A method-only attribute denoting an Event Logging Method. /// [AttributeUsage(AttributeTargets.Method)] public sealed class EventLogMethodAttribute : System.Attribute { private string id; private bool heapAllowed = true; private bool debugPrint = false; private string formatString = String.Empty; /// /// Sole constructor requiring the method (event type) /// identifier as the only parameter. /// /// /// A string identifier for the particular event logging method /// which becomes the identifier for the event type. /// public EventLogMethodAttribute(string id) { this.id = id; } /// /// A string identifier for the particular event logging method /// which becomes the identifier for the event type. /// public string Id { get { return this.id; } set { this.id = value; } } /// /// If true, the generated code can perform heap allocations. NOT SURE IF NEEDED. // TODO /// public bool HeapAllowed { get { return this.heapAllowed; } set { this.heapAllowed = value; } } /// /// If true, the generated code will include a test /// for the DebugPrint bit for this event type. /// public bool DebugPrint { get { return this.debugPrint; } set { this.debugPrint = value; } } /// /// A 'String.Format' format control string used when: /// /// 1. The event is transferred to the debugger, and /// /// /// 2. The event is displayed with the script tool in a mixed stream. /// /// public string FormatString { get { return this.formatString; } set { this.formatString = value; } } } /// /// A parameter-only attribute describing the treatment /// of a single parameter to an event logging method. /// /// /// No Id is present as a Property as the parameter's /// name is the natural Id. /// [AttributeUsage(AttributeTargets.Parameter)] public sealed class EventLogMethodParameterAttribute : Attribute { private string title = String.Empty; private uint ordinalInStruct; private string typeInStruct = String.Empty; /// /// A string used in lieu of the parameter name in columnar reports. /// /// If not supplied, the parameter name is used. public string Title { get { return this.title; } set { this.title = value; } } /// /// Specifies the zero-based ordinal of this parameter in the structure /// used to add this event to the event stream. /// /// /// If not supplied, the parameter order in the method call is used. /// public uint OrdinalInStruct { get { return this.ordinalInStruct; } set { this.ordinalInStruct = value; } } /// /// Specifies the type of the data element to use in the structure used /// to add this event to the event stream. /// /// /// If not supplied, the type of the parameter in the method call is used. /// public string TypeInStruct // BUGBUG: Should not be a string, should be a value-type. // TODO { get { return this.typeInStruct; } set { this.typeInStruct = value; } } } /// /// Eventing and Tracing support for the TcpSession class. /// [CLSCompliant(false)] [EventLogSource("TcpSession")] public class TcpSessionEventsSource : EventSource // TODO: Base class constructor should take storageOptions and Size - then the static almost goes away. { public const uint LogStateChanges = 0x00010000; public const uint LogReceivedPackets = 0x00020000; public const uint LogSendingPackets = 0x00040000; public const uint LogTimeouts = 0x00080000; public const uint LogStateChangeContractCalls = 0x00100000; public const uint LogDataTransferContractCalls = 0x00200000; public const uint LogQueryContractCalls = 0x00400000; public const uint LogInfoContractCalls = 0x00800000; // Event Log size in bytes. // Overhead is 24 bytes and TcpSession uses <= 8. private const uint EventLogBufferSize = 32u * 2048u; // Global Instance public static readonly TcpSessionEventsSource EventLog; // Enums to represent TCP Contract Entrypoints public enum TcpSessionContractEntrypoints { Unknown = 0, Connect, Bind, Listen, Accept, DoneSending, DoneReceiving, Abort, Close, BindLocalEndPoint, Read, PollRead, Write, IsSessionAvailable, IsDataAvailable, GetLocalAddress, GetLocalPort, GetRemoteAddress, GetRemotePort, ChannelClosed, } // Strings matching enum immediately above. internal static readonly string[] ContractCallNames = new string[] { "Unknown", "Connect", "Bind", "Listen", "Accept", "DoneSending", "DoneReceiving", "Abort", "Close", "BindLocalEndPoint", "Read", "PollRead", "Write", "IsSessionAvailable", "IsDataAvailable", "GetLocalAddress", "GetLocalPort", "GetRemoteAddress", "GetRemotePort", "ChannelClosed", }; private UIntPtr stateChangeTypeHandle; private UIntPtr receivedPacketTypeHandle; private UIntPtr sendingPacketTypeHandle; private UIntPtr timeoutTypeHandle; private UIntPtr contractCallTypeHandle; private uint debugOptions; private struct StateChangeEntry { public ushort sessionId; public byte fromState; public byte toState; public StateChangeEntry(uint sessionId, TcpStateEnum fromState, TcpStateEnum toState) { this.sessionId = (ushort)sessionId; this.fromState = (byte)fromState; this.toState = (byte)toState; } } private struct ReceivedPacketEntry { public ushort sessionId; public byte sessionState; public byte packetFlags; public ushort packetLength; public ReceivedPacketEntry(uint sessionId, TcpStateEnum sessionState, uint packetFlags, uint packetLength) { this.sessionId = (ushort)sessionId; this.sessionState = (byte)sessionState; this.packetFlags = (byte)packetFlags; this.packetLength = (ushort)packetLength; } } private struct SendingPacketEntry { public ushort sessionId; public byte sessionState; public byte packetFlags; public ushort packetLength; public SendingPacketEntry(uint sessionId, TcpStateEnum sessionState, uint packetFlags, uint packetLength) { this.sessionId = (ushort)sessionId; this.sessionState = (byte)sessionState; this.packetFlags = (byte)packetFlags; this.packetLength = (ushort)packetLength; } } private struct TimeoutEntry { public ushort sessionId; public byte sessionState; public byte timeoutType; public TimeoutEntry(uint sessionId, TcpStateEnum sessionState, TcpSession.TcpTimeoutType timeoutType) { this.sessionId = (ushort)sessionId; this.sessionState = (byte)sessionState; this.timeoutType = (byte)timeoutType; } } private struct ContractCallEntry { public ushort sessionId; public byte sessionState; public byte callId; public ContractCallEntry(uint sessionId, TcpStateEnum sessionState, TcpSessionContractEntrypoints callId) { this.sessionId = (ushort)sessionId; this.sessionState = (byte)sessionState; this.callId = (byte)callId; } } /// /// The Static Constructor. It creates the event session for this SIP. /// static TcpSessionEventsSource() { TcpSessionEventsSource.EventLog = TcpSessionEventsSource.Create(// BUGBUG AM: Why isn't this a normal constructor???? "TcpSessions", TcpSessionEventsSource.EventLogBufferSize, QualityOfService.RecyclableEvents, EventSource.ENABLE_ALL_MASK & ~( // Buffering Mask // BUGBUG: Switch to Positive Logic when system and user masks separated? // TODO //Incl TcpSessionEventsSource.LogStateChanges | /*Omit*/TcpSessionEventsSource.LogSendingPackets | //Incl TcpSessionEventsSource.LogReceivedPackets | //Incl TcpSessionEventsSource.LogTimeouts | //Incl TcpSessionEventsSource.LogStateChangeContractCalls | /*Omit*/TcpSessionEventsSource.LogDataTransferContractCalls | /*Omit*/TcpSessionEventsSource.LogQueryContractCalls | /*Omit*/TcpSessionEventsSource.LogInfoContractCalls | 0u), EventSource.ENABLE_ALL_MASK & ~( // Debugging Mask // BUGBUG: Same // TODO /*Omit*/TcpSessionEventsSource.LogStateChanges | /*Omit*/TcpSessionEventsSource.LogSendingPackets | /*Omit*/TcpSessionEventsSource.LogReceivedPackets | /*Omit*/TcpSessionEventsSource.LogTimeouts | /*Omit*/TcpSessionEventsSource.LogStateChangeContractCalls | /*Omit*/TcpSessionEventsSource.LogDataTransferContractCalls | /*Omit*/TcpSessionEventsSource.LogQueryContractCalls | /*Omit*/TcpSessionEventsSource.LogInfoContractCalls | 0u)); #if false TcpSessionEvents.EventLog = TcpSessionEvents.Create("TcpSession", 4096, QualityOfService.RecyclableEvents, EventSource.ENABLE_ALL_MASK | EventSource.CAPTURE_DEBUG_PRINT); #endif } /// /// Create and Register a TcpSessionEventsSource. /// /// /// This should be a Generic when supported. Or use more of the base class (Static?) // BUGBUG AM (later?) /// public static TcpSessionEventsSource Create(string sourceName, uint size, uint storageOptions, // BUGBUG AM: [Flags] enum uint sourceFlags, uint debugFlags) { TcpSessionEventsSource tcpSessionEventsSource = null; EventingStorage eventStorage = EventingStorage.CreateLocalStorage(storageOptions, size); if (eventStorage == null) { DebugStub.WriteLine("Failure to obtain storage for TcpSessionEvents"); DebugStub.Break(); } else { tcpSessionEventsSource = new TcpSessionEventsSource(sourceName, eventStorage, sourceFlags, debugFlags); if (tcpSessionEventsSource == null) { // TODO: Is EventStorage returned here and below if failures occur? DebugStub.WriteLine("Failure to construct TcpSessionEventsSource instance."); DebugStub.Break(); } else { bool registerSucceeded = tcpSessionEventsSource.Register(); if (registerSucceeded == false) { tcpSessionEventsSource = null; DebugStub.WriteLine("Failure to register TcpSessionEventsSource."); DebugStub.Break(); } } } return tcpSessionEventsSource; } /// Fully parameterized and sole constructor. /// BUGBUG AM: parameterization: have base EP that takes storageoptions and size to elim dup code (generated or not) public TcpSessionEventsSource(string sourceName, EventingStorage storage, uint controlFlags, uint debugOptions) : base(sourceName, storage, controlFlags) { this.debugOptions = debugOptions; } ~TcpSessionEventsSource() { // BUGBUG AM: Free EventingStorage (using base somehow? please!) } //[NoHeapAllocation] [EventLogMethod("TcpSessionStateChange", HeapAllowed = true, DebugPrint = false, FormatString = "TCP: Ses{0,3} ({1}) State Change to {2}.")] public bool LogSessionStateChange( [EventLogMethodParameter(Title = "Session", OrdinalInStruct = 0, TypeInStruct = "ushort")] uint sessionId, [EventLogMethodParameter(Title = "FrState", OrdinalInStruct = 1, TypeInStruct = "byte")] TcpStateEnum fromState, [EventLogMethodParameter(Title = "ToState", OrdinalInStruct = 2, TypeInStruct = "byte")] TcpStateEnum toState) // BUGBUG AM: signature poor way to differentiate various entries. Is there a way to have two two "int" loggers with different types and member labels? { if ((debugOptions & LogStateChanges /* To Debugger */) != 0) { Core.Log("TCP: Ses{0,3} ({1}) State Change to {2}.", sessionId, TcpState.TcpStateNames[(uint)fromState], TcpState.TcpStateNames[(uint)toState]); } if ((ControlFlags & LogStateChanges) != 0) { StateChangeEntry stateChangeEntry = new StateChangeEntry(sessionId, fromState, toState); unsafe { // BUGBUG AM: Just a comment - this causes my otherwise safe compile to be changed to unsafe. This is bad. return (LogEntry(ControlFlags, stateChangeTypeHandle, (byte*)&stateChangeEntry, sizeof(StateChangeEntry)) != 0); } } return false; } //[NoHeapAllocation] [EventLogMethod("TcpPacketReceived", HeapAllowed = true, DebugPrint = false, FormatString = "TCP: Ses{0,3} ({1}) Packet ({2}) Len{3,4} received")] public bool LogReceivedPacket( [EventLogMethodParameter(Title = "Session Id", OrdinalInStruct = 0, TypeInStruct = "ushort")] uint sessionId, [EventLogMethodParameter(Title = "Session State", OrdinalInStruct = 1, TypeInStruct = "byte")] TcpStateEnum sessionState, [EventLogMethodParameter(Title = "Packet Flags", OrdinalInStruct = 2, TypeInStruct = "byte")] uint packetFlags, [EventLogMethodParameter(Title = "Packet Length", OrdinalInStruct = 3, TypeInStruct = "ushort")] uint packetLength) { if ((debugOptions & LogReceivedPackets /* To Debugger */) != 0) { string flagsText = FlagsToText(packetFlags); // TODO Move then Qualify Core.Log("TCP: Ses{0,3} ({1}) Packet ({2}) Len{3,4} received", sessionId, TcpState.TcpStateNames[(uint)sessionState], flagsText, packetLength); } if ((ControlFlags & LogReceivedPackets) != 0) { ReceivedPacketEntry receivedPacketEntry = new ReceivedPacketEntry(sessionId, sessionState, packetFlags, packetLength); unsafe { return (LogEntry(ControlFlags, receivedPacketTypeHandle, (byte*)&receivedPacketEntry, sizeof(ReceivedPacketEntry)) != 0); } } return false; } //[NoHeapAllocation] [EventLogMethod("TcpPacketSending", HeapAllowed = true, DebugPrint = false, FormatString = "TCP: Ses{0,3} ({1}) Packet ({2}) Len{3,4} being sent")] public bool LogSendingPacket( [EventLogMethodParameter(Title = "Session Id", OrdinalInStruct = 0, TypeInStruct = "ushort")] uint sessionId, [EventLogMethodParameter(Title = "Session State", OrdinalInStruct = 1, TypeInStruct = "byte")] TcpStateEnum sessionState, [EventLogMethodParameter(Title = "Packet Flags", OrdinalInStruct = 2, TypeInStruct = "byte")] uint packetFlags, [EventLogMethodParameter(Title = "Packet Length", OrdinalInStruct = 3, TypeInStruct = "ushort")] uint packetLength) { if ((debugOptions & LogSendingPackets /* To Debugger */) != 0) { string flagsText = FlagsToText(packetFlags); // TODO Move then Qualify Core.Log("TCP: Ses{0,3} ({1}) Packet ({2}) Len{3,4} being sent", sessionId, TcpState.TcpStateNames[(uint)sessionState], flagsText, packetLength); } if ((ControlFlags & LogSendingPackets) != 0) { SendingPacketEntry sendingPacketEntry = new SendingPacketEntry(sessionId, sessionState, packetFlags, packetLength); unsafe { return (LogEntry(ControlFlags, sendingPacketTypeHandle, (byte*)&sendingPacketEntry, sizeof(SendingPacketEntry)) != 0); } } return false; } //[NoHeapAllocation] [EventLogMethod("TcpTimeout", HeapAllowed = true, DebugPrint = false, FormatString = "TCP: Ses{0,3} ({1}) Timeout of type '{2}' occurred")] public bool LogTimeout( [EventLogMethodParameter(Title = "Session Id", OrdinalInStruct = 0, TypeInStruct = "ushort")] uint sessionId, [EventLogMethodParameter(Title = "Session State", OrdinalInStruct = 1, TypeInStruct = "byte")] TcpStateEnum sessionState, [EventLogMethodParameter(Title = "Timeout Type", OrdinalInStruct = 2, TypeInStruct = "byte")] TcpSession.TcpTimeoutType timeoutType) { if ((debugOptions & LogTimeouts /* To Debugger */) != 0) { Core.Log("TCP: Ses{0,3} ({1}) Timeout of type '{2}' occurred", sessionId, TcpState.TcpStateNames[(uint)sessionState], TcpSession.TcpTimeoutTypeNames[(uint)timeoutType]); } if ((ControlFlags & LogTimeouts) != 0) { TimeoutEntry timeoutEntry = new TimeoutEntry(sessionId, sessionState, timeoutType); unsafe { return (LogEntry(ControlFlags, timeoutTypeHandle, (byte*)&timeoutEntry, sizeof(TimeoutEntry)) != 0); } } return false; } //[NoHeapAllocation] [EventLogMethod("TcpSessionStateChangeContractCall", HeapAllowed = true, DebugPrint = true, FormatString = "TCP: Ses{0,3} ({1}) Contract EP '{2}' called.")] public bool LogSessionStateChangeContractCall( [EventLogMethodParameter(Title = "Session", OrdinalInStruct = 0, TypeInStruct = "ushort")] uint sessionId, [EventLogMethodParameter(Title = "SessionState", OrdinalInStruct = 1, TypeInStruct = "byte")] TcpStateEnum sessionState, [EventLogMethodParameter(Title = "CallId", OrdinalInStruct = 2, TypeInStruct = "byte")] TcpSessionContractEntrypoints contractEntrypoint) { return this.LogSessionContractCall(sessionId, sessionState, contractEntrypoint, LogStateChangeContractCalls); } //[NoHeapAllocation] [EventLogMethod("TcpSessionDataTransferContractCall", HeapAllowed = true, DebugPrint = true, FormatString = "TCP: Ses{0,3} ({1}) Contract EP '{2}' called.")] internal bool LogSessionDataTransferContractCall( [EventLogMethodParameter(Title = "Session", OrdinalInStruct = 0, TypeInStruct = "ushort")] uint sessionId, [EventLogMethodParameter(Title = "SessionState", OrdinalInStruct = 1, TypeInStruct = "byte")] TcpStateEnum sessionState, [EventLogMethodParameter(Title = "CallId", OrdinalInStruct = 2, TypeInStruct = "byte")] TcpSessionContractEntrypoints contractEntrypoint) { return this.LogSessionContractCall(sessionId, sessionState, contractEntrypoint, LogDataTransferContractCalls); } //[NoHeapAllocation] [EventLogMethod("TcpSessionQueryContractCall", HeapAllowed = true, DebugPrint = true, FormatString = "TCP: Ses{0,3} ({1}) Contract EP '{2}' called.")] internal bool LogSessionQueryContractCall( [EventLogMethodParameter(Title = "Session", OrdinalInStruct = 0, TypeInStruct = "ushort")] uint sessionId, [EventLogMethodParameter(Title = "SessionState", OrdinalInStruct = 1, TypeInStruct = "byte")] TcpStateEnum sessionState, [EventLogMethodParameter(Title = "CallId", OrdinalInStruct = 2, TypeInStruct = "byte")] TcpSessionContractEntrypoints contractEntrypoint) { return this.LogSessionContractCall(sessionId, sessionState, contractEntrypoint, LogQueryContractCalls); } //[NoHeapAllocation] [EventLogMethod("TcpSessionInfoContractCall", HeapAllowed = true, DebugPrint = true, FormatString = "TCP: Ses{0,3} ({1}) Contract EP '{2}' called.")] internal bool LogSessionInfoContractCall( [EventLogMethodParameter(Title = "Session", OrdinalInStruct = 0, TypeInStruct = "ushort")] uint sessionId, [EventLogMethodParameter(Title = "SessionState", OrdinalInStruct = 1, TypeInStruct = "byte")] TcpStateEnum sessionState, [EventLogMethodParameter(Title = "CallId", OrdinalInStruct = 2, TypeInStruct = "byte")] TcpSessionContractEntrypoints contractEntrypoint) { return this.LogSessionContractCall(sessionId, sessionState, contractEntrypoint, LogInfoContractCalls); } //[NoHeapAllocation] [EventLogMethod("TcpSessionContractCall", HeapAllowed = true, DebugPrint = true, FormatString = "TCP: Ses{0,3} ({1}) Contract EP '{2}' called.")] private bool LogSessionContractCall( [EventLogMethodParameter(Title = "Session", OrdinalInStruct = 0, TypeInStruct = "ushort")] uint sessionId, [EventLogMethodParameter(Title = "SessionState", OrdinalInStruct = 1, TypeInStruct = "byte")] TcpStateEnum sessionState, [EventLogMethodParameter(Title = "CallName", OrdinalInStruct = 2, TypeInStruct = "byte")] TcpSessionContractEntrypoints contractEntrypoint, uint flag) { if ((debugOptions & flag /* To Debugger */) != 0) { Core.Log("TCP: Ses{0,3} ({1}) Contract EP '{2}' called.", sessionId, TcpState.TcpStateNames[(uint)sessionState], TcpSessionEventsSource.ContractCallNames[(uint)contractEntrypoint]); } if ((ControlFlags & flag) != 0) { ContractCallEntry contractCallEntry = new ContractCallEntry(sessionId, sessionState, contractEntrypoint); unsafe { return (LogEntry(ControlFlags, contractCallTypeHandle, (byte*)&contractCallEntry, sizeof(ContractCallEntry)) != 0); } } return false; } public override bool Register() { // Check assumptions for remainder of method. if ((base.Register() == false) || (HostController == null)) { // BUGBUG AM: base.Register() should check if HostController is null, not all callers DebugStub.WriteLine("TcpSessionEventsSource: Improper Registration Environment."); return false; } // TcpSessionStateChange event registration if (HostController.RegisterEvent("TcpSessionStateChange", "TCP: Ses{0,3} ({1}) State Change to {2}.", ref stateChangeTypeHandle)) { // BUGBUG AM: Aliases possible with different structs. Should pass in Struct and Reflect to get name of runtime type, field names, ... if ((!HostController.RegisterEventField(stateChangeTypeHandle, "SessionId", 0, DataType.__uint16)) || (!HostController.RegisterEventField(stateChangeTypeHandle, "FromState", 0, DataType.__uint8)) || (!HostController.RegisterEventField(stateChangeTypeHandle, "ToState", 0, DataType.__uint8))) { stateChangeTypeHandle = 0; } } // TcpSessionReceivedPacket event registration if (HostController.RegisterEvent("TcpSessionReceivedPacket", "TCP: Ses{0,3} ({1}) Packet ({2}) Len{3,4} received", ref receivedPacketTypeHandle)) { if ((!HostController.RegisterEventField(receivedPacketTypeHandle, "SessionId", 0, DataType.__uint16)) || (!HostController.RegisterEventField(receivedPacketTypeHandle, "SessionState", 0, DataType.__uint8)) || (!HostController.RegisterEventField(receivedPacketTypeHandle, "PacketFlags", 0, DataType.__uint8)) || (!HostController.RegisterEventField(receivedPacketTypeHandle, "PacketLength", 0, DataType.__uint16))) { receivedPacketTypeHandle = 0; } } // TcpSessionReceivedPacket event registration if (HostController.RegisterEvent("TcpSessionSendingPacket", "TCP: Ses{0,3} ({1}) Packet ({2}) Len{3,4} being sent", ref sendingPacketTypeHandle)) { if ((!HostController.RegisterEventField(sendingPacketTypeHandle, "SessionId", 0, DataType.__uint16)) || (!HostController.RegisterEventField(sendingPacketTypeHandle, "SessionState", 0, DataType.__uint8)) || (!HostController.RegisterEventField(sendingPacketTypeHandle, "PacketFlags", 0, DataType.__uint8)) || (!HostController.RegisterEventField(sendingPacketTypeHandle, "PacketLength", 0, DataType.__uint16))) { sendingPacketTypeHandle = 0; } } // TcpSessionTimeout event registration if (HostController.RegisterEvent("TcpSessionTimeout", "TCP: Ses{0,3} ({1}) Timeout of type '{2}' occurred", ref timeoutTypeHandle)) { if ((!HostController.RegisterEventField(timeoutTypeHandle, "SessionId", 0, DataType.__uint16)) || (!HostController.RegisterEventField(timeoutTypeHandle, "SessionState", 0, DataType.__uint8)) || (!HostController.RegisterEventField(timeoutTypeHandle, "TimeoutType", 0, DataType.__uint8))) { timeoutTypeHandle = 0; } } // TcpSessionContractCall event registration if (HostController.RegisterEvent("TcpSessionContractCall", "TCP: Ses{0,3} ({1}) Contract EP '{2}' called.", ref contractCallTypeHandle)) { if ((!HostController.RegisterEventField(contractCallTypeHandle, "SessionId", 0, DataType.__uint16)) || (!HostController.RegisterEventField(contractCallTypeHandle, "SessionState", 0, DataType.__uint8)) || (!HostController.RegisterEventField(contractCallTypeHandle, "ContractCall", 0, DataType.__uint8))) { contractCallTypeHandle = 0; } } // Make sure all handles were either there before or were created here. if ((stateChangeTypeHandle == 0) || (contractCallTypeHandle == 0) || (sendingPacketTypeHandle == 0) || (sendingPacketTypeHandle == 0)) { // Construct an error message StringBuilder errorString = new StringBuilder(); String conjunction = "TcpSessionEventsSource: Registration Failed for "; // State Change if (stateChangeTypeHandle == 0) { errorString.Append(conjunction); errorString.Append("StateChangeEventType"); conjunction = ", "; } // Received Packet if (receivedPacketTypeHandle == 0) { errorString.Append(conjunction); errorString.Append("ReceivedPacketEventType"); conjunction = ", "; } // Sending Packet if (sendingPacketTypeHandle == 0) { errorString.Append(conjunction); errorString.Append("SendingPacketEventType"); conjunction = ", "; } // Timeout if (timeoutTypeHandle == 0) { errorString.Append(conjunction); errorString.Append("TimeoutEventType"); conjunction = ", "; } // Contract Call if (contractCallTypeHandle == 0) { errorString.Append(conjunction); errorString.Append("ContractCallEventType"); conjunction = ", "; } // Complete the error message and write it to the debugger. errorString.Append("."); errorString.Append(Environment.NewLine); DebugStub.Write(errorString.ToString()); // Report the failure. return false; } // If this is reached then everything worked so report success. return true; } [Pure] [Inline] private static string FlagsToText(uint flags) { string[] loBits = new string[] { "....", "F...", ".S..", "FS..", "..R.", "F.R.", ".SR.", "FSR.", "...P", "F..P", ".S.P", "FS.P", "..RP", "F.RP", ".SRP", "FSRP", }; string[] hiBits = new string[] { "....", "A...", ".I..", "AI..", "..E.", "A.E.", ".IE.", "AIE.", "...C", "A..C", ".I.C", "AI.C", "..EC", "A.EC", ".IEC", "AIEC", }; return loBits[(flags >> 0) & 0x0F] + hiBits[(flags >> 4) & 0x0F]; } } }