示例#1
0
        public void Transfer(SISession session)
        {
            IEnumerable <Streamhost> source = null;

            if (this.ProxyAllowed)
            {
                try
                {
                    source = this.GetProxyList();
                }
                catch
                {
                }
            }
            try
            {
                if ((source != null) && (source.Count <Streamhost>() > 0))
                {
                    this.MediatedTransfer(session, source);
                }
                else
                {
                    this.DirectTransfer(session);
                }
            }
            catch (Exception exception)
            {
                CommonConfig.Logger.WriteError("socket5传输过程出现异常!", exception);
                this.TransferAborted.Raise <TransferAbortedEventArgs>(this, new TransferAbortedEventArgs(session));
                this.siFileTransfer.InvalidateSession(session.Sid);
            }
        }
示例#2
0
        private void Data(string sessionId, Iq stanza)
        {
            sessionId.ThrowIfNull <string>("sessionId");
            stanza.ThrowIfNull <Iq>("stanza");
            XmlElement element = stanza.Data["data"];

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

            if (session == null)
            {
                throw new ArgumentException("Invalid session-id.");
            }
            byte[] buffer = Convert.FromBase64String(element.InnerText);
            try
            {
                session.Stream.Write(buffer, 0, buffer.Length);
            }
            catch (Exception exception)
            {
                throw new IOException("The stream could not be written.", exception);
            }
            session.Count += buffer.Length;
            this.BytesTransferred.Raise <BytesTransferredEventArgs>(this, new BytesTransferredEventArgs(session));
        }
示例#3
0
        /// <summary>
        /// Performs a mediated transfer, meaning we send the data over a proxy server.
        /// </summary>
        /// <param name="session">The SI session whose data to transfer.</param>
        /// <param name="proxies"></param>
        /// <exception cref="Socks5Exception">The SOCKS5 connection to the designated
        /// proxy server could not be established.</exception>
        /// <exception cref="XmppErrorException">The server 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>
        void MediatedTransfer(SISession session, IEnumerable <Streamhost> proxies)
        {
            var proxy = NegotiateProxy(session, proxies);

            // Connect to the designated proxy.
            using (var client = new Socks5Client(proxy.Host, proxy.Port)) {
                // Send the SOCKS5 Connect command.
                string     hostname = Sha1(session.Sid + session.From + session.To);
                SocksReply reply    = client.Request(SocksCommand.Connect, hostname, 0);
                if (reply.Status != ReplyStatus.Succeeded)
                {
                    throw new Socks5Exception("SOCKS5 Connect request failed.");
                }
                // Activate the bytetream.
                var xml = Xml.Element("query", "http://jabber.org/protocol/bytestreams")
                          .Attr("sid", session.Sid).Child(
                    Xml.Element("activate").Text(session.To.ToString()));
                Iq iq = im.IqRequest(IqType.Set, proxy.Jid, im.Jid, xml);
                if (iq.Type == IqType.Error)
                {
                    throw Util.ExceptionFromError(iq, "Could not activate the bytestream.");
                }
                // Finally, go ahead and send the data to the proxy.
                SendData(session, client.GetStream());
            }
        }
示例#4
0
        /// <summary>
        /// Waits for a client connection to be made and subsequently verifies it.
        /// </summary>
        /// <param name="session">The SI session whose data to transfer.</param>
        /// <param name="server">The instance of the SOCKS5 server to accept
        /// client connections on.</param>
        /// <param name="timeout">The number of milliseconds to wait for a client
        /// connection before returning to the caller, or -1 to wait
        /// indefinitely.</param>
        /// <exception cref="SocketException">An error occurred when accessing the
        /// underlying socket of the SOCKS5 server instance.</exception>
        /// <exception cref="Socks5Exception">The SOCKS5 negotiation with the client
        /// failed.</exception>
        /// <exception cref="TimeoutException">A timeout was specified and it
        /// expired.</exception>
        /// <exception cref="IOException">The stream could not be read, or the
        /// operation timed out.</exception>
        void AcceptClientConnection(SISession session, Socks5Server server,
                                    int timeout = -1)
        {
            var request = server.Accept(timeout);

            if (request.Command != SocksCommand.Connect)
            {
                throw new Socks5Exception("Unexpected SOCKS5 command: " +
                                          request.Command);
            }
            if (request.ATyp != ATyp.Domain)
            {
                throw new Socks5Exception("Unexpected ATyp: " + request.ATyp);
            }
            string hash = (string)request.Destination;
            // Calculate the SHA-1 hash and compare it with the one in the request.
            string calculated = Sha1(session.Sid + im.Jid + session.To);

            if (calculated != hash)
            {
                throw new Socks5Exception("Hostname hash mismatch.");
            }
            // We're good to go.
            server.Reply(ReplyStatus.Succeeded, hash, request.Port);
        }
