internal DccChatSession( DccUserInfo dccUserInfo ) { _dccUserInfo = dccUserInfo; _listening = false; _receiving = false; }
/// <summary> /// Send a DCC Chat request to a remote user and wait for a connection /// using timeout period specified. /// </summary> /// <remarks> /// <para>If the user does not respond within the timeout period the DccChatSession /// will stop listening for a connection. The sesssion instance created then becomes /// invalid. This methods must be called again and a new instance created in order to /// initiate a try again. /// </para> /// <para> /// This method should be called from within a try/catch block /// in case there are socket errors. /// </para> /// </remarks> /// <param name="dccUserInfo">A collection of information about the remote user.</param> /// <param name="listenIPAddress">The IP address that will be sent to the remote user. It must /// be in dotted quad format (i.e. 192.168.0.2). If the client is behind a NAT system then /// this should be the address of that system and not the local host.</param> /// <param name="listenPort">The TCP/IP port to listen on</param> /// <param name="timeout">How long to wait for a response in milliseconds. /// A value of zero will disable the timeout.</param> public static DccChatSession Request( DccUserInfo dccUserInfo, string listenIPAddress, int listenPort, long timeout ) { Debug.WriteLineIf( DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name +"] DccChatSession::Request()"); //Create session object var session = new DccChatSession( dccUserInfo ); session._listenPort = listenPort; //Start session Thread session._thread = new Thread(new ThreadStart( session.Listen ) ); session._thread.Name = session.ToString(); session._thread.Start(); //Send Chat request to remote user session.SendChatRequest( listenIPAddress, listenPort ); //Start timeout thread if timeout > 0 if( timeout > 0 ) { var timer = new Timer( session.TimerExpired, session, timeout, 0); Debug.WriteLineIf( DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name +"] DccChatSession::Request timeout thread started"); } return session; }
/// <summary> /// When another a remote user has sent a chat request, this /// method is called to accept the request and /// start a chat session with that user. /// </summary> /// <remarks> /// This method should be called from within a try/catch block /// because there are many things that could prevent this /// connection attempt from succeeding. /// </remarks> /// <param name="dccUserInfo">A collection of information about the remote user.</param> /// <returns>The DccChatSession instance for this session.</returns> public static DccChatSession Accept( DccUserInfo dccUserInfo ) { Debug.WriteLineIf( DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name +"] DccChatSession::Accept()"); var session = new DccChatSession( dccUserInfo ); //Start session Thread session._thread = new Thread(session.Connect) {Name = session.ToString()}; session._thread.Start(); return session; }
/// <summary> /// Send a DCC Chat request to a remote user and use the default /// timeout period of 30 seconds. /// </summary> /// <remarks> /// <para>If the user does not respond within the timeout period the DccChatSession /// will stop listening for a connection. The sesssion instance created then becomes /// invalid. This methods must be called again and a new instance created in order to /// initiate a try again. /// </para> /// <para> /// This method should be called from within a try/catch block /// in case there are socket errors. /// </para> /// </remarks> /// <param name="dccUserInfo">A collection of information about the remote user.</param> /// <param name="listenIPAddress">The IP address of the local machine in dot /// quad format (e.g. 192.168.0.25). This is the address that will be sent to the /// remote user. The IP address of the NAT machine must be used if the /// client is behind a a NAT/Firewall system. </param> /// <param name="listenPort">The TCP/IP port to listen on</param> public static DccChatSession Request( DccUserInfo dccUserInfo, string listenIPAddress, int listenPort ) { return Request( dccUserInfo, listenIPAddress, listenPort, DefaultTimeout ); }
internal void Parse(Connection connection, string message) { Debug.WriteLineIf(DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name + "] DccListener::Parse()"); Match match = _parser.Match(message); string requestor = match.Groups[1].ToString(); string[] tokens = _tokenizer.Split(match.Groups[2].ToString().Trim()); switch (tokens[Action]) { case Chat: if (OnDccChatRequest != null) { //Test for sufficient number of arguments if (tokens.Length < 4) { connection.Listener.FireError(ReplyCode.UnparseableMessage, "Incorrect CHAT arguments: " + message); return; } //Send event DccUserInfo dccUserInfo; try { dccUserInfo = new DccUserInfo( connection, Rfc2812Util.ParseUserInfoLine(requestor), new IPEndPoint(DccUtil.LongToIPAddress(tokens[Address]), int.Parse(tokens[Port], CultureInfo.InvariantCulture))); } catch (ArgumentException ae) { connection.Listener.FireError(ReplyCode.BadDccEndpoint, "Invalid TCP/IP connection information sent."); return; } try { OnDccChatRequest(dccUserInfo); } catch (ArgumentException ae) { connection.Listener.FireError(ReplyCode.UnknownEncryptionProtocol, ae.ToString()); } } break; case Send: //Test for sufficient number of arguments if (tokens.Length < 5) { connection.Listener.FireError(ReplyCode.UnparseableMessage, "Incorrect SEND arguments: " + message); return; } if (OnDccSendRequest != null) { DccUserInfo dccUserInfo; try { dccUserInfo = new DccUserInfo( connection, Rfc2812Util.ParseUserInfoLine(requestor), new IPEndPoint(DccUtil.LongToIPAddress(tokens[Address]), int.Parse(tokens[Port], CultureInfo.InvariantCulture))); } catch (ArgumentException ae) { connection.Listener.FireError(ReplyCode.BadDccEndpoint, ae.ToString()); return; } try { OnDccSendRequest( dccUserInfo, tokens[FileName], int.Parse(tokens[FileSize], CultureInfo.InvariantCulture), IsTurbo(5, tokens)); } catch (ArgumentException ae) { connection.Listener.FireError(ReplyCode.UnknownEncryptionProtocol, ae.ToString()); } } break; case Get: //Test for sufficient number of arguments if (tokens.Length < 2) { connection.Listener.FireError(ReplyCode.UnparseableMessage, "Incorrect GET arguments: " + message); return; } if (OnDccGetRequest != null) { try { OnDccGetRequest( new DccUserInfo( connection, Rfc2812Util.ParseUserInfoLine(requestor)), tokens[FileName], IsTurbo(2, tokens)); } catch (ArgumentException ae) { connection.Listener.FireError(ReplyCode.UnknownEncryptionProtocol, ae.ToString()); } } break; case Accept: //Test for sufficient number of arguments if (tokens.Length < 4) { connection.Listener.FireError(ReplyCode.UnparseableMessage, "Incorrect DCC ACCEPT arguments: " + message); return; } //DccListener will try to handle Receive at correct file position try { DccFileSession session = DccFileSessionManager.DefaultInstance.LookupSession("C" + tokens[2]); session.OnDccAcceptReceived(long.Parse(tokens[3], CultureInfo.InvariantCulture)); } catch (ArgumentException e) { connection.Listener.FireError(ReplyCode.UnableToResume, e.ToString()); } break; case Resume: //Test for sufficient number of arguments if (tokens.Length < 4) { connection.Listener.FireError(ReplyCode.UnparseableMessage, "Incorrect DCC RESUME arguments: " + message); return; } //DccListener will automatically handle Resume/Accept interaction try { DccFileSession session = DccFileSessionManager.DefaultInstance.LookupSession("S" + tokens[2]); session.OnDccResumeRequest(long.Parse(tokens[3], CultureInfo.InvariantCulture)); } catch (ArgumentException e) { connection.Listener.FireError(ReplyCode.UnableToResume, e.ToString()); } break; default: connection.Listener.FireError(ReplyCode.UnparseableMessage, message); Debug.WriteLineIf(DccUtil.DccTrace.TraceError, "[" + Thread.CurrentThread.Name + "] DccListener::Parse() Unknown DCC command"); break; } }