139 lines
5 KiB
C#
139 lines
5 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using AsterNET.FastAGI.Command;
|
|
using AsterNET.IO;
|
|
|
|
namespace AsterNET.FastAGI
|
|
{
|
|
/// <summary>
|
|
/// An AGIConnectionHandler is created and run by the AGIServer whenever a new
|
|
/// socket connection from an Asterisk Server is received.<br />
|
|
/// It reads the request using an AGIReader and runs the AGIScript configured to
|
|
/// handle this type of request. Finally it closes the socket connection.
|
|
/// </summary>
|
|
public class AGIConnectionHandler
|
|
{
|
|
#if LOGGER
|
|
private readonly Logger logger = Logger.Instance();
|
|
#endif
|
|
private static readonly LocalDataStoreSlot _channel = Thread.AllocateDataSlot();
|
|
private readonly SocketConnection socket;
|
|
private readonly IMappingStrategy mappingStrategy;
|
|
private readonly bool _SC511_CAUSES_EXCEPTION;
|
|
private readonly bool _SCHANGUP_CAUSES_EXCEPTION;
|
|
|
|
#region Channel
|
|
|
|
/// <summary>
|
|
/// Returns the AGIChannel associated with the current thread.
|
|
/// </summary>
|
|
/// <returns>the AGIChannel associated with the current thread or null if none is associated.</returns>
|
|
internal static AGIChannel Channel
|
|
{
|
|
get { return (AGIChannel) Thread.GetData(_channel); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AGIConnectionHandler(socket, mappingStrategy)
|
|
|
|
/// <summary>
|
|
/// Creates a new AGIConnectionHandler to handle the given socket connection.
|
|
/// </summary>
|
|
/// <param name="socket">the socket connection to handle.</param>
|
|
/// <param name="mappingStrategy">the strategy to use to determine which script to run.</param>
|
|
public AGIConnectionHandler(SocketConnection socket, IMappingStrategy mappingStrategy,
|
|
bool SC511_CAUSES_EXCEPTION, bool SCHANGUP_CAUSES_EXCEPTION)
|
|
{
|
|
this.socket = socket;
|
|
this.mappingStrategy = mappingStrategy;
|
|
_SC511_CAUSES_EXCEPTION = SC511_CAUSES_EXCEPTION;
|
|
_SCHANGUP_CAUSES_EXCEPTION = SCHANGUP_CAUSES_EXCEPTION;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void Run()
|
|
{
|
|
try
|
|
{
|
|
var reader = new AGIReader(socket);
|
|
var writer = new AGIWriter(socket);
|
|
AGIRequest request = reader.ReadRequest();
|
|
|
|
//Added check for when the request is empty
|
|
//eg. telnet to the service
|
|
if (request.Request.Count > 0)
|
|
{
|
|
var channel = new AGIChannel(writer, reader, _SC511_CAUSES_EXCEPTION, _SCHANGUP_CAUSES_EXCEPTION);
|
|
AGIScript script = mappingStrategy.DetermineScript(request);
|
|
Thread.SetData(_channel, channel);
|
|
|
|
if (script != null)
|
|
{
|
|
#if LOGGER
|
|
logger.Info("Begin AGIScript " + script.GetType().FullName + " on " + Thread.CurrentThread.Name);
|
|
#endif
|
|
script.Service(request, channel);
|
|
#if LOGGER
|
|
logger.Info("End AGIScript " + script.GetType().FullName + " on " + Thread.CurrentThread.Name);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
var error = "No script configured for URL '" + request.RequestURL + "' (script '" + request.Script +
|
|
"')";
|
|
channel.SendCommand(new VerboseCommand(error, 1));
|
|
#if LOGGER
|
|
logger.Error(error);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var error = "A connection was made with no requests";
|
|
#if LOGGER
|
|
logger.Error(error);
|
|
#endif
|
|
}
|
|
}
|
|
catch (AGIHangupException)
|
|
{
|
|
}
|
|
catch (IOException)
|
|
{
|
|
}
|
|
catch (AGIException ex)
|
|
{
|
|
#if LOGGER
|
|
logger.Error("AGIException while handling request", ex);
|
|
#else
|
|
throw ex;
|
|
#endif
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
#if LOGGER
|
|
logger.Error("Unexpected Exception while handling request", ex);
|
|
#else
|
|
throw ex;
|
|
#endif
|
|
}
|
|
|
|
Thread.SetData(_channel, null);
|
|
try
|
|
{
|
|
socket.Close();
|
|
}
|
|
#if LOGGER
|
|
catch (IOException ex)
|
|
{
|
|
logger.Error("Error on close socket", ex);
|
|
}
|
|
#else
|
|
catch { }
|
|
#endif
|
|
}
|
|
}
|
|
} |