Logo Search packages:      
Sourcecode: galaxium version File versions  Download package

HTTPConnection.cs

/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2008 Philippe Durand <draekz@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Timers;
using System.Net;
using System.IO;

using Anculus.Core;

using Galaxium.Core;
using Galaxium.Protocol;

namespace Galaxium.Protocol.Msn
{
      internal enum HTTPActions { Open, Poll, None };
      internal enum HTTPServerTypes { NS, SB };
      
      public class HTTPConnection : AbstractConnection
      {
            private HTTPActions _action = HTTPActions.None;
            private string _ip = String.Empty;
            private HTTPServerTypes _serverType = HTTPServerTypes.NS;
            private string _sessionID = String.Empty;
            private System.Timers.Timer _pollTimer;
            private bool _connected = false;
            private bool _sending = false;
            
            internal string IP
            {
                  get { return _ip; }
                  set { _ip = value; }
            }
            
            internal HTTPActions Action
            {
                  get { return _action; }
                  set { _action = value; }
            }
            
            internal HTTPServerTypes Type
            {
                  get { return _serverType; }
                  set { _serverType = value; }
            }
            
            public override bool IsConnected
            {
                  get
                  {
                        return _connected;
                  }
            }
            
            public override bool IsSending
            {
                  get { return _sending; }
            }
            
            public HTTPConnection (ISession session, IConnectionInfo connectionInfo) : base (session, connectionInfo)
            {
                  _pollTimer = new System.Timers.Timer (2000);
                  _pollTimer.Elapsed += PollForData;
                  _pollTimer.AutoReset = true;
            }
            
            public override void Connect ()
            {
                  Log.Debug ("Connect to {0}:{1}", _connectionInfo.HostName, _connectionInfo.Port);
                  
                  _intendedDisconnect = false;
                  
                  OnEstablished (new ConnectionEventArgs (this));
                  
                  _connected = true;
                  
                  OnAfterConnect (new ConnectionEventArgs (this));
            }

            protected override void Dispose (bool disposing)
            {
                  if (!_disposed)
                  {
                        if (disposing)
                        {
                              if (IsConnected)
                              {
                                    Log.Debug("Disconnecting during disposing of abstract connection.");
                                    Disconnect ();
                              }
                        }
                  }
                  
                  _disposed = true;
            }

            public override void Reconnect ()
            {
                  Disconnect ();
                  Connect ();
            }

            public override void Disconnect ()
            {
                  _intendedDisconnect = true;
                  
                  if (IsConnected)
                  {
                        _connected = false;
                        
                        if (_pollTimer.Enabled)
                              _pollTimer.Stop();
                        
                        OnClosed (new ConnectionEventArgs (this));
                  }
            }
            
            private string GenerateURI ()
            {
                  StringBuilder sb = new StringBuilder();
                  
                  sb.Append ("http://");
                  sb.Append (ConnectionInfo.HostName);
                  sb.Append ("/gateway/gateway.dll?");
                  
                  switch (Action)
                  {
                        case HTTPActions.Open:
                              sb.Append ("Action=open&");
                              sb.Append ("Server="+Type.ToString()+"&");
                              sb.Append ("IP="+IP);
                              break;
                        case HTTPActions.Poll:
                              sb.Append ("Action=poll&");
                              sb.Append ("SessionID="+_sessionID);
                              break;
                        case HTTPActions.None:
                              sb.Append ("SessionID="+_sessionID);
                              break;
                  }
                  
                  //Log.Debug ("Using URI: "+sb.ToString());
                  
                  return (sb.ToString());
            }
            
