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 } }