示例#5
0
        private Streamhost NegotiateProxy(SISession session, IEnumerable <Streamhost> proxies)
        {
            XmlElement e = Xml.Element("query", "http://jabber.org/protocol/bytestreams").Attr("sid", session.Sid);

            foreach (Streamhost streamhost in proxies)
            {
                e.Child(Xml.Element("streamhost", null).Attr("jid", streamhost.Jid.ToString()).Attr("host", streamhost.Host).Attr("port", streamhost.Port.ToString()));
            }
            Iq errorIq = base.im.IqRequest(IqType.Set, session.To, base.im.Jid, e, null, -1, "");

            if (errorIq.Type == IqType.Error)
            {
                throw Util.ExceptionFromError(errorIq, "The SOCKS5 negotiation failed.");
            }
            XmlElement element2 = errorIq.Data["query"];

            if ((element2 == null) || (element2.NamespaceURI != "http://jabber.org/protocol/bytestreams"))
            {
                throw new XmppException("Erroneous response.");
            }
            XmlElement element3 = element2["streamhost-used"];

            if (element3 == null)
            {
                throw new XmppException("Missing streamhost-used element.");
            }
            string     proxyJid    = element3.GetAttribute("jid");
            Streamhost streamhost2 = proxies.FirstOrDefault <Streamhost>(proxy => proxy.Jid == proxyJid);

            if (streamhost2 == null)
            {
                throw new XmppException("Invalid streamhost JID.");
            }
            return(streamhost2);
        }
示例#6
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));
        }
示例#7
0
        public void CancelFileTransfer(FileTransfer transfer)
        {
            transfer.ThrowIfNull <FileTransfer>("transfer");
            SISession session = this.GetSession(transfer.SessionId, transfer.From, transfer.To);

            if (session == null)
            {
                throw new ArgumentException("The specified transfer instance does not represent an active data-transfer operation.");
            }
            session.Extension.CancelTransfer(session);
        }
示例#8
0
        private void Close(string sessionId, Iq stanza)
        {
            sessionId.ThrowIfNull <string>("sessionId");
            stanza.ThrowIfNull <Iq>("stanza");
            SISession session = this.siFileTransfer.GetSession(sessionId, stanza.From, stanza.To);

            if (session != null)
            {
                this.siFileTransfer.InvalidateSession(sessionId);
                if (session.Count < session.Size)
                {
                    this.TransferAborted.Raise <TransferAbortedEventArgs>(this, new TransferAbortedEventArgs(session));
                }
            }
        }
示例#9
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 void Transfer(SISession session)
        {
            session.ThrowIfNull("session");
            // Open the negotiated IBB.
            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 = 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.
                CloseStream(session.To, session.Sid);
            }
        }
示例#10
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 void Transfer(SISession session)
        {
            IEnumerable <Streamhost> proxies = null;

            // Determine if this is going to be a direct or a mediated transfer.
            if (ProxyAllowed)
            {
                try {
                    var externalAddresses = GetExternalAddresses();
                    // If all of our external addresses are behind NATs, we may need a proxy.
                    bool behindNAT = externalAddresses.All(addr => BehindNAT(addr));
                    if (behindNAT)
                    {
                        // Look for user-defined proxies first.
                        if (Proxies.Count > 0)
                        {
                            proxies = Proxies;
                        }
                        else
                        {
                            // Otherwise query XMPP server for a list of proxies.
                            proxies = GetProxyList();
                        }
                    }
                } catch {
                    // Retrieving the external addresses may fail as well as querying
                    // the XMPP server for proxies. In these cases, we at least try
                    // with a direct transfer.
                }
            }

            try {
                if (proxies != null && proxies.Count() > 0)
                {
                    MediatedTransfer(session, proxies);
                }
                else
                {
                    DirectTransfer(session);
                }
            } catch (Exception) {
                // Raise the 'TransferAborted' event.
                TransferAborted.Raise(this, new TransferAbortedEventArgs(session));
                // Invalidate the session.
                siFileTransfer.InvalidateSession(session.Sid);
            }
        }
