Ejemplo n.º 1
0
        /// <summary>
        /// Processes an IBB 'data' request.
        /// </summary>
        /// <param name="sessionId">The mandatory session id attribute of the 'data'
        /// element.</param>
        /// <param name="stanza">The IQ stanza containing the request.</param>
        /// <exception cref="ArgumentNullException">The sessionId parameter or the
        /// stanza parameter is null.</exception>
        /// <exception cref="ArgumentException">The IQ stanza is missing the
        /// mandatory 'data' element, or the specified session id is not associated
        /// with a file-stream.</exception>
        /// <exception cref="FormatException">The data contained in the 'data' element
        /// is not a valid BASE64-encoded string.</exception>
        /// <exception cref="IOException">The data could not be written to the
        /// file-stream. Consult the InnerException property of the IOException object
        /// to obtain the specific reason.</exception>
        void Data(string sessionId, Iq stanza)
        {
            sessionId.ThrowIfNull("sessionId");
            stanza.ThrowIfNull("stanza");
            var data = stanza.Data["data"];

            if (data == null)
            {
                throw new ArgumentException("Invalid stanza, missing data element.");
            }
            SISession session = siFileTransfer.GetSession(sessionId, stanza.From, im.Jid);

            if (session == null)
            {
                throw new ArgumentException("Invalid session-id.");
            }
            string base64 = data.InnerText;

            // Decode base64 string and write decoded binary data to file.
            byte[] bytes = Convert.FromBase64String(base64);
            try {
                session.Stream.Write(bytes, 0, bytes.Length);
            } catch (Exception e) {
                throw new IOException("The stream could not be written.", e);
            }
            // Update the byte count and raise the 'BytesTransferred' event.
            session.Count = session.Count + bytes.Length;
            BytesTransferred.Raise(this, new BytesTransferredEventArgs(session));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Performs the actual data-transfer implied by the specified
        /// SI session.
        /// </summary>
        /// <param name="session">The SI session whose data to transfer.</param>
        /// <exception cref="ArgumentNullException">The session parameter is
        /// null.</exception>
        /// <exception cref="NotSupportedException">The XMPP extension
        /// implementing this method is not supported by the intended recipient's
        /// XMPP client.</exception>
        /// <exception cref="XmppErrorException">The server or the XMPP entity
        /// with the specified JID returned an XMPP error code. Use the Error
        /// property of the XmppErrorException to obtain the specific error
        /// condition.</exception>
        /// <exception cref="XmppException">The server returned invalid data or
        /// another unspecified XMPP error occurred.</exception>
        public async Task Transfer(SISession session)
        {
            session.ThrowIfNull("session");
            // Open the negotiated IBB.
            await OpenStream(session.To, session.Sid);

            byte[] buf = new byte[blockSize];
            // 'seq' is defined as 16-bit unsigned short value that wraps around.
            ushort seq  = 0;
            long   left = session.Size;

            try
            {
                while (left > 0)
                {
                    int read = session.Stream.Read(buf, 0, blockSize);
                    left = left - read;
                    if (read <= 0)
                    {
                        break;
                    }
                    string b64  = Convert.ToBase64String(buf, 0, read);
                    var    data = Xml.Element("data", "http://jabber.org/protocol/ibb")
                                  .Attr("sid", session.Sid)
                                  .Attr("seq", seq.ToString())
                                  .Text(b64);
                    seq++;
                    Iq response = await im.IqRequest(IqType.Set, session.To, im.Jid, data);

                    if (response.Type == IqType.Error)
                    {
                        throw Util.ExceptionFromError(response);
                    }
                    session.Count = session.Count + read;
                    // Raise the 'BytesTransferred' event.
                    BytesTransferred.Raise(this, new BytesTransferredEventArgs(session));
                }
            }
            catch (ObjectDisposedException)
            {
                // This means the IO-stream has been disposed because we cancelled
                // the transfer. Just fall through.
            }
            catch
            {
                // The IQ response is of type 'error', the other site has cancelled
                // the transfer.
                TransferAborted.Raise(this, new TransferAbortedEventArgs(session));
                // Rethrow.
                throw;
            }
            finally
            {
                // Gracefully close the IBB.
                await CloseStream(session.To, session.Sid);
            }
        }
        /// <summary>
        /// Receives the actual data after SOCKS5 negotiation has been completed.
        /// </summary>
        /// <param name="stanza">The original requesting IQ stanza.</param>
        /// <param name="sid">The session-id associated with the
        /// data-transfer.</param>
        /// <param name="stream">The stream from which to read the incoming
        /// data.</param>
        /// <exception cref="XmppException">The specifid SID does not denote a
        /// valid SI session.</exception>
        private async Task ReceiveData(Iq stanza, string sid, Stream stream)
        {
            SISession session = siFileTransfer.GetSession(sid, stanza.From, stanza.To);

            if (session == null)
            {
                throw new XmppException("Invalid session-id: " + sid);
            }
            long left = session.Size;

            try
            {
                while (left > 0)
                {
                    byte[] buffer = new byte[4096];
                    int    read   = await stream.ReadAsync(buffer, 0, buffer.Length);

                    if (read <= 0)
                    {
                        break;
                    }
                    left = left - read;
                    await session.Stream.WriteAsync(buffer, 0, read);

                    // Update the byte count and raise the 'BytesTransferred' event.
                    session.Count = session.Count + read;
                    BytesTransferred.Raise(this, new BytesTransferredEventArgs(session));
                }
            }
            catch (ObjectDisposedException)
            {
                // This means the IO-stream has been disposed because we cancelled
                // the transfer. Just fall through.
            }
            finally
            {
                // Tear down the SI session.
                siFileTransfer.InvalidateSession(sid);
                // If not all bytes have been transferred, the data-transfer must have
                // been aborted prematurely.
                if (session.Count < session.Size)
                {
                    TransferAborted.Raise(this, new TransferAbortedEventArgs(session));
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Sends the actual data associated with the specified session over the
        /// specified stream.
        /// </summary>
        /// <param name="session">The SI session whose data to transfer.</param>
        /// <param name="stream">The (network) stream representing the connection
        /// to the client.</param>
        private void SendData(SISession session, Stream stream)
        {
            long left = session.Size;

            try
            {
                while (left > 0)
                {
                    byte[] buffer = new byte[4096];
                    int    read   = session.Stream.Read(buffer, 0,
                                                        (int)Math.Min(left, buffer.Length));
                    if (read > 0)
                    {
                        stream.Write(buffer, 0, read);
                    }
                    else
                    {
                        break;
                    }
                    left = left - read;
                    // Update the byte count and raise the 'BytesTransferred' event.
                    session.Count = session.Count + read;
                    BytesTransferred.Raise(this, new BytesTransferredEventArgs(session));
                }
            }
            catch (ObjectDisposedException)
            {
                // This means the IO-stream has been disposed because we cancelled
                // the transfer. Just fall through.
            }
            finally
            {
                // Tear down the SI session.
                siFileTransfer.InvalidateSession(session.Sid);
                // If not all bytes have been transferred, the data-transfer must have
                // been aborted prematurely.
                if (session.Count < session.Size)
                {
                    TransferAborted.Raise(this, new TransferAbortedEventArgs(session));
                }
            }
        }