863 lines
36 KiB
C#
863 lines
36 KiB
C#
// ----------------------------------------------------------------------------
|
|
//
|
|
// 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
|
|
{
|
|
/// <summary>
|
|
/// A class-only attribute to denote an Event Logging Source.
|
|
/// </summary>
|
|
[AttributeUsage(AttributeTargets.Class)]
|
|
public sealed class EventLogSourceAttribute : Attribute
|
|
{
|
|
private string id = String.Empty;
|
|
private bool fieldRegistrationErrorFatal = true;
|
|
|
|
/// <summary>
|
|
/// Sole constructor requiring the source Identifier as the only parameter.
|
|
/// </summary>
|
|
/// <params name="id">
|
|
/// A string identifier for the particular event logging <b>source</b>.
|
|
/// </params>
|
|
public EventLogSourceAttribute(string id)
|
|
{
|
|
this.id = id;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A string identifier for the particular event logging <b>source</b>.
|
|
/// </summary>
|
|
public string Id
|
|
{
|
|
get { return this.id; }
|
|
set { this.id = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// A Boolean that dictates the handling of a field registration errors.
|
|
/// If <b>true</b> (the default), any field registration error causes
|
|
/// the entire registration, and therefore the Create method, to fail.
|
|
/// </summary>
|
|
public bool FieldRegistationErrorFatal
|
|
{
|
|
get { return this.fieldRegistrationErrorFatal; }
|
|
set { this.fieldRegistrationErrorFatal = value; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A method-only attribute denoting an Event Logging Method.
|
|
/// </summary>
|
|
[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;
|
|
|
|
/// <summary>
|
|
/// Sole constructor requiring the method (event type)
|
|
/// identifier as the only parameter.
|
|
/// </summary>
|
|
/// <params name="id">
|
|
/// A string identifier for the particular event logging <b>method</b>
|
|
/// which becomes the identifier for the event type.
|
|
/// </params>
|
|
public EventLogMethodAttribute(string id)
|
|
{
|
|
this.id = id;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A string identifier for the particular event logging <b>method</b>
|
|
/// which becomes the identifier for the event type.
|
|
/// </summary>
|
|
public string Id
|
|
{
|
|
get { return this.id; }
|
|
set { this.id = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// If true, the generated code can perform heap allocations. NOT SURE IF NEEDED. // TODO
|
|
/// </summary>
|
|
public bool HeapAllowed
|
|
{
|
|
get { return this.heapAllowed; }
|
|
set { this.heapAllowed = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// If true, the generated code will include a test
|
|
/// for the DebugPrint bit for this event type.
|
|
/// </summary>
|
|
public bool DebugPrint
|
|
{
|
|
get { return this.debugPrint; }
|
|
set { this.debugPrint = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// A 'String.Format' format control string used when:
|
|
/// <para>
|
|
/// 1. The event is transferred to the debugger, and
|
|
/// </para>
|
|
/// <para>
|
|
/// 2. The event is displayed with the script tool in a mixed stream.
|
|
/// </para>
|
|
/// </summary>
|
|
public string FormatString
|
|
{
|
|
get { return this.formatString; }
|
|
set { this.formatString = value; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A parameter-only attribute describing the treatment
|
|
/// of a single parameter to an event logging method.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// No Id is present as a Property as the parameter's
|
|
/// name is the natural Id.
|
|
/// </remarks>
|
|
[AttributeUsage(AttributeTargets.Parameter)]
|
|
public sealed class EventLogMethodParameterAttribute : Attribute
|
|
{
|
|
private string title = String.Empty;
|
|
private uint ordinalInStruct;
|
|
private string typeInStruct = String.Empty;
|
|
|
|
/// <summary>
|
|
/// A string used in lieu of the parameter name in columnar reports.
|
|
/// </summary>
|
|
/// <remarks>If not supplied, the parameter name is used.</remarks>
|
|
public string Title
|
|
{
|
|
get { return this.title; }
|
|
set { this.title = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies the zero-based ordinal of this parameter in the structure
|
|
/// used to add this event to the event stream.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If not supplied, the parameter order in the method call is used.
|
|
/// </remarks>
|
|
public uint OrdinalInStruct
|
|
{
|
|
get { return this.ordinalInStruct; }
|
|
set { this.ordinalInStruct = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies the type of the data element to use in the structure used
|
|
/// to add this event to the event stream.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If not supplied, the type of the parameter in the method call is used.
|
|
/// </remarks>
|
|
public string TypeInStruct // BUGBUG: Should not be a string, should be a value-type. // TODO
|
|
{
|
|
get { return this.typeInStruct; }
|
|
set { this.typeInStruct = value; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Eventing and Tracing support for the TcpSession class.
|
|
/// </summary>
|
|
[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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The Static Constructor. It creates the event session for this SIP.
|
|
/// </summary>
|
|
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
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create and Register a TcpSessionEventsSource.
|
|
/// </summary>
|
|
/// <devdoc>
|
|
/// This should be a Generic when supported. Or use more of the base class (Static?) // BUGBUG AM (later?)
|
|
/// </devdoc>
|
|
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;
|
|
}
|
|
|
|
/// <summary>Fully parameterized and sole constructor.</summary>
|
|
/// <devdoc>BUGBUG AM: parameterization: have base EP that takes storageoptions and size to elim dup code (generated or not)</devdoc>
|
|
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];
|
|
}
|
|
}
|
|
}
|