示例#11
0
        /// <summary>
        /// Negotiates with the target which of the specified SOCKS5 proxies to use.
        /// </summary>
        /// <param name="session">The SI session whose data to transfer.</param>
        /// <param name="proxies">An enumerable collection of SOCKS5 proxy servers
        /// to advertise to the target.</param>
        /// <returns>The proxy server to use for the data transfer.</returns>
        /// <exception cref="XmppErrorException">The server 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>
        Streamhost NegotiateProxy(SISession session, IEnumerable <Streamhost> proxies)
        {
            // Compile XML containing our list of proxy servers.
            var xml = Xml.Element("query", "http://jabber.org/protocol/bytestreams")
                      .Attr("sid", session.Sid);

            foreach (var proxy in proxies)
            {
                xml.Child(Xml.Element("streamhost")
                          .Attr("jid", proxy.Jid.ToString())
                          .Attr("host", proxy.Host)
                          .Attr("port", proxy.Port.ToString()));
            }
            // Wait for the other site to tell us which proxy server it selected.
            var iq = im.IqRequest(IqType.Set, session.To, im.Jid, xml);

            if (iq.Type == IqType.Error)
            {
                throw Util.ExceptionFromError(iq, "The SOCKS5 negotiation failed.");
            }
            var query = iq.Data["query"];

            if (query == null || query.NamespaceURI !=
                "http://jabber.org/protocol/bytestreams")
            {
                throw new XmppException("Erroneous response.");
            }
            if (query.GetAttribute("sid") != session.Sid)
            {
                throw new XmppException("Invalid session identifier.");
            }
            var used = query["streamhost-used"];

            if (used == null)
            {
                throw new XmppException("Missing streamhost-used element.");
            }
            var proxyJid   = used.GetAttribute("jid");
            var streamhost = proxies.FirstOrDefault(proxy => proxy.Jid == proxyJid);

            if (streamhost == null)
            {
                throw new XmppException("Invalid streamhost JID.");
            }
            return(streamhost);
        }
示例#12
0
        public void Transfer(SISession session)
        {
            session.ThrowIfNull <SISession>("session");
            this.OpenStream(session.To, session.Sid);
            byte[] buffer = new byte[0x1000];
            ushort num    = 0;
            long   size   = session.Size;

            try
            {
                while (size > 0L)
                {
                    int length = session.Stream.Read(buffer, 0, 0x1000);
                    size -= length;
                    if (length <= 0)
                    {
                        return;
                    }
                    string     text = Convert.ToBase64String(buffer, 0, length);
                    XmlElement data = Xml.Element("data", "http://jabber.org/protocol/ibb").Attr("sid", session.Sid).Attr("seq", num.ToString()).Text(text);
                    num = (ushort)(num + 1);
                    Iq errorIq = base.im.IqRequest(IqType.Set, session.To, base.im.Jid, data, null, -1, "");
                    if (errorIq.Type == IqType.Error)
                    {
                        throw Util.ExceptionFromError(errorIq, null);
                    }
                    session.Count += length;
                    this.BytesTransferred.Raise <BytesTransferredEventArgs>(this, new BytesTransferredEventArgs(session));
                }
            }
            catch (ObjectDisposedException exception)
            {
                CommonConfig.Logger.WriteError(exception);
            }
            catch (Exception exception2)
            {
                CommonConfig.Logger.WriteError(exception2);
                this.TransferAborted.Raise <TransferAbortedEventArgs>(this, new TransferAbortedEventArgs(session));
                throw;
            }
            finally
            {
                this.CloseStream(session.To, session.Sid);
            }
        }
示例#13
0
        /// <summary>
        /// Processes an IBB 'close' request.
        /// </summary>
        /// <param name="sessionId">The mandatory session id attribute of the 'close'
        /// 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>
        void Close(string sessionId, Iq stanza)
        {
            sessionId.ThrowIfNull("sessionId");
            stanza.ThrowIfNull("stanza");
            SISession session = siFileTransfer.GetSession(sessionId,
                                                          stanza.From, stanza.To);

            // We don't allow the other site to close a session that we opened.
            if (session != null)
            {
                siFileTransfer.InvalidateSession(sessionId);
                // Had all bytes been received when we got the 'close' request?
                // Otherwise, the other site cancelled the transfer prematurely.
                if (session.Count < session.Size)
                {
                    TransferAborted.Raise(this, new TransferAbortedEventArgs(session));
                }
            }
        }
