/// <summary> // NOTE: We only support starting a session monitor /// if we catch a client request or server status /// response at the head of the TcpStream. /// We *could* pick things up in the middle but it would /// require a bit more effort for what shouldn't be /// a typical case. /// </summary> /// <param name="c"> /// A <see cref="TcpConnection"/> /// </param> /// <param name="OnHttpRequestFound"> /// A <see cref="OnHttpRequestFoundDelegate"/> /// </param> /// <param name="OnHttpStatusFound"> /// A <see cref="OnHttpStatusFoundDelegate"/> /// </param> /// <param name="OnHttpWatcherError"> /// A <see cref="OnHttpWatcherErrorDelegate"/> /// </param> public HttpSessionWatcher(TcpConnection c, OnHttpRequestFoundDelegate OnHttpRequestFound, OnHttpStatusFoundDelegate OnHttpStatusFound, OnHttpWatcherErrorDelegate OnHttpWatcherError) { if (IsDebugEnabled) { log.Debug(""); } // attach stream generators to both flows of the given connection streamGenerator0 = new TcpStreamGenerator(c.Flows[0], new TimeSpan(0, 0, 60), null); streamGenerator0.OnCallback += HandleStreamGeneratorOnCallback; tcpStreamGeneratorToMonitorType[streamGenerator0] = MonitorTypes.Unknown; streamGenerator1 = new TcpStreamGenerator(c.Flows[1], new TimeSpan(0, 0, 60), null); streamGenerator1.OnCallback += HandleStreamGeneratorOnCallback; tcpStreamGeneratorToMonitorType[streamGenerator1] = MonitorTypes.Unknown; requestsWaitingForStatus = new Queue <HttpRequest>(); // setup the delegates this.OnHttpRequestFound = OnHttpRequestFound; this.OnHttpStatusFound = OnHttpStatusFound; this.OnHttpWatcherError = OnHttpWatcherError; }
private void SetTypeForTcpStreamGenerator(TcpStreamGenerator sg, MonitorTypes monitorType) { if (sg == streamGenerator0) { MonitorTypeFlow0 = monitorType; } else { MonitorTypeFlow1 = monitorType; } }
TcpStreamGenerator.CallbackReturnValue HandleTcpStreamGeneratorOnCallback(TcpStreamGenerator tcpStreamGenerator, TcpStreamGenerator.CallbackCondition condition) { Console.WriteLine("{0} bytes in stream", tcpStreamGenerator.tcpStream.Length); int expectedSize = 0; for (int i = 0; i < callbackCount; i++) { expectedSize += payloadSizes[i]; } Assert.Equal(expectedSize, tcpStreamGenerator.tcpStream.Length); callbackCount++; return(TcpStreamGenerator.CallbackReturnValue.ContinueMonitoring); }
void HandleConnectionManagerOnConnectionFound(TcpConnection c) { Console.WriteLine("HandleConnectionManagerOnConnectionFound c {0}", c.ToString()); var timeout = new TimeSpan(0, 5, 0); TcpStreamGenerator incomingGenerator = new TcpStreamGenerator(c.Flows[0], timeout, 100000); incomingGenerator.OnCallback += HandleTcpStreamGeneratorOnCallback; incomingGenerators.Add(incomingGenerator); // We only test the first of the two flows in this unit test // so no need to attach to the other flow #if false TcpStreamGenerator outgoingGenerator = new TcpStreamGenerator(c.Flows[1], timeout, 100000); outgoingGenerator.OnCallback += HandleTcpStreamGeneratorOnCallback; outgoingGenerators.Add(outgoingGenerator); #endif }
// Process the given tcpStream until either // - ProcessStatus.Error OR // - ProcessStatus.NeedMoreData OR // - ProcessStatus.Completed // // ProcessStatus.Continue is hidden as this method will simply // loop internally, asking the current HttpMessage to continue processing // // see HttpMessage.Process() for return values from this method as they // are the same private HttpMessage.ProcessStatus HandleTcpStreamGenerator(TcpStreamGenerator tcpStreamGenerator) { var tcpStream = tcpStreamGenerator.tcpStream; var monitorType = tcpStreamGeneratorToMonitorType[tcpStreamGenerator]; if (IsDebugEnabled) { log.DebugFormat("monitorType: {0}", monitorType); } HttpMessage theMessage = null; // retrieve the pending message or create and assign a new one if there // is no pending message if (monitorType == MonitorTypes.Client) { if (pendingRequest == null) { if (IsDebugEnabled) { log.Debug("No pendingRequest, creating a new one"); } pendingRequest = new HttpRequest(); } theMessage = pendingRequest; } else if (monitorType == MonitorTypes.Server) { if (pendingStatus == null) { if (IsDebugEnabled) { log.Debug("no pendingStatus, creating a new one"); } pendingStatus = new HttpStatus(); } theMessage = pendingStatus; } BinaryReader br = new BinaryReader(tcpStream); // default to NeedMoreData since that would be our state if // we didn't get into the while() loop due to running out of data HttpMessage.ProcessStatus status = HttpMessage.ProcessStatus.NeedMoreData; // outer loop runs while we have bytes to process // // NOTE: We can process until we run out of data because we re-use // the same message for the given TcpStream while (br.BaseStream.Position < br.BaseStream.Length) { // if we haven't identified the monitor type yet, attempt to do so now if (monitorType == HttpSessionWatcher.MonitorTypes.Unknown) { // attempt to process as a request // NOTE: Must assign pendingRequest BEFORE calling ProcessBinaryReader() // which may pass the object if processing completes pendingRequest = new HttpRequest(); status = ProcessBinaryReader(pendingRequest, MonitorTypes.Client, br); if (status == HttpMessage.ProcessStatus.Error) { pendingRequest = null; // attempt to process as a status // NOTE: Must assign pendingStatus BEFORE calling ProcessBinaryReader() // which may pass the object if processing completes pendingStatus = new HttpStatus(); status = ProcessBinaryReader(pendingStatus, MonitorTypes.Server, br); if (status == HttpMessage.ProcessStatus.Error) { pendingStatus = null; return(status); } else // success { theMessage = pendingStatus; monitorType = HttpSessionWatcher.MonitorTypes.Server; // assign the monitor type SetTypeForTcpStreamGenerator(tcpStreamGenerator, monitorType); } } else // success { theMessage = pendingRequest; monitorType = HttpSessionWatcher.MonitorTypes.Client; // assign the monitor type SetTypeForTcpStreamGenerator(tcpStreamGenerator, monitorType); } } else // otherwise just process the data like normal { status = ProcessBinaryReader(theMessage, monitorType, br); } // stop processing if we need more data // or if we are complete since we are done with this message and // only by re-entering this function do we create a new one if ((status == HttpMessage.ProcessStatus.NeedMoreData) || (status == HttpMessage.ProcessStatus.Complete)) { break; } } return(status); }
TcpStreamGenerator.CallbackReturnValue HandleStreamGeneratorOnCallback(TcpStreamGenerator tcpStreamGenerator, TcpStreamGenerator.CallbackCondition condition) { switch (condition) { // stop monitoring if we have an error condition case TcpStreamGenerator.CallbackCondition.SizeLimitReached: case TcpStreamGenerator.CallbackCondition.OutOfRange: case TcpStreamGenerator.CallbackCondition.ConnectionTimeout: case TcpStreamGenerator.CallbackCondition.StreamError: string errorString = string.Format("condition == {0}, shutting down monitors", condition); log.Warn(errorString); ShutDownMonitor(errorString); return(TcpStreamGenerator.CallbackReturnValue.StopMonitoring); // early out if we don't have the next packet in sequence case TcpStreamGenerator.CallbackCondition.OutOfSequence: if (IsDebugEnabled) { log.DebugFormat("condition {0} != TcpStreamMonitor.CallbackCondition.NextInSequence, returning ContinueMonitoring", condition); } return(TcpStreamGenerator.CallbackReturnValue.ContinueMonitoring); case TcpStreamGenerator.CallbackCondition.DuplicateDropped: // nothing to do here, we dropped a duplicate entry return(TcpStreamGenerator.CallbackReturnValue.ContinueMonitoring); // normal case, nothing to do here but fall through case TcpStreamGenerator.CallbackCondition.NextInSequence: break; default: string error = "Unknown condition of '" + condition + "'"; throw new System.InvalidOperationException(error); } // process the data in the TcpStream until we encounter // an error/exception case HttpMessage.ProcessStatus processStatus; while (true) { processStatus = HandleTcpStreamGenerator(tcpStreamGenerator); if (IsDebugEnabled) { log.DebugFormat("processStatus is {0}", processStatus); } // if an error was detected we should stop monitoring the monitor // with the error and delete the other monitor if (processStatus == HttpMessage.ProcessStatus.Error) { var monitorType = tcpStreamGeneratorToMonitorType[tcpStreamGenerator]; string errorString = string.Format("Processing monitorType {0} got {1}, stopping monitor and deleting other monitor", monitorType, processStatus); ShutDownMonitor(errorString); return(TcpStreamGenerator.CallbackReturnValue.StopMonitoring); } else if (processStatus == HttpMessage.ProcessStatus.NeedMoreData) { // not enough data remaining in the TcpStream so stop looping // and ask the TcpStreamMonitor to continue monitoring return(TcpStreamGenerator.CallbackReturnValue.ContinueMonitoring); } else if (processStatus == HttpMessage.ProcessStatus.Continue) { // just continue looping } else if (processStatus == HttpMessage.ProcessStatus.Continue) { // just continue looping } } }