            public override void Send (byte[] data)
            {
                  ThrowUtility.ThrowIfNull ("data", data);
                  
                  lock (_lock)
                  {
                        // We dont want to send the poll while sending other stuff.
                        if (_pollTimer.Enabled)
                              _pollTimer.Stop ();
                        
                        HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create (GenerateURI ());
                        
                        if (Configuration.Proxy.Section.GetBool (Configuration.Proxy.UseProxy.Name, Configuration.Proxy.UseProxy.Default))
                        {
                              // We should use the HTTP proxy.
                              string host = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpHost.Name, Configuration.Proxy.HttpHost.Default);
                              int port = Configuration.Proxy.Section.GetInt (Configuration.Proxy.HttpPort.Name, Configuration.Proxy.HttpPort.Default);
                              string username = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpUsername.Name, Configuration.Proxy.HttpUsername.Default);
                              string password = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpPassword.Name, Configuration.Proxy.HttpPassword.Default);
                              
                              request.Proxy = new WebProxy (host, port);
                              request.Proxy.Credentials = new NetworkCredential (username, password);
                        }
                        
                        request.Method = "POST";
                        request.Accept = "*/*";
                        request.AllowAutoRedirect = false;
                        request.AllowWriteStreamBuffering = false;
                        request.KeepAlive = true;
                        request.UserAgent = "MSMSGS";
                        request.ContentType = "application/x-msn-messenger";
                        request.ContentLength = data.Length;
                        request.Headers.Add ("Pragma", "no-cache");
                        
                        Stream stream = request.GetRequestStream ();
                        stream.Write (data, 0, data.Length);
                        stream.Close ();
                        
                        _sending = true;
                        
                        request.BeginGetResponse(BeginGetResponseComplete, request);
                  }
            }
            
            private void BeginGetResponseComplete (IAsyncResult ar)
            {
                  bool wasSending = false;
                  byte[] responseData = null;
                  int responseLength = 0;
                  
                  lock (_lock)
                  {
                        if (ar != null)
                        {
                              HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
                              HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar);
                              
                              //Log.Debug ("Response Header: \n"+response.Headers.ToString());
                              
                              foreach (string str in response.Headers.AllKeys)
                              {
                                    switch (str)
                                    {
                                          case "Content-Length":
                                                responseLength = Int32.Parse(response.Headers.Get (str));
                                                break;
                                          case "X-MSN-Messenger":
                                                string text = response.Headers.Get(str);
                                                
                                                string[] parts = text.Split(';');
                                                foreach (string part in parts)
                                                {
                                                      string[] elements = part.Split('=');
                                                      switch (elements[0].Trim())
                                                      {
                                                            case "SessionID":
                                                                  _sessionID = elements[1];
                                                                  break;
                                                            case "GW-IP":
                                                                  ConnectionInfo.HostName = elements[1];
                                                                  break;
                                                            case "Session":
                                                                  break;
                                                            case "Action":
                                                                  break;
                                                      }
                                                }
                                                break;
                                    }
                              }
                              
                              responseData = new byte[responseLength];
                              int responseRead = 0;
                              
                              Stream responseStream = response.GetResponseStream();
                              
                              while (responseRead < responseLength)
                              {
                                    byte[] buf = new byte[256];
                                    int read = responseStream.Read (buf, 0, buf.Length);
                                    Array.Copy(buf, 0, responseData, responseRead, read);
                                    responseRead += read;
                              }
                              
                              responseStream.Close();
                              response.Close();
                              
                              // This looks odd I know, but we have to only say we are done sending, once we have received
                              // the data we are looking for. This is because the HTTP method does not like sending 2
                              // commands at once.
                              
                              wasSending = _sending;
                              _sending = false;
                        }
                  }
                  
                  // Make sure the dispatch isn't within the lock statement
                  ThreadUtility.SyncDispatch (new VoidDelegate (delegate
                  {
                        if (wasSending)
                              OnSendComplete (new EventArgs ());
                        
                        OnDataReceived (new ConnectionDataEventArgs (this, responseData, responseLength));
                  }));
                  
                  lock (_lock)
                  {
                        if ((!_sending) && (!_pollTimer.Enabled))
                              _pollTimer.Start ();
                  }
            }
            
            private void PollForData (object sender, ElapsedEventArgs args)
            {
                  Action = HTTPActions.Poll;
                  Send(new byte[0]);
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index