示例#14
0
        private void AcceptClientConnection(SISession session, Socks5Server server, int timeout = -1)
        {
            SocksRequest request = server.Accept(timeout);

            if (request.Command != SocksCommand.Connect)
            {
                throw new Socks5Exception("Unexpected SOCKS5 command: " + request.Command);
            }
            if (request.ATyp != ATyp.Domain)
            {
                throw new Socks5Exception("Unexpected ATyp: " + request.ATyp);
            }
            string destination = (string)request.Destination;

            if (this.Sha1(session.Sid + base.im.Jid + session.To) != destination)
            {
                throw new Socks5Exception("Hostname hash mismatch.");
            }
            server.Reply(ReplyStatus.Succeeded, destination, request.Port);
        }
示例#15
0
        private void OnInitiationResult(InitiationResult result, Jid to, string name, Stream stream, long size, string description, Action <bool, FileTransfer> cb)
        {
            Exception    exception;
            FileTransfer transfer = new FileTransfer(base.im.Jid, to, name, size, null, description, 0L);

            try
            {
                IDataStream extension = base.im.GetExtension(result.Method) as IDataStream;
                SISession   session   = new SISession(result.SessionId, stream, size, false, base.im.Jid, to, extension);
                this.siSessions.TryAdd(result.SessionId, session);
                this.metaData.TryAdd(result.SessionId, new FileMetaData(name, description));
                if (cb != null)
                {
                    cb(true, transfer);
                }
                try
                {
                    CommonConfig.Logger.WriteInfo("开始执行Transfer文件传输方法");
                    extension.Transfer(session);
                }
                catch (Exception exception1)
                {
                    exception = exception1;
                    CommonConfig.Logger.WriteError("发送文件过程出错:" + exception.ToString(), exception);
                }
            }
            catch (Exception exception2)
            {
                exception = exception2;
                if (stream != null)
                {
                    stream.Dispose();
                }
                CommonConfig.Logger.WriteError("OnInitiationResult发送文件异常", exception);
                if (cb != null)
                {
                    cb(false, transfer);
                }
            }
        }
示例#16
0
        private void MediatedTransfer(SISession session, IEnumerable <Streamhost> proxies)
        {
            Streamhost streamhost = this.NegotiateProxy(session, proxies);

            using (Socks5Client client = new Socks5Client(streamhost.Host, streamhost.Port, null, null))
            {
                string domain = this.Sha1(session.Sid + session.From + session.To);
                if (client.Request(SocksCommand.Connect, domain, 0).Status != ReplyStatus.Succeeded)
                {
                    CommonConfig.Logger.WriteInfo("SOCKS5 Connect request failed.");
                    throw new Socks5Exception("SOCKS5 Connect request failed.");
                }
                CommonConfig.Logger.WriteInfo("SOCKS5 Connect successed.");
                XmlElement data    = Xml.Element("query", "http://jabber.org/protocol/bytestreams").Attr("sid", session.Sid).Child(Xml.Element("activate", null).Text(session.To.ToString()));
                Iq         errorIq = base.im.IqRequest(IqType.Set, streamhost.Jid, base.im.Jid, data, null, -1, "");
                if (errorIq.Type == IqType.Error)
                {
                    throw Util.ExceptionFromError(errorIq, "Could not activate the bytestream.");
                }
                this.SendData(session, client.GetStream());
            }
        }
示例#17
0
        /// <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>
        void 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   = stream.Read(buffer, 0, buffer.Length);
                    if (read <= 0)
                    {
                        break;
                    }
                    left = left - read;
                    session.Stream.Write(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));
                }
            }
        }
