using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using Misuzilla.Applications.TwitterIrcGateway.Authentication;
namespace Misuzilla.Applications.TwitterIrcGateway
{
///
/// TwitterIrcGatewayの接続サーバ機能を提供します。
///
public class Server : MarshalByRefObject
{
private static List _runningServers = new List();
private static Dictionary _sessions;
private TcpListener _tcpListener;
private Encoding _encoding = Encoding.GetEncoding("ISO-2022-JP");
///
/// APIアクセスに利用するプロクシサーバの設定
///
public IWebProxy Proxy = null;
///
/// APIアクセスに利用するOAuthのクライアントキー
///
public String OAuthClientKey { get; set; }
///
/// APIアクセスに利用するOAuthのシークレットキー
///
public String OAuthSecretKey { get; set; }
public const String ServerName = "localhost";
public const String ServerNick = "$TweetIrcGatewayServer$";
///
/// ユーザ認証を行うクラスを取得・設定します
///
public IAuthentication Authentication { get; set; }
///
/// SSL通信を必要とするかどうかを取得します
///
public Boolean IsSslConnection { get; private set; }
///
/// SSLの認証に利用する証明書を取得・設定します
///
public X509Certificate Certificate { get; set; }
///
/// 新たなセッションが開始されたイベント
///
public event EventHandler ConnectionAttached;
///
/// 文字エンコーディングを取得・設定します
///
public Encoding Encoding
{
get { return _encoding; }
set { _encoding = value; }
}
///
/// サーバが現在動作中かどうかを取得します
///
public Boolean IsRunning
{
get { return _tcpListener != null; }
}
///
/// 現在存在しているセッション情報のコレクションを取得します。
///
public IDictionary Sessions
{
get { return _sessions; }
}
///
/// 現在実行しているサーバのコレクションを取得します。
///
public static IList RunningServers
{
get { return _runningServers.AsReadOnly(); }
}
public Server() : this(false)
{
}
public Server(Boolean useSslConnection)
{
// for Mono
if (Environment.OSVersion.Platform == PlatformID.Unix)
ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };
// OAuth Default Tokens (TweetIrcGateway)
OAuthClientKey = "9gGt51Xp3AB8C7wU2Tw";
OAuthSecretKey = "74K9CwKANFVLVupHMtHy4fJ3TjAJq58CvxxtAQjoI";
ServicePointManager.DefaultConnectionLimit = 1000;
Authentication = new OAuthAuthentication();
IsSslConnection = useSslConnection;
}
///
/// 指定したIPアドレスとポートでクライアントからの接続待ち受けを開始します
///
/// 接続を待ち受けるIPアドレス
/// 接続を待ち受けるポート
public void Start(IPAddress ipAddr, Int32 port)
{
if (IsRunning)
{
throw new InvalidOperationException();
}
lock (_runningServers)
{
_runningServers.Add(this);
}
_sessions = new Dictionary();
TraceLogger.Server.Information(String.Format("Starting IRC Server: IPAddress = {0}, Port = {1}, IsSslConnection={2}", ipAddr, port, IsSslConnection));
_tcpListener = new TcpListener(ipAddr, port);
_tcpListener.Start();
_tcpListener.BeginAcceptTcpClient(AcceptHandled, this);
}
///
/// クライアントからの接続待ち受けを停止します
///
public void StopListen()
{
lock (this)
{
if (_tcpListener != null)
{
_tcpListener.Stop();
_tcpListener = null;
}
}
}
///
/// クライアントからの接続待ち受けを停止し、すべてのセッションを停止します。
///
public void Stop()
{
lock (this)
{
StopListen();
lock (_runningServers)
{
_runningServers.Remove(this);
}
lock (_sessions)
{
List sessions = new List(_sessions.Values);
foreach (SessionBase session in sessions)
{
session.Close();
}
}
}
}
public override string ToString()
{
return String.Format("Server: LocalEndPoint={0}", _tcpListener.LocalEndpoint);
}
public SessionBase GetSession(String sessionId)
{
lock (_sessions)
{
if (_sessions.ContainsKey(sessionId))
return _sessions[sessionId];
}
return null;
}
public SessionBase GetOrCreateSession(User user)
{
return GetOrCreateSession(user.Id.ToString(), (server, sessionId) => new Session(user, this));
}
public SessionBase GetOrCreateSession(String sessionId, Func sessionFactory)
{
lock (_sessions)
{
if (!_sessions.ContainsKey(sessionId))
{
_sessions[sessionId] = sessionFactory(this, sessionId);
_sessions[sessionId].ConnectionAttached += new EventHandler(Server_ConnectionAttached);
}
return _sessions[sessionId];
}
}
void Server_ConnectionAttached(object sender, ConnectionAttachEventArgs e)
{
if (ConnectionAttached != null)
{
ConnectionAttached(sender, e);
}
}
#region Internal Implementation
void AcceptHandled(IAsyncResult ar)
{
TcpClient tcpClient = null;
if (_tcpListener != null)
{
lock (this)
lock (_tcpListener)
{
if (_tcpListener != null && ar.IsCompleted)
{
tcpClient = _tcpListener.EndAcceptTcpClient(ar);
_tcpListener.BeginAcceptTcpClient(AcceptHandled, this);
}
}
}
if (tcpClient != null && tcpClient.Connected)
{
TraceLogger.Server.Information(String.Format("Client Connected: RemoteEndPoint={0}", tcpClient.Client.RemoteEndPoint));
Connection connection = new Connection(this, tcpClient);
connection.Start();
}
}
#endregion
}
}