public override void Stop()
 {
     base.Stop();
     // Shutdown currently open streaming connections.
     lock (_currentStreamingRequests.SyncRoot) {
         foreach (DictionaryEntry entry in _currentStreamingRequests)
         {
             EndpointPushNotifier notifier = entry.Value as EndpointPushNotifier;
             notifier.Close();
         }
         _currentStreamingRequests = null;
     }
 }
        private void HandleFlexClientStreamingOpenRequest(HttpRequest request, HttpResponse response, IClient flexClient)
        {
            Session session = FluorineContext.Current.Session as Session;

            if (session == null)
            {
                string msg = string.Format("Cannot grant streaming connection when ASP.NET session state is disabled", this.Id);
                if (log.IsWarnEnabled)
                {
                    log.Warn(msg);
                }
                try {
                    HandleBadRequest(msg, HttpContext.Current.Response);
                } catch (HttpException) { }
                return;
            }
            if (!_canStream || !session.CanStream)
            {
                string msg = string.Format("Cannot grant streaming connection, limit has been reached", this.Id);
                try {
                    HandleBadRequest(msg, HttpContext.Current.Response);
                } catch (HttpException) { }
                return;
            }

            bool canStream = false;

            lock (this.SyncRoot) {
                _streamingClientsCount.Increment();
                if (_streamingClientsCount.Value == this.MaxStreamingClients)
                {
                    canStream  = true;                    // This thread got the last spot.
                    _canStream = false;
                }
                else if (_streamingClientsCount.Value > this.MaxStreamingClients)
                {
                    canStream = false;                     // This thread lost the last spot.
                    _streamingClientsCount.Decrement();    // We're not going to grant the streaming right to the client.
                }
                else
                {
                    // Allow this thread to stream.
                    canStream = true;
                }
            }
            if (!canStream)
            {
                string msg = string.Format("Cannot service streaming request, max-streaming-clients reached in endpoint {0}", this.Id);
                try {
                    HandleBadRequest(msg, HttpContext.Current.Response);
                } catch (HttpException) { }
                return;
            }

            UserAgent userAgent = this.ChannelDefinition.Properties.UserAgentSettings[request.Browser.Browser];

            if (userAgent != null)
            {
                lock (session.SyncRoot) {
                    session.MaxConnectionsPerSession = userAgent.MaxStreamingConnectionsPerSession;
                }
            }

            lock (session.SyncRoot) {
                session.StreamingConnectionsCount++;
                if (session.StreamingConnectionsCount == session.MaxConnectionsPerSession)
                {
                    canStream         = true;             // This thread got the last spot in the session.
                    session.CanStream = false;
                }
                else if (session.StreamingConnectionsCount > session.MaxConnectionsPerSession)
                {
                    canStream = false;
                    session.StreamingConnectionsCount--;
                    _streamingClientsCount.Decrement();
                }
                else
                {
                    canStream = true;
                }
            }
            if (!canStream)
            {
                string msg = string.Format("Cannot grant streaming connection, limit has been reached", this.Id);
                try {
                    HandleBadRequest(msg, HttpContext.Current.Response);
                } catch (HttpException) { }
                return;
            }

            EndpointPushNotifier notifier = null;

            try {
                response.ContentType = ContentType.AMF;
                response.AppendHeader("Cache-Control", "no-cache");
                response.AppendHeader("Pragma", "no-cache");
                response.AppendHeader("Connection", "close");
                //response.AppendHeader("Transfer-Encoding", "chunked");
                response.Flush();

                // Setup for specific user agents.
                byte[] kickStartBytesToStream = null;
                int    kickStartBytes         = userAgent != null ? userAgent.KickstartBytes : 0;
                if (kickStartBytes > 0)
                {
                    // The minimum number of actual bytes that need to be sent to kickstart, taking into account transfer-encoding overhead.
                    try {
                        int chunkLengthHeaderSize = System.Text.Encoding.ASCII.GetBytes(System.Convert.ToString(kickStartBytes, 0x10)).Length; //System.Text.ASCIIEncoding.ASCII.GetBytes(kickStartBytes.ToString("X")).Length;
                        int chunkOverhead         = chunkLengthHeaderSize + 4;                                                                 // 4 for the 2 wrapping CRLF tokens.
                        int minimumKickstartBytes = kickStartBytes - chunkOverhead;
                        kickStartBytesToStream = new byte[(minimumKickstartBytes > 0) ? minimumKickstartBytes : kickStartBytes];
                    } catch {
                        kickStartBytesToStream = new byte[kickStartBytes];
                    }
                }
                if (kickStartBytesToStream != null)
                {
                    StreamChunk(kickStartBytesToStream, response);
                }
                try {
                    notifier = new EndpointPushNotifier(this, flexClient);
                    lock (_currentStreamingRequests.SyncRoot) {
                        _currentStreamingRequests.Add(notifier.Id, notifier);
                    }
                    // Push down an acknowledgement for the 'connect' request containing the unique id for this specific stream.
                    AcknowledgeMessage connectAck = new AcknowledgeMessage();
                    connectAck.body          = notifier.Id;
                    connectAck.correlationId = OpenCommand;
                    StreamMessage(connectAck, response);
                } catch (MessageException) {
                }

                if (log.IsDebugEnabled)
                {
                    string msg = string.Format("Start streaming for endpoint with id {0} and client with id {1}", this.Id, flexClient.Id);
                    log.Debug(msg);
                }

                int serverToClientHeartbeatMillis = this.ChannelDefinition.Properties.ServerToClientHeartbeatMillis >= 0 ? this.ChannelDefinition.Properties.ServerToClientHeartbeatMillis : 0;
                serverToClientHeartbeatMillis = 100;
                while (!notifier.IsClosed)
                {
                    IList messages = notifier.GetPendingMessages();
                    StreamMessages(messages, response);
                    lock (notifier.SyncRoot) {
                        Monitor.Wait(notifier.SyncRoot, serverToClientHeartbeatMillis);

                        messages = notifier.GetPendingMessages();
                        // If there are no messages to send to the client, send a 0
                        // byte as a heartbeat to make sure the client is still valid.
                        if ((messages == null || messages.Count == 0) && serverToClientHeartbeatMillis > 0)
                        {
                            try {
                                StreamChunk(Heartbeat, response);
                                response.Flush();
                            } catch (HttpException) {
                                break;
                            } catch (IOException) {
                                break;
                            }
                        }
                        else
                        {
                            StreamMessages(messages, response);
                        }
                    }
                }
                // Terminate the response.
                StreamChunk(null, response);
                if (log.IsDebugEnabled)
                {
                    string msg = string.Format("Releasing streaming connection for endpoint with id {0} and and client with id {1}", this.Id, flexClient.Id);
                    log.Debug(msg);
                }
            } catch (IOException ex)            //HttpException?
            {
                if (log.IsWarnEnabled)
                {
                    log.Warn("Streaming thread for endpoint with id " + this.Id + " is closing connection due to an IO error.", ex);
                }
            } catch (Exception ex) {
                if (log.IsErrorEnabled)
                {
                    log.Error("Streaming thread for endpoint with id " + this.Id + " is closing connection due to an error.", ex);
                }
            } finally {
                if (notifier != null && _currentStreamingRequests != null)
                {
                    if (_currentStreamingRequests != null)
                    {
                        lock (_currentStreamingRequests.SyncRoot) {
                            _currentStreamingRequests.Remove(notifier.Id);
                        }
                    }
                    notifier.Close();
                }
                _streamingClientsCount.Decrement();
                lock (session.SyncRoot) {
                    session.StreamingConnectionsCount--;
                    session.CanStream = session.StreamingConnectionsCount < session.MaxConnectionsPerSession;
                }
            }
        }
		private void HandleFlexClientStreamingOpenRequest(HttpRequest request, HttpResponse response, IClient flexClient) {
			Session session = FluorineContext.Current.Session as Session;
			if (session == null) {
				string msg = string.Format("Cannot grant streaming connection when ASP.NET session state is disabled", this.Id);
				if (log.IsWarnEnabled)
					log.Warn(msg);
				try {
					HandleBadRequest(msg, HttpContext.Current.Response);
				} catch (HttpException) { }
				return;
			}
			if (!_canStream || !session.CanStream) {
				string msg = string.Format("Cannot grant streaming connection, limit has been reached", this.Id);
				try {
					HandleBadRequest(msg, HttpContext.Current.Response);
				} catch (HttpException) { }
				return;
			}

			bool canStream = false;
			lock (this.SyncRoot) {
				_streamingClientsCount.Increment();
				if (_streamingClientsCount.Value == this.MaxStreamingClients) {
					canStream = true; // This thread got the last spot.
					_canStream = false;

				} else if (_streamingClientsCount.Value > this.MaxStreamingClients) {
					canStream = false; // This thread lost the last spot.
					_streamingClientsCount.Decrement();// We're not going to grant the streaming right to the client.
				} else {
					// Allow this thread to stream.
					canStream = true;
				}
			}
			if (!canStream) {
				string msg = string.Format("Cannot service streaming request, max-streaming-clients reached in endpoint {0}", this.Id);
				try {
					HandleBadRequest(msg, HttpContext.Current.Response);
				} catch (HttpException) { }
				return;
			}

			UserAgent userAgent = this.ChannelDefinition.Properties.UserAgentSettings[request.Browser.Browser];
			if (userAgent != null) {
				lock (session.SyncRoot) {
					session.MaxConnectionsPerSession = userAgent.MaxStreamingConnectionsPerSession;
				}
			}

			lock (session.SyncRoot) {
				session.StreamingConnectionsCount++;
				if (session.StreamingConnectionsCount == session.MaxConnectionsPerSession) {
					canStream = true; // This thread got the last spot in the session.
					session.CanStream = false;
				} else if (session.StreamingConnectionsCount > session.MaxConnectionsPerSession) {
					canStream = false;
					session.StreamingConnectionsCount--;
					_streamingClientsCount.Decrement();
				} else {
					canStream = true;
				}
			}
			if (!canStream) {
				string msg = string.Format("Cannot grant streaming connection, limit has been reached", this.Id);
				try {
					HandleBadRequest(msg, HttpContext.Current.Response);
				} catch (HttpException) { }
				return;
			}

			EndpointPushNotifier notifier = null;
			try {
				response.ContentType = ContentType.AMF;
				response.AppendHeader("Cache-Control", "no-cache");
				response.AppendHeader("Pragma", "no-cache");
				response.AppendHeader("Connection", "close");
				//response.AppendHeader("Transfer-Encoding", "chunked");
				response.Flush();

				// Setup for specific user agents.
				byte[] kickStartBytesToStream = null;
				int kickStartBytes = userAgent != null ? userAgent.KickstartBytes : 0;
				if (kickStartBytes > 0) {
					// The minimum number of actual bytes that need to be sent to kickstart, taking into account transfer-encoding overhead.
					try {
						int chunkLengthHeaderSize = System.Text.Encoding.ASCII.GetBytes(System.Convert.ToString(kickStartBytes, 0x10)).Length; //System.Text.ASCIIEncoding.ASCII.GetBytes(kickStartBytes.ToString("X")).Length;
						int chunkOverhead = chunkLengthHeaderSize + 4; // 4 for the 2 wrapping CRLF tokens.
						int minimumKickstartBytes = kickStartBytes - chunkOverhead;
						kickStartBytesToStream = new byte[(minimumKickstartBytes > 0) ? minimumKickstartBytes : kickStartBytes];
					} catch {
						kickStartBytesToStream = new byte[kickStartBytes];
					}
				}
				if (kickStartBytesToStream != null) {
					StreamChunk(kickStartBytesToStream, response);
				}
				try {
					notifier = new EndpointPushNotifier(this, flexClient);
					lock (_currentStreamingRequests.SyncRoot) {
						_currentStreamingRequests.Add(notifier.Id, notifier);
					}
					// Push down an acknowledgement for the 'connect' request containing the unique id for this specific stream.
					AcknowledgeMessage connectAck = new AcknowledgeMessage();
					connectAck.body = notifier.Id;
					connectAck.correlationId = OpenCommand;
					StreamMessage(connectAck, response);
				} catch (MessageException) {
				}

				if (log.IsDebugEnabled) {
					string msg = string.Format("Start streaming for endpoint with id {0} and client with id {1}", this.Id, flexClient.Id);
					log.Debug(msg);
				}

				int serverToClientHeartbeatMillis = this.ChannelDefinition.Properties.ServerToClientHeartbeatMillis >= 0 ? this.ChannelDefinition.Properties.ServerToClientHeartbeatMillis : 0;
				serverToClientHeartbeatMillis = 100;
				while (!notifier.IsClosed) {
					IList messages = notifier.GetPendingMessages();
					StreamMessages(messages, response);
					lock (notifier.SyncRoot) {
						Monitor.Wait(notifier.SyncRoot, serverToClientHeartbeatMillis);

						messages = notifier.GetPendingMessages();
						// If there are no messages to send to the client, send a 0
						// byte as a heartbeat to make sure the client is still valid.
						if ((messages == null || messages.Count == 0) && serverToClientHeartbeatMillis > 0) {
							try {
								StreamChunk(Heartbeat, response);
								response.Flush();
							} catch (HttpException) {
								break;
							} catch (IOException) {
								break;
							}
						} else {
							StreamMessages(messages, response);
						}
					}
				}
				// Terminate the response.
				StreamChunk(null, response);
				if (log.IsDebugEnabled) {
					string msg = string.Format("Releasing streaming connection for endpoint with id {0} and and client with id {1}", this.Id, flexClient.Id);
					log.Debug(msg);
				}
			} catch (IOException ex)//HttpException?
			{
				if (log.IsWarnEnabled)
					log.Warn("Streaming thread for endpoint with id " + this.Id + " is closing connection due to an IO error.", ex);
			} catch (Exception ex) {
				if (log.IsErrorEnabled)
					log.Error("Streaming thread for endpoint with id " + this.Id + " is closing connection due to an error.", ex);
			} finally {
				if (notifier != null && _currentStreamingRequests != null) {
					if (_currentStreamingRequests != null) {
						lock (_currentStreamingRequests.SyncRoot) {
							_currentStreamingRequests.Remove(notifier.Id);
						}
					}
					notifier.Close();
				}
				_streamingClientsCount.Decrement();
				lock (session.SyncRoot) {
					session.StreamingConnectionsCount--;
					session.CanStream = session.StreamingConnectionsCount < session.MaxConnectionsPerSession;
				}
			}
		}