示例#18
0
        private void ReceiveData(Iq stanza, string sid, Stream stream)
        {
            SISession session = this.siFileTransfer.GetSession(sid, stanza.From, stanza.To);

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

            try
            {
                while (size > 0L)
                {
                    byte[] buffer = new byte[0x1000];
                    int    count  = stream.Read(buffer, 0, buffer.Length);
                    if (count <= 0)
                    {
                        return;
                    }
                    size -= count;
                    session.Stream.Write(buffer, 0, count);
                    session.Count += count;
                    this.BytesTransferred.Raise <BytesTransferredEventArgs>(this, new BytesTransferredEventArgs(session));
                }
            }
            catch (ObjectDisposedException)
            {
            }
            finally
            {
                this.siFileTransfer.InvalidateSession(sid);
                if (session.Count < session.Size)
                {
                    this.TransferAborted.Raise <TransferAbortedEventArgs>(this, new TransferAbortedEventArgs(session));
                }
            }
        }
示例#19
0
        private void SendData(SISession session, Stream stream)
        {
            long size = session.Size;

            try
            {
                CommonConfig.Logger.WriteInfo("开始通过socket5方式传输流,大小为:" + size);
                while (size > 0L)
                {
                    byte[] buffer = new byte[0x1000];
                    int    count  = session.Stream.Read(buffer, 0, (int)Math.Min(size, (long)buffer.Length));
                    if (count > 0)
                    {
                        stream.Write(buffer, 0, count);
                        CommonConfig.Logger.WriteInfo("socket5传read=" + count.ToString());
                    }
                    else
                    {
                        break;
                    }
                    size          -= count;
                    session.Count += count;
                    this.BytesTransferred.Raise <BytesTransferredEventArgs>(this, new BytesTransferredEventArgs(session));
                }
                CommonConfig.Logger.WriteInfo("传输完成,socket5方式共:" + session.Size);
            }
            catch (ObjectDisposedException)
            {
            }
            finally
            {
                this.siFileTransfer.InvalidateSession(session.Sid);
                if (session.Count < session.Size)
                {
                    this.TransferAborted.Raise <TransferAbortedEventArgs>(this, new TransferAbortedEventArgs(session));
                }
            }
        }
示例#20
0
 /// <summary>
 /// Invoked whenever a 'Stream Initiation' request for file transfers
 /// is received.
 /// </summary>
 /// <param name="from">The JID of the XMPP entity that wishes to initiate
 /// the data-stream.</param>
 /// <param name="si">The 'si' element of the request.</param>
 /// <returns>The response to the SI request or an error element to include
 /// in the IQ response.</returns>
 XmlElement OnStreamInitiationRequest(Jid from, XmlElement si)
 {
     try {
         string method = SelectStreamMethod(si["feature"]);
         // If the session-id is already in use, we cannot process the request.
         string sid = si.GetAttribute("id");
         if (String.IsNullOrEmpty(sid) || siSessions.ContainsKey(sid))
         {
             return(new XmppError(ErrorType.Cancel, ErrorCondition.Conflict).Data);
         }
         // Extract file information and hand to user.
         var    file           = si["file"];
         string desc           = file["desc"] != null ? file["desc"].InnerText : null,
                name           = file.GetAttribute("name");
         int          size     = Int32.Parse(file.GetAttribute("size"));
         FileTransfer transfer = new FileTransfer(from, im.Jid, name, size,
                                                  sid, desc);
         string savePath = TransferRequest.Invoke(transfer);
         // User has rejected the request.
         if (savePath == null)
         {
             return(new XmppError(ErrorType.Cancel, ErrorCondition.NotAcceptable).Data);
         }
         // Create an SI session instance.
         SISession session = new SISession(sid, File.OpenWrite(savePath),
                                           size, true, from, im.Jid, im.GetExtension(method) as IDataStream);
         siSessions.TryAdd(sid, session);
         // Store the file's meta data.
         metaData.TryAdd(sid, new FileMetaData(name, desc));
         // Construct and return the negotiation result.
         return(Xml.Element("si", "http://jabber.org/protocol/si").Child(
                    FeatureNegotiation.Create(new SubmitForm(
                                                  new ListField("stream-method", method)))));
     } catch {
         return(new XmppError(ErrorType.Cancel, ErrorCondition.BadRequest).Data);
     }
 }
示例#21
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>
        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));
                }
            }
        }
示例#22
0
        private XmlElement OnStreamInitiationRequest(Jid from, XmlElement si)
        {
            FileStream stream = null;

            try
            {
                string str       = this.SelectStreamMethod(si["feature"]);
                string attribute = si.GetAttribute("id");
                if (string.IsNullOrEmpty(attribute) || this.siSessions.ContainsKey(attribute))
                {
                    return(new XmppError(ErrorType.Cancel, ErrorCondition.Conflict, new XmlElement[0]).Data);
                }
                XmlElement   element     = si["file"];
                string       description = (element["desc"] != null) ? element["desc"].InnerText : null;
                string       name        = element.GetAttribute("name");
                int          num         = int.Parse(element.GetAttribute("size"));
                FileTransfer transfer    = new FileTransfer(from, base.im.Jid, name, (long)num, attribute, description, 0L);
                string       path        = this.TransferRequest(transfer);
                if (path == null)
                {
                    return(new XmppError(ErrorType.Cancel, ErrorCondition.NotAcceptable, new XmlElement[0]).Data);
                }
                stream = File.OpenWrite(path);
                SISession session = new SISession(attribute, stream, (long)num, true, from, base.im.Jid, base.im.GetExtension(str) as IDataStream);
                this.siSessions.TryAdd(attribute, session);
                this.metaData.TryAdd(attribute, new FileMetaData(name, description));
                return(Xml.Element("si", "http://jabber.org/protocol/si").Child(FeatureNegotiation.Create(new SubmitForm(new DataField[] { new ListField("stream-method", str) }))));
            }
            catch
            {
                if (stream != null)
                {
                    stream.Close();
                }
                return(new XmppError(ErrorType.Cancel, ErrorCondition.BadRequest, new XmlElement[0]).Data);
            }
        }
示例#23
0
        /// <summary>
        /// Invoked once the result of a pending stream-initiation operation has been
        /// received.
        /// </summary>
        /// <param name="result">The result of the stream-initiation operation. If
        /// this parameter is null, stream-initiation failed.</param>
        /// <param name="to">The JID of the XMPP user to offer the file to.</param>
        /// <param name="stream">The stream to read the file-data from.</param>
        /// <param name="name">The name of the file, as offered to the XMPP user
        /// with the specified JID.</param>
        /// <param name="size">The number of bytes to transfer.</param>
        /// <param name="cb">A callback method invoked once the other site has
        /// accepted or rejected the file-transfer request.</param>
        /// <param name="description">A description of the file so the receiver can
        /// better understand what is being sent.</param>
        /// <remarks>This is called in the context of an arbitrary thread.</remarks>
        void OnInitiationResult(InitiationResult result, Jid to, string name,
                                Stream stream, long size, string description, Action <bool, FileTransfer> cb)
        {
            FileTransfer transfer = new FileTransfer(im.Jid, to, name, size, null,
                                                     description);

            try {
                // Get the instance of the data-stream extension that the other site has
                // selected.
                IDataStream ext = im.GetExtension(result.Method) as IDataStream;
                // Register the session.
                SISession session = new SISession(result.SessionId, stream, size, false,
                                                  im.Jid, to, ext);
                siSessions.TryAdd(result.SessionId, session);
                // Store the file's meta data.
                metaData.TryAdd(result.SessionId, new FileMetaData(name, description));
                // Invoke user-provided callback.
                if (cb != null)
                {
                    cb.Invoke(true, transfer);
                }
                // Perform the actual data-transfer.
                try {
                    ext.Transfer(session);
                } catch (Exception e) {
                    // Nothing to do here.
                }
            } catch {
                // Something went wrong. Invoke user-provided callback to let them know
                // the file-transfer can't be performed.
                if (cb != null)
                {
                    cb.Invoke(false, transfer);
                }
            }
        }
示例#24
0
 /// <summary>
 /// Cancels the data-transfer implied by the specified SI session.
 /// </summary>
 /// <param name="session">The SI session whose data-transfer to
 /// cancel.</param>
 /// <exception cref="ArgumentNullException">The session parameter is
 /// null.</exception>
 public void CancelTransfer(SISession session)
 {
     session.ThrowIfNull("session");
     siFileTransfer.InvalidateSession(session.Sid);
 }
