ObexWebRequest.cs :  » Business-Application » 32feet.NET » InTheHand » Net » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Business Application » 32feet.NET 
32feet.NET » InTheHand » Net » ObexWebRequest.cs
// 32feet.NET - Personal Area Networking for .NET
//
// InTheHand.Net.ObexWebRequest
// 
// Copyright (c) 2003-2010 In The Hand Ltd, All rights reserved.
// This source code is licensed under the In The Hand Community License - see License.txt

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using InTheHand.Net;
using InTheHand.Net.Sockets;
using InTheHand.Net.Bluetooth;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace InTheHand.Net{
  /// <summary>
  /// Provides an OBEX implementation of the <see cref="WebRequest"/> class.
  /// </summary>
    /// -
    /// <remarks>
    /// <para>If you want to transfer an file or other object using the standard 
    /// service as used by Windows' Wireless Link / Bluetooth File Transfer Wizard, 
    /// Palm's Beam, Nokia's Send via Infrared, then use the OBEX protocol.  
    /// </para>
    /// <para>The PUT operation is supported, and there is new support for GET,
    /// (see the documentation at the <see cref="P:InTheHand.Net.ObexWebRequest.Method"/>
    /// property).
    /// Changing folders is not supported, nor is getting a folder listing.
    /// </para>
    /// <para>In the previous version there were some issue with handling file names 
    /// that include non-English characters, and connections 
    /// to some device types failed.  Also if the connection to the peer was lost
    /// then the request could hang reading forever.  See the release note and bugs
    /// database for more information.
    /// </para>
    /// </remarks>
    /// -
    /// <example>
    /// Use code like the following to send a file.
    /// <code>
    /// ' The host part of the URI is the device address, e.g. IrDAAddress.ToString(),
    /// ' and the file part is the OBEX object name.
    /// Dim uri As New Uri("obex://112233445566/HelloWorld.txt")
    /// Dim req As New ObexWebRequest(uri)
    /// req.ReadFile("Hello World.txt")
    /// Dim rsp As ObexWebResponse = CType(req.GetResponse(),ObexWebResponse)
    /// Console.WriteLine("Response Code: {0} (0x{0:X})", rsp.StatusCode)
    /// </code>
    /// Or, to send locally generated content use something like the following.
    /// <code>
    /// ' The host part of the URI is the device address, e.g. IrDAAddress.ToString(),
    /// ' and the file part is the OBEX object name.
    /// Dim uri As New Uri("obex://112233445566/HelloWorld2.txt")
    /// Dim req As New ObexWebRequest(uri)
    /// Using content As Stream = req.GetRequestStream()
    ///    ' Using a StreamWriter to write text to the stream...
    ///    Using wtr As New StreamWriter(content)
    ///       wtr.WriteLine("Hello World GetRequestStream")
    ///       wtr.WriteLine("Hello World GetRequestStream 2")
    ///       wtr.Flush()
    ///       ' Set the Length header value
    ///       req.ContentLength = content.Length
    ///    End Using
    ///    ' In this case closing the StreamWriter also closed the Stream, but ...
    /// End Using
    /// Dim rsp As ObexWebResponse = CType(req.GetResponse(),ObexWebResponse) 
    /// Console.WriteLine("Response Code: {0} (0x{0:X})", rsp.StatusCode)
    /// </code>
    /// See also the ObexPushApplication and ObexPushVB sample programs.
    /// </example>
  public class ObexWebRequest : WebRequest
  {
    private System.IO.MemoryStream requestStream = new System.IO.MemoryStream();
    

    private bool connected = false;
    private Socket s;
        private Stream ns;
        private Stream m_alreadyConnectedObexStream;
        BluetoothPublicFactory _btFactory;

    
    private ushort remoteMaxPacket = 0x400;
        private int connectionId = 0; // TODO -1 is the "not set" value for ConnectionId see OBEX13.pdf section 2.2.11, 0 is a valid value!

    #region Constructor
    static ObexWebRequest()
    {
            PlatformVerification.ThrowException();

      //register the obex schemes with the WebRequest base method
      ObexWebRequestCreate owrc = new ObexWebRequestCreate();
      WebRequest.RegisterPrefix("obex",owrc);
      WebRequest.RegisterPrefix("obex-push",owrc);
      WebRequest.RegisterPrefix("obex-ftp",owrc);
      WebRequest.RegisterPrefix("obex-sync",owrc);
    }

        internal ObexWebRequest(Uri requestUri, BluetoothPublicFactory factory)
            : this(requestUri)
        {
            Debug.Assert(factory != null, "NOT factory!=null");
            _btFactory = factory;
        }

        /// <overloads>
        /// Create a new Obex request with the specified <see cref="Uri"/>.
        /// </overloads>
        /// -
        /// <summary>
    /// Create a new Obex request with the specified <see cref="Uri"/>.
    /// </summary>
    /// <param name="requestUri"></param>
    /// <remarks>Uri must use one of the following schemes - obex, obex-push, obex-ftp, obex-sync.
    /// The host name must be the device address in short hex, or dotted hex notation - not the default representation using the colon separator</remarks>
    public ObexWebRequest(Uri requestUri)
    {
            if (requestUri == null) {
                throw new ArgumentNullException("requestUri");
            }
      if(!requestUri.Scheme.StartsWith("obex"))
      {
        throw new UriFormatException("Scheme type not supported by ObexWebRequest");
      }
      uri = requestUri;
    }

        /// <summary>
        /// [Advanced usage]
        /// Create a new Obex request with the specified <see cref="T:System.Uri"/> 
        /// and the open <see cref="T:System.IO.Stream"/> connection to an OBEX server.
        /// </summary>
        /// -
        /// <param name="requestUri">[Advanced usage]
        /// A url of the form 
        /// &#x201C;<i>scheme</i><c>:///</c><i>filename</i>&#x201D;, 
        /// &#x201C;e.g. <c>obex:///foo.txt</c>&#x201D;.
        /// That is the host part must be blank, 
        /// and the scheme and filename parts set as for the other constructor 
        /// <see cref="M:InTheHand.Net.ObexWebRequest.#ctor(System.Uri)"/>
        /// </param>
        /// <param name="stream">An instance of <see cref="T:System.IO.Stream"/>
        /// already connected to an OBEX server.
        /// </param>
        public ObexWebRequest(Uri requestUri, Stream stream)
            : this(requestUri)
        {
            if (requestUri == null) {
                throw new ArgumentNullException("requestUri");
            }
            if (requestUri.Host.Length != 0) {
                throw new ArgumentException("Uri must have no host part when passing in the connection stream.");
            }
            if (stream == null) {
                throw new ArgumentNullException("stream");
            }
            if (!(stream.CanRead && stream.CanWrite)) {
                throw new ArgumentException("Stream must be open for reading and writing.");
            }
            m_alreadyConnectedObexStream = stream;
        }
        #endregion

    #region Headers
        private WebHeaderCollection headers = new WebHeaderCollection();
    /// <summary>
        /// Specifies a collection of the name/value pairs that make up the OBEX headers.
    /// </summary>
    public override WebHeaderCollection Headers
    {
      get
      {
        return headers;
      }
      set
      {
        headers = value;
      }
    }
    #endregion

    #region Method
        private ObexMethod method = ObexMethod.Put;
    /// <summary>
    /// Gets or sets the method for the request.
    /// </summary>
    /// <remarks>
        /// <para>For Object Exchange the method code is mapped to the equivalent HTTP style method.
        /// For example "PUT", "GET" etc. "PUT" is the default value.
        /// There is new support for GET as of version 2.5.
        /// </para>
        /// <para>To use GET change the <c>Method</c> to "<c>GET</c>" and you must also use
        /// scheme "<c>obex-ftp</c>" in the URL instead of the usual "<c>obex</c>"
        /// -- unless you know that the default OBEX server you are connecting
        /// supports GET.
        /// </para>
        /// <para>For a PUT sample see the <see cref="T:InTheHand.Net.ObexWebRequest">class</see>
        /// documentation.  For GET, see below.
        /// </para>
        /// 
        /// <example>
        /// <code>
        /// ' The host part of the URI is the device address, e.g. IrDAAddress.ToString(),
        /// ' and the file part is the OBEX object name.
        /// Dim addr As String = "112233445566"
        /// Dim uri As New Uri("obex-ftp://" &amp; addr &amp; "/HelloWorld.txt")
        /// Dim req As New ObexWebRequest(uri)
        /// req.Method = "GET"
        /// Dim rsp As ObexWebResponse = CType(req.GetResponse(), ObexWebResponse)
        /// Console.WriteLine("Response Code: {0} (0x{0:X})", rsp.StatusCode)
        /// Using content As Stream = rsp.GetResponseStream()
        ///    ' Using a StreamReader to read text from the stream...
        ///    Using rdr As New StreamReader(content)
        ///       While True
        ///          Dim line As String = rdr.ReadLine()
        ///          If line Is Nothing Then Exit While
        ///          Console.WriteLine(line)
        ///       End While
        ///    End Using
        /// End Using
        /// </code>
        /// </example>
        /// </remarks>
    public override string Method
    {
      get
      {
        switch(method)
        {
          case ObexMethod.Put:
            return "PUT";
          case ObexMethod.Get:
            return "GET";
          default:
            return "";
        }
      }
      set
      {
                if (value == null)
                    throw new ArgumentNullException("value");
        switch(value.ToUpper())
        {
          case "PUT":
            method = ObexMethod.Put;
            break;
          case "GET":
            method = ObexMethod.Get;
            break;
          default:
            throw new InvalidOperationException("Method not supported");
        }
      }
    }
    #endregion

    #region Connect
    private ObexStatusCode Connect()
    {
      if (!connected)
      {
                if(ns == null)
        {
                    try
                    {
#if V2 && WinXP
                        bool isWidcomm = false;
#endif
                        if (uri.Host.Length == 0) {
                            System.Diagnostics.Debug.Assert(m_alreadyConnectedObexStream != null);
                            System.Diagnostics.Debug.Assert(m_alreadyConnectedObexStream.CanRead
                                && m_alreadyConnectedObexStream.CanWrite);
                            ns = m_alreadyConnectedObexStream;
                        } else {
                            BluetoothAddress ba;
                            IrDAAddress ia;
                            if(BluetoothAddress.TryParse(uri.Host,out ba))
                            {
                                // No good on Widcomm! s = new Socket(AddressFamily32.Bluetooth, SocketType.Stream, BluetoothProtocolType.RFComm);
                                BluetoothClient cli;
                                if (_btFactory == null) {
                                    cli = new BluetoothClient();
                                } else {
                                    cli = _btFactory.CreateBluetoothClient();
                                }
                                Guid serviceGuid;

                                switch (uri.Scheme)
                                {
                                    case "obex-ftp":
                                        serviceGuid = BluetoothService.ObexFileTransfer;
                                        break;
                                    //potential for other obex based profiles to be added
                                    case "obex-sync":
                                        serviceGuid = BluetoothService.IrMCSyncCommand;
                                        break;
                                    default:
                                        serviceGuid = BluetoothService.ObexObjectPush;
                                        break;
                                }


                                BluetoothEndPoint bep = new BluetoothEndPoint(ba, serviceGuid);
                                cli.Connect(bep);
                                ns = cli.GetStream();
                                try {
                                    Socket tmp = cli.Client; // Attempt to get the Socket
                                } catch (NotSupportedException) {
#if V2 && WinXP
                                    isWidcomm = true;
#endif
                                }
                            }
                            else if (IrDAAddress.TryParse(uri.Host, out ia))
                            {
                                //irda
                                s = new Socket(AddressFamily.Irda, SocketType.Stream, ProtocolType.IP);

                                IrDAEndPoint iep = new IrDAEndPoint(ia, "OBEX");

                                s.Connect(iep);
                            }
                            else
                            {
                                //assume a tcp host
                                s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                                IPAddress ipa;
                                try
                                {
                                    ipa = IPAddress.Parse(uri.Host);
                                }
                                catch
                                {
                                    // Compile-time: warning CS0618: 'System.Net.Dns.Resolve(string)' 
                                    //    is obsolete: 'Resolve is obsoleted for this type, 
                                    //    please use GetHostEntry instead. http://go.microsoft.com/fwlink/?linkid=14202'
                                    // However GetHostEntry isn't supported on NETCFv1,
                                    // so just keep it and disable the warning on
                                    // the other platforms.
#if V1
/*
#endif
#pragma warning disable 618
#if V1
*/
#endif
                                    ipa = System.Net.Dns.Resolve(uri.Host).AddressList[0];
#if V1
/*
#endif
#pragma warning restore 618
#if V1
*/
#endif
                                }

                                IPEndPoint ipep = new IPEndPoint(ipa, 650);

                                s.Connect(ipep);
                            }
                     
                            if (ns == null) // BluetoothClient used above
                                ns = new NetworkStream(s, true);

#if V2 && WinXP
                            try {
                                ns.ReadTimeout = timeout;
                                ns.WriteTimeout = timeout;
                            } catch (InvalidOperationException ex) {
                                Debug.Fail("** Failure setting Stream timeouts: {0}", ex.Message);
                                if (!isWidcomm)
                                    throw;
                            }
#endif
                        }

                        return Connect_Obex();
                    }
          finally
          {
            if (s != null && !s.Connected)
            {
              s = null;
            }
          }
        }
      }
      return (ObexStatusCode)0;
    }

        private ObexStatusCode Connect_Obex()
        {
            //do obex negotiation
            byte[] connectPacket;
            if (uri.Scheme == "obex-ftp") {
                connectPacket = new byte[] { 0x80, 0x00, 26, 0x10, 0x00, 0x20, 0x00, 0x46, 0x00, 19, 0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2, 0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 };
            } else {
                connectPacket = new byte[7] { 0x80, 0x00, 0x07, 0x10, 0x00, 0x20, 0x00 };
            }
            ns.Write(connectPacket, 0, connectPacket.Length);

            byte[] receivePacket = new byte[3];
            StreamReadBlockMust(ns, receivePacket, 0, 3);
            if (receivePacket[0] == (byte)(ObexStatusCode.OK | ObexStatusCode.Final)) {
                //get length
                short len = (short)(IPAddress.NetworkToHostOrder(BitConverter.ToInt16(receivePacket, 1)) - 3);

                byte[] receivePacket2 = new byte[3 + len];
                Buffer.BlockCopy(receivePacket, 0, receivePacket2, 0, 3);
                StreamReadBlockMust(ns, receivePacket2, 3, len);
                ObexParser.ParseHeaders(receivePacket2, true, ref remoteMaxPacket, null, headers);
                if (headers["CONNECTIONID"] != null) {
                    connectionId = int.Parse(headers["CONNECTIONID"]);
                }
                //ParseHeaders(receivePacket2, headers, null);
            }
            return (ObexStatusCode)receivePacket[0];
        }
    #endregion

    #region Content Type
    /// <summary>
    /// Gets or sets the value of the Type OBEX header.
    /// </summary>
    public override string ContentType
    {
      get
      {
        return headers["TYPE"];
      }
      set
      {
        headers["TYPE"] = value;
      }
    }

    #endregion

    #region Content Length
    /// <summary>
    /// Gets or sets the Length OBEX header.
    /// </summary>
    /// <remarks>This property is mandatory, if not set no data will be sent.
    /// If you use the <see cref="ReadFile"/> helper method this value is automatically populated with the size of the file that was read.</remarks>
    public override long ContentLength
    {
      get
      {
        string len = headers["LENGTH"];
        if(len == null || len == string.Empty)
        {
          return 0;
        }
        return long.Parse(len);
      }
      set
      {
        headers["LENGTH"] = value.ToString();
      }
    }
    #endregion

    #region Proxy
    /// <summary>
    /// Not Supported - do not use, this will throw an exception.
    /// </summary>
    public override IWebProxy Proxy
    {
      get
      {
        throw new NotSupportedException();
      }
      set
      {
        throw new NotSupportedException();
      }
    }
    #endregion

        #region Timeout
        private int timeout = 50000;
        /// <summary>
        /// Gets or sets the time-out value for the <see cref="GetResponse"/> method.
        /// </summary>
        /// <value>The number of milliseconds to wait before the request times out.
        /// The default is 50,000 milliseconds (50 seconds).
        /// A value of -1 or 0 represents no time-out.</value>
        public override int Timeout
        {
            get
            {
                return timeout;
            }
            set
            {
                if (value < -1)
                {
                    throw new ArgumentOutOfRangeException("value");
                }
                
                if (value == -1)
                {
                    timeout = 0;
                }
                else
                {
                    timeout = value;
                }
            }
        }
        #endregion

        #region Uri
        private Uri uri;
    /// <summary>
    /// Gets the original Uniform Resource Identifier (URI) of the request. 
    /// </summary>
    /// <remarks>For an ObexPush request the URI will use the "obex://" prefix, followed by the numerical device id in hex format.
    /// The path section of the URI represents the remote filename of the pushed object. Subfolders are not supported. Some devices may only support specific object types e.g. V-Card.</remarks>
    public override Uri RequestUri
    {
      get
      {
        return uri;
      }
    }
    #endregion

    #region DoPut
    private ObexStatusCode DoPut()
    {
      ObexStatusCode status = 0;

      byte[] buffer = new byte[remoteMaxPacket];

            string filename = uri.PathAndQuery;
            if (!uri.UserEscaped) {
#if !(WinCE && V1)
                // This is a NOP if there's no %xx encodings present.
                filename = Uri.UnescapeDataString(filename);
#else
        // HACK ObexWebRequest -- No Unescape method on NETCFv1!!
#endif
            }
            filename = filename.TrimStart(new char[] { '/' });
      int filenameLength = (filename.Length + 1) * 2;

      int packetLength = 3;
      buffer[0] = (byte)ObexMethod.Put;

            if (connectionId != 0) {
                buffer[packetLength] = (byte)ObexHeader.ConnectionID;
                byte[] raw = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(connectionId));
                raw.CopyTo(buffer, packetLength + 1);
                packetLength += 5;
            }

      buffer[packetLength] = (byte)ObexHeader.Name;
      BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)(filenameLength+3))).CopyTo(buffer, packetLength + 1);
      System.Text.Encoding.BigEndianUnicode.GetBytes(filename).CopyTo(buffer, packetLength + 3);
            packetLength += (3 + filenameLength);

      string contentType = headers["TYPE"];
      if(contentType!=null && contentType!="")
      {
                int contentTypeLength = (contentType.Length + 1);// *2;
        buffer[packetLength] = (byte)ObexHeader.Type;
        BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)(contentTypeLength+3))).CopyTo(buffer, packetLength+1);
        System.Text.Encoding.ASCII.GetBytes(contentType).CopyTo(buffer, packetLength+3);
        packetLength += (3+contentTypeLength);
      }
      if(this.ContentLength!=0)
      {
        buffer[packetLength] = (byte)ObexHeader.Length;
        BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Convert.ToInt32(this.ContentLength))).CopyTo(buffer, packetLength+1);
        packetLength += 5;
      }

      //write the final packet size
      BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)packetLength)).CopyTo(buffer, 1);

      //send packet with name header
            ns.Write(buffer, 0, packetLength);

      if (CheckResponse(ref status, false))
      {

        int totalBytes = 0;
        
        int thisRequest = 0;
        
        byte[] requestBuffer = requestStream.GetBuffer();

        //we really want the content length, but if not available send the whole buffer
        if(this.ContentLength > 0)
        {
          totalBytes = (int)this.ContentLength;
        }
        else
        {
          totalBytes = requestBuffer.Length;
        }

        MemoryStream readBuffer = new MemoryStream(requestBuffer);

        while (totalBytes > 0)
        {
          if(totalBytes <= (remoteMaxPacket - 6))
          {
            thisRequest = totalBytes;

            totalBytes = 0;
            buffer[0] = (byte)ObexMethod.PutFinal;
            buffer[3] = (byte)ObexHeader.EndOfBody;

          }
          else
          {
            thisRequest = remoteMaxPacket - 6;
            //decrement byte count
            totalBytes -= thisRequest;
            buffer[0] = (byte)ObexMethod.Put;
            buffer[3] = (byte)ObexHeader.Body;
          }

          int readBytes = readBuffer.Read(buffer, 6, thisRequest);

                    // Before we use the unchecked arithmetic below, check that our
                    // maths hasn't failed and we're writing too big length headers.
                    ushort check = (ushort)readBytes;
          BitConverter.GetBytes(IPAddress.HostToNetworkOrder(unchecked((short)(readBytes+3)))).CopyTo(buffer, 4);
      
          BitConverter.GetBytes(IPAddress.HostToNetworkOrder(unchecked((short)(readBytes + 6)))).CopyTo(buffer, 1);
          
                    ns.Write(buffer, 0, readBytes + 6);

          if (!CheckResponse(ref status, false))
          {
            return status;
          }
        }
      }

      return status;

    }
    #endregion

    #region DoGet
    private ObexStatusCode DoGet(MemoryStream ms, WebHeaderCollection headers)
    {
            ObexStatusCode sc;
            const byte ObexMethod_GetFinal = (byte)ObexMethod.Get | 0x80;
            // Status codes are always final.
            const ObexStatusCode ObexStatus_OK = ObexStatusCode.OK | ObexStatusCode.Final;
            const ObexStatusCode ObexStatus_Continue = ObexStatusCode.Continue | ObexStatusCode.Final;

      byte[] buffer = new byte[remoteMaxPacket];

            buffer[0] = ObexMethod_GetFinal;
      int bufferlen = 3;

      //build the packet based on the available headers

      //connectionid (must be first header)
      if(connectionId != 0)
      {
                buffer[bufferlen] = (byte)ObexHeader.ConnectionID;
        BitConverter.GetBytes(IPAddress.HostToNetworkOrder(connectionId)).CopyTo(buffer, bufferlen+1);
        
        bufferlen += 5;
      }

            //name
      string filename = uri.PathAndQuery.TrimStart(new char[]{'/'});
      if(filename.Length>0)
      {
        const int NullTerminatorLen = 2;
        int filenameLength = filename.Length * 2 + NullTerminatorLen;
        buffer[bufferlen] = (byte)ObexHeader.Name;
        int filenameheaderlen = IPAddress.HostToNetworkOrder((short)(filenameLength + 3));
        BitConverter.GetBytes(filenameheaderlen).CopyTo(buffer, bufferlen+1);
        System.Text.Encoding.BigEndianUnicode.GetBytes(filename).CopyTo(buffer, bufferlen+3);

        bufferlen += filenameLength+3;
      }

      //content type
      string type = this.headers["TYPE"];
      if (type != null)
      {
        buffer[bufferlen] = (byte)ObexHeader.Type;
        int typeheaderlen = IPAddress.HostToNetworkOrder((short)((type.Length + 1) + 3));
        BitConverter.GetBytes(typeheaderlen).CopyTo(buffer, bufferlen+1);
        System.Text.Encoding.ASCII.GetBytes(type).CopyTo(buffer, bufferlen+3);

        bufferlen += type.Length+4;
      }
      
      //write total packet size
      BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)bufferlen)).CopyTo(buffer, 1);
      
      //send packet with name header
            //then loop until end
            do
            {
                // Send then Receive
                ns.Write(buffer, 0, bufferlen);
                //
                StreamReadBlockMust(ns, buffer, 0, 3);
                int bytesread = 3;
                //get code
                sc = (ObexStatusCode)buffer[0];
                //get length
                short len = (short)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, 1));
                Debug.Assert(len > 0, "not got len!");
                //read all of packet
                StreamReadBlockMust(ns, buffer, bytesread, len - bytesread);
                ObexParser.ParseHeaders(buffer, false, ref remoteMaxPacket, ms, headers);

                //prepare the next request
                buffer[0] = ObexMethod_GetFinal;
                BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)3)).CopyTo(buffer, 1);
                bufferlen = 3;
            }
            while (sc == ObexStatus_Continue);

            if (sc != ObexStatus_OK) {
                throw new WebException("GET failed with code: " + sc, WebExceptionStatus.ProtocolError);
            }
            return sc;
    }
    #endregion

    #region Check Response
    private bool CheckResponse(ref ObexStatusCode status, bool isConnectResponse)
    {
            if (isConnectResponse)
                throw new ArgumentException("CheckResponse does not know how to parse the connect response");
      byte[] receiveBuffer = new byte[3];
            StreamReadBlockMust(ns, receiveBuffer, 0, receiveBuffer.Length);

      status = (ObexStatusCode)receiveBuffer[0];

      switch(status)
      {
                case ObexStatusCode.Final | ObexStatusCode.OK:
                case ObexStatusCode.OK:
        case ObexStatusCode.Final | ObexStatusCode.Continue:
        case ObexStatusCode.Continue:
          //get length
          short len = (short)(IPAddress.NetworkToHostOrder(BitConverter.ToInt16(receiveBuffer, 1)) - 3);
                    Debug.Assert(len >= 0, "not got len!");

          if (len > 0)
          {
            byte[] receivePacket2 = new byte[len];
                        StreamReadBlockMust(ns, receivePacket2, 0, len);
                        if (len == 5 && ((ObexHeader)receivePacket2[0] == ObexHeader.ConnectionID)) {
                            // ignore ConnectionId
                        } else {
                            Debug.Fail("unused headers...");
                        }
          }

          return true;
        default:
          return false;
      }
      
      //handle errors please!
    }
    #endregion

    #region Disconnect
    private void Disconnect()
    {
            if (ns != null)
            {
                ObexStatusCode status = 0;

                short disconnectPacketSize = 3;
                byte[] disconnectPacket = new byte[8];
                disconnectPacket[0] = (byte)ObexMethod.Disconnect;

                //add connectionid header
                if (connectionId != 0)
                {
                    disconnectPacket[3] = (byte)ObexHeader.ConnectionID;
                    BitConverter.GetBytes(IPAddress.HostToNetworkOrder(connectionId)).CopyTo(disconnectPacket, 4);
                    disconnectPacketSize += 5;
                }

                //set packet size
                BitConverter.GetBytes(IPAddress.HostToNetworkOrder(disconnectPacketSize)).CopyTo(disconnectPacket, 1);

                ns.Write(disconnectPacket, 0, disconnectPacketSize);

                CheckResponse(ref status, false);

                ns.Close();
            }
    }
    #endregion

    #region Get Request Stream
    /// <summary>
    /// Gets a <see cref="System.IO.Stream"/> object to use to write request data.
    /// </summary>
    /// <returns></returns>
    public override System.IO.Stream GetRequestStream()
    {
      return requestStream;
    }
    #endregion

    #region Read File
    /// <summary>
    /// Reads the contents of the specified file to the request stream.
    /// </summary>
    /// <param name="fileName">The filename (including the path) from which to read.</param>
    /// <remarks>Provides an easy equivalent to manually writing the file contents to the request stream.</remarks>
    public void ReadFile(string fileName)
    {
      FileStream fs = File.OpenRead(fileName);
      long len = 0;
      //read in 1k chunks
      byte[] buffer = new byte[1024];
      int readBytes;
      do
      {
        readBytes = fs.Read(buffer, 0, buffer.Length);
        len += readBytes;
        requestStream.Write(buffer, 0, readBytes);
      }while (readBytes > 0);

      fs.Close();
      requestStream.Close();

      //write content length
      this.ContentLength = len;
    }
    #endregion

    #region Get Response
    /// <summary>
    /// Returns the OBEX server response.
    /// </summary>
        /// -
        /// <returns>An <see cref="T:InTheHand.Net.ObexWebResponse"/>.</returns>
        /// -
        /// <exception cref="System.Net.WebException">
        /// An error occurred, with the error that occured being stored in the 
        /// <see cref="P:System.Exception.InnerException"/> property.  If the error 
        /// occurred in the connect phase then the <see cref="P:System.Net.WebException.Status"/>
        /// property will have value <see cref="F:System.Net.WebExceptionStatus.ConnectFailure"/>,
        /// and in the operation phase on the desktop CLR it will have value
        /// <see cref="F:System.Net.WebExceptionStatus.UnknownError"/>
        /// </exception>
        public override WebResponse GetResponse()
        {
            ObexStatusCode status;
            MemoryStream ms = new MemoryStream();
            WebHeaderCollection responseHeaders = new WebHeaderCollection();
            //try connecting if not already
            try
            {
                status = Connect();
            }
            catch (Exception se)
            {
                throw new WebException("Connect failed.", se, WebExceptionStatus.ConnectFailure, null);
            }

            try
            {
                switch (this.method)
                {
                    case ObexMethod.Put:
                    case ObexMethod.PutFinal:
                        status = DoPut();
                        break;
                    case ObexMethod.Get:
                        status = DoGet(ms, responseHeaders);
                        ms.Seek(0, SeekOrigin.Begin);
                        break;
                    default:
                        throw new WebException("Unsupported Method.", new InvalidOperationException(), WebExceptionStatus.ProtocolError, null);
                }
                Disconnect();
            } catch (WebException) {
                throw; // Don't need to wrap these.
            } catch (Exception ex)
            {
                
                    throw new WebException("Operation failed.", ex
#if ! WinCE
                        // UnknownError member not supported on CE unfortunately.
                        , WebExceptionStatus.UnknownError, null
#endif
);

            }
            finally {
                if (ns != null) {
                    ns.Close();
                }
            }

            return new ObexWebResponse(ms, responseHeaders, status);
        }
    #endregion
    
        /// <summary>
        /// A wrapper for Stream.Read that blocks until the requested number of bytes
        /// have been read, and throw an exception if the stream is closed before that occurs.
        /// </summary>
        private static void StreamReadBlockMust(Stream stream, byte[] buffer, int offset, int size)
        {
            int numRead = StreamReadBlock(stream, buffer, offset, size);
            System.Diagnostics.Debug.Assert(numRead <= size);
            if (numRead < size) {
                throw new EndOfStreamException("Connection closed whilst reading an OBEX packet.");
            }
        }

        /// <summary>
        /// A wrapper for Stream.Read that blocks until the requested number of bytes
        /// have been read or the end of the Stream has been reached.
        /// Returns the number of bytes read.
        /// </summary>
        private static int StreamReadBlock(Stream stream, byte[] buffer, int offset, int size)
        {
            int numRead = 0;
            while (size - numRead > 0) {
                int curCount = stream.Read(buffer, offset + numRead, size - numRead);
                if (curCount == 0) { // EoF
                    break;
                }
                numRead += curCount;
            }
            System.Diagnostics.Debug.Assert(numRead <= size);
            return numRead;
        }

        /// <summary>
        /// Begins a request for a OBEX server response.
        /// </summary>
        /// -
        /// <returns>
        /// An IAsyncResult that references the asynchronous request for a response.
        /// </returns>
        public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
        {
            AsyncResult<WebResponse> ar = new AsyncResult<WebResponse>(callback, state);
            System.Threading.ThreadPool.QueueUserWorkItem(HackApmRunner_GetResponse, ar);
            return ar;
        }

        [SuppressMessage("Microsoft.Design", "CA1031", Justification = "Is rethrown by APM caller.")]
        void HackApmRunner_GetResponse(object state)
        {
            AsyncResult<WebResponse> ar = (AsyncResult<WebResponse>)state;
            try {
                WebResponse rsp = this.GetResponse();
                ar.SetAsCompleted(rsp, false);
            } catch (Exception ex) {
                ar.SetAsCompleted(ex, false);
            }
        }

        /// <summary>
        /// Begins a request for a OBEX server response.
        /// </summary>
        /// -
        /// <returns>An <see cref="T:InTheHand.Net.ObexWebResponse"/>.</returns>
        /// -
        /// <exception cref="System.Net.WebException">
        /// An error occurred, with the error that occured being stored in the 
        /// <see cref="P:System.Exception.InnerException"/> property.  If the error 
        /// occurred in the connect phase then the <see cref="P:System.Net.WebException.Status"/>
        /// property will have value <see cref="F:System.Net.WebExceptionStatus.ConnectFailure"/>,
        /// and in the operation phase on the desktop CLR it will have value
        /// <see cref="F:System.Net.WebExceptionStatus.UnknownError"/>
        /// </exception>
        public override WebResponse EndGetResponse(IAsyncResult asyncResult)
        {
            AsyncResult<WebResponse> ar = (AsyncResult<WebResponse>)asyncResult;
            return ar.EndInvoke();
        }

  }//class
}


www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.