示例#25
0
        /// <summary>
        /// Performs a direct transfer, meaning we act as a SOCKS5 server.
        /// </summary>
        /// <param name="session">The SI session whose data to transfer.</param>
        /// <exception cref="Socks5Exception">The SOCKS5 server could not be
        /// instantiated.</exception>
        /// <exception cref="XmppErrorException">The server 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>
        void DirectTransfer(SISession session)
        {
            // Create the listening SOCKS5 server.
            Socks5Server socks5Server = null;

            try {
                socks5Server = CreateSocks5Server(serverPortFrom, serverPortTo);
            } catch (Exception e) {
                throw new Socks5Exception("The SOCKS5 server could not be created.", e);
            }
            IEnumerable <IPAddress> externalAddresses = null;

            try {
                externalAddresses = GetExternalAddresses();
                // Check if we might need to forward the server port.
                if (externalAddresses.Any(addr => BehindNAT(addr)) && UseUPnP)
                {
                    try {
                        //UPnP.ForwardPort(socks5Server.Port, ProtocolType.Tcp,
                        //	"XMPP SOCKS5 File-transfer");
                    } catch (InvalidOperationException) {
                        // If automatic port forwarding failed for whatever reason, just
                        // go on normally. The user can still configure forwarding manually.
                    }
                }
            } catch (NotSupportedException) {
                // Not much we can do.
            }
            // Waiting for a client connection is a blocking call and we need to
            // negotiate the SOCKS5 connection after we send the IQ request but
            // _before_ we wait for the IQ response.
            Task.Factory.StartNew(() => {
                try {
                    AcceptClientConnection(session, socks5Server, acceptTimeout);
                    SendData(session, socks5Server.GetStream());
                } finally {
                    socks5Server.Close();
                }
            });

            // Send target a list of streamhosts, one for each active network interface.
            var xml = Xml.Element("query", "http://jabber.org/protocol/bytestreams")
                      .Attr("sid", session.Sid);
            // Compile a set of all our IP addresses that we can advertise.
            ISet <IPAddress> ips = new HashSet <IPAddress>();

            if (externalAddresses != null)
            {
                ips.UnionWith(externalAddresses);
            }
            ips.UnionWith(GetIpAddresses());
            foreach (var ip in ips)
            {
                xml.Child(Xml.Element("streamhost")
                          .Attr("jid", im.Jid.ToString())
                          .Attr("host", ip.ToString())
                          .Attr("port", socks5Server.Port.ToString()));
            }
            // Send IQ with streamhosts to the target.
            var iq = im.IqRequest(IqType.Set, session.To, im.Jid, xml);

            if (iq.Type == IqType.Error)
            {
                throw Util.ExceptionFromError(iq, "The SOCKS5 connection could not " +
                                              "be established.");
            }
        }
示例#26
0
 /// <summary>
 /// Cancels the data-transfer implied by the specified SI session.
 /// </summary>
 /// <param name="session">The SI session whose data-transfer to
 /// cancel.</param>
 /// <exception cref="ArgumentNullException">The session parameter is
 /// null.</exception>
 public void CancelTransfer(SISession session)
 {
     session.ThrowIfNull("session");
     siFileTransfer.InvalidateSession(session.Sid);
     TransferAborted.Raise(this, new TransferAbortedEventArgs(session));
 }
 public TransferAbortedEventArgs(SISession session)
 {
     session.ThrowIfNull <SISession>("session");
     this.Session = session;
 }
示例#28
0
 internal FileTransfer(SISession session, string name, string description) : this(session.From, session.To, name, session.Size, session.Sid, description, session.Count)
 {
 }
示例#29
0
		/// <summary>
		/// Invoked whenever a 'Stream Initiation' request for file transfers
		/// is received.
		/// </summary>
		/// <param name="from">The JID of the XMPP entity that wishes to initiate
		/// the data-stream.</param>
		/// <param name="si">The 'si' element of the request.</param>
		/// <returns>The response to the SI request or an error element to include
		/// in the IQ response.</returns>
		XmlElement OnStreamInitiationRequest(Jid from, XmlElement si) {
			try {
				string method = SelectStreamMethod(si["feature"]);
				// If the session-id is already in use, we cannot process the request.
				string sid = si.GetAttribute("id");
				if (String.IsNullOrEmpty(sid) || siSessions.ContainsKey(sid))
					return new XmppError(ErrorType.Cancel, ErrorCondition.Conflict).Data;
				// Extract file information and hand to user.
				var file = si["file"];
				string desc = file["desc"] != null ? file["desc"].InnerText : null,
					name = file.GetAttribute("name");
				int size = Int32.Parse(file.GetAttribute("size"));
				FileTransfer transfer = new FileTransfer(from, im.Jid, name, size,
					sid, desc);
				string savePath = TransferRequest.Invoke(transfer);
				// User has rejected the request.
				if (savePath == null)
					return new XmppError(ErrorType.Cancel, ErrorCondition.NotAcceptable).Data;
				// Create an SI session instance.
				SISession session = new SISession(sid, File.OpenWrite(savePath),
					size, true, from, im.Jid, im.GetExtension(method) as IDataStream);
				siSessions.TryAdd(sid, session);
				// Store the file's meta data.
				metaData.TryAdd(sid, new FileMetaData(name, desc));
				// Construct and return the negotiation result.
				return Xml.Element("si", "http://jabber.org/protocol/si").Child(
					FeatureNegotiation.Create(new SubmitForm(
						new ListField("stream-method", method))));
			} catch {
				return new XmppError(ErrorType.Cancel, ErrorCondition.BadRequest).Data;
			}
		}
 /// <summary>
 /// Initializes a new instance of the BytesTransferredEventArgs class.
 /// </summary>
 /// <param name="session">The session for which the event is raised.</param>
 /// <exception cref="ArgumentNullException">The session parameter
 /// is null.</exception>
 public TransferAbortedEventArgs(SISession session)
 {
     session.ThrowIfNull("session");
     Session = session;
 }
		/// <summary>
		/// Initializes a new instance of the BytesTransferredEventArgs class.
		/// </summary>
		/// <param name="session">The session for which the event is raised.</param>
		/// <exception cref="ArgumentNullException">The session parameter
		/// is null.</exception>
		public BytesTransferredEventArgs(SISession session) {
			session.ThrowIfNull("session");
			Session = session;
		}
示例#32
0
		/// <summary>
		/// Invoked once the result of a pending stream-initiation operation has been
		/// received.
		/// </summary>
		/// <param name="result">The result of the stream-initiation operation. If
		/// this parameter is null, stream-initiation failed.</param>
		/// <param name="to">The JID of the XMPP user to offer the file to.</param>
		/// <param name="stream">The stream to read the file-data from.</param>
		/// <param name="name">The name of the file, as offered to the XMPP user
		/// with the specified JID.</param>
		/// <param name="size">The number of bytes to transfer.</param>
		/// <param name="cb">A callback method invoked once the other site has
		/// accepted or rejected the file-transfer request.</param>
		/// <param name="description">A description of the file so the receiver can
		/// better understand what is being sent.</param>
		/// <remarks>This is called in the context of an arbitrary thread.</remarks>
		void OnInitiationResult(InitiationResult result, Jid to, string name,
			Stream stream, long size, string description, Action<bool, FileTransfer> cb) {
			FileTransfer transfer = new FileTransfer(im.Jid, to, name, size, null,
				description);
			try {
				// Get the instance of the data-stream extension that the other site has
				// selected.
				IDataStream ext = im.GetExtension(result.Method) as IDataStream;
				// Register the session.
				SISession session = new SISession(result.SessionId, stream, size, false,
					im.Jid, to, ext);
				siSessions.TryAdd(result.SessionId, session);
				// Store the file's meta data.
				metaData.TryAdd(result.SessionId, new FileMetaData(name, description));
				// Invoke user-provided callback.
				if (cb != null)
					cb.Invoke(true, transfer);
				// Perform the actual data-transfer.
				try {
					ext.Transfer(session);
				} catch(Exception e) {
					// Nothing to do here.
				}
			} catch {
				// Something went wrong. Invoke user-provided callback to let them know
				// the file-transfer can't be performed.
				if (cb != null)
					cb.Invoke(false, transfer);
			}
		}
示例#33
0
 public BytesTransferredEventArgs(SISession session)
 {
     session.ThrowIfNull <SISession>("session");
     this.Session = session;
 }
		/// <summary>
		/// Initializes a new instance of the BytesTransferredEventArgs class.
		/// </summary>
		/// <param name="session">The session for which the event is raised.</param>
		/// <exception cref="ArgumentNullException">The session parameter
		/// is null.</exception>
		public TransferAbortedEventArgs(SISession session) {
			session.ThrowIfNull("session");
			Session = session;
		}