private Boolean TimedOut(DccFileSession session) { if ((DateTime.Now - session.LastActivity) >= timeout) { return(true); } return(false); }
internal void RemoveSession(DccFileSession session) { sessions.Remove(session.ID); if (sessions.Count == 0) { timerStopped = true; timerThread.Change(Timeout.Infinite, TimeoutCheckPeriod); } Debug.WriteLineIf(DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name + "] DccSessionManager::RemoveSession() ID=" + session.ID); }
internal void AddSession(DccFileSession session) { sessions.Add(session.ID, session); if (timerStopped) { timerStopped = false; timerThread.Change(TimeoutCheckPeriod, TimeoutCheckPeriod); } Debug.WriteLineIf(DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name + "] DccSessionManager::AddSession() ID=" + session.ID); }
internal void CheckSessions(object state) { Debug.WriteLineIf(DccUtil.DccTrace.TraceVerbose, "[" + Thread.CurrentThread.Name + "] DccSessionManager::CheckSessions()"); sessionClone = (Hashtable)sessions.Clone(); foreach (object session in sessionClone.Values) { DccFileSession fileSession = (DccFileSession)session; lock ( fileSession ) { if (TimedOut(fileSession)) { fileSession.TimedOut(); } } } }
/// <summary> /// Attempt to send a file to a remote user. Start listening /// on the given port and address. If the remote user does not accept /// the offer within the timeout period the the session /// will be closed. /// </summary> /// <remarks> /// This method should be called from within a try/catch block /// in case there are socket errors. This methods will also automatically /// handle a Resume if the remote client requests it. /// </remarks> /// <param name="dccUser">The 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 NAT/Firewall system. </param> /// <param name="listenPort">The port that the session will listen on.</param> /// <param name="dccFileInfo">The file to be sent. If the file name has spaces in it /// they will be replaced with underscores when the name is sent.</param> /// <param name="bufferSize">The size of the send buffer. Generally should /// be between 4k and 32k.</param> /// <param name="turbo">True to use send-ahead mode for transfers.</param> /// <returns>A unique session instance for this file and remote user.</returns> /// <exception cref="ArgumentException">If the listen port is already in use.</exception> public static DccFileSession Send( DccUser dccUser, string listenIPAddress, int listenPort, DccFileInfo dccFileInfo, int bufferSize, bool turbo) { Debug.WriteLineIf(DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name + "] DccFileSession::Send()"); DccFileSession session = null; //Test if we are already using this port if (DccFileSessionManager.DefaultInstance.ContainsSession("S" + listenPort)) { throw new ArgumentException("Already listening on port " + listenPort); } try { session = new DccFileSession(dccUser, dccFileInfo, bufferSize, listenPort, "S" + listenPort); //set turbo mode session.turboMode = turbo; //Set server IP address session.listenIPAddress = listenIPAddress; //Add session to active sessions hashtable DccFileSessionManager.DefaultInstance.AddSession(session); //Create stream to file dccFileInfo.OpenForRead(); //Start session Thread session.thread = new Thread(new ThreadStart(session.Listen)); session.thread.Name = session.ToString(); session.thread.Start(); //Send DCC Send request to remote user session.DccSend(IPAddress.Parse(listenIPAddress)); return(session); } catch (Exception ex) { if (session != null) { DccFileSessionManager.DefaultInstance.RemoveSession(session); } throw ex; } }
/// <summary> /// Another user has offered to send a file. This method should be called /// to accept the offer and save the file to the give location. The parameters /// needed to call this method are provided by the <c>OnDccFileTransferRequest()</c> /// event. /// </summary> /// <remarks> /// This method should be called from within a try/catch block /// in case it is unable to connect or there are other socket /// errors. /// </remarks> /// <param name="dccUser">Information on the remote user.</param> /// <param name="dccFileInfo">The local file that will hold the data being sent. If the file /// is the result of a previous incomplete download the the attempt will be made /// to resume where the previous left off.</param> /// <param name="turbo">Will the send ahead protocol be used.</param> /// <returns>A unique session instance for this file and remote user.</returns> /// <exception cref="ArgumentException">If the listen port is already in use.</exception> public static DccFileSession Receive(DccUser dccUser, DccFileInfo dccFileInfo, bool turbo) { Debug.WriteLineIf(DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name + "] DccFileSession::Receive()"); //Test if we are already using this port if (DccFileSessionManager.DefaultInstance.ContainsSession("C" + dccUser.remoteEndPoint.Port)) { throw new ArgumentException("Already listening on port " + dccUser.remoteEndPoint.Port); } DccFileSession session = null; try { session = new DccFileSession(dccUser, dccFileInfo, (64 * 1024), dccUser.remoteEndPoint.Port, "C" + dccUser.remoteEndPoint.Port); //Has the initiator specified the turbo protocol? session.turboMode = turbo; //Open file for writing dccFileInfo.OpenForWrite(); DccFileSessionManager.DefaultInstance.AddSession(session); //Determine if we can resume a download if (session.dccFileInfo.ShouldResume()) { session.waitingOnAccept = true; session.dccFileInfo.SetResumeToFileSize(); session.SendResume(); } else { session.thread = new Thread(new ThreadStart(session.Download)); session.thread.Name = session.ToString(); session.thread.Start(); } return(session); } catch (Exception ex) { if (session != null) { DccFileSessionManager.DefaultInstance.RemoveSession(session); } throw ex; } }
private Boolean TimedOut( DccFileSession session ) { if( ( DateTime.Now - session.LastActivity ) >= timeout ) { return true; } return false; }
internal void RemoveSession( DccFileSession session ) { sessions.Remove( session.ID ); if( sessions.Count == 0 ) { timerStopped = true; timerThread.Change( Timeout.Infinite, TimeoutCheckPeriod ); } Debug.WriteLineIf( DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name +"] DccSessionManager::RemoveSession() ID=" + session.ID ); }
internal void AddSession( DccFileSession session ) { sessions.Add( session.ID, session ); if( timerStopped ) { timerStopped = false; timerThread.Change(TimeoutCheckPeriod, TimeoutCheckPeriod); } Debug.WriteLineIf( DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name +"] DccSessionManager::AddSession() ID=" + session.ID ); }
/// <summary> /// Attempt to send a file to a remote user. Start listening /// on the given port and address. If the remote user does not accept /// the offer within the timeout period the the session /// will be closed. /// </summary> /// <remarks> /// This method should be called from within a try/catch block /// in case there are socket errors. This methods will also automatically /// handle a Resume if the remote client requests it. /// </remarks> /// <param name="dccUser">The 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 NAT/Firewall system. </param> /// <param name="listenPort">The port that the session will listen on.</param> /// <param name="dccFileInfo">The file to be sent. If the file name has spaces in it /// they will be replaced with underscores when the name is sent.</param> /// <param name="bufferSize">The size of the send buffer. Generally should /// be between 4k and 32k.</param> /// <param name="turbo">True to use send-ahead mode for transfers.</param> /// <returns>A unique session instance for this file and remote user.</returns> /// <exception cref="ArgumentException">If the listen port is already in use.</exception> public static DccFileSession Send( DccUser dccUser, string listenIPAddress, int listenPort, DccFileInfo dccFileInfo, int bufferSize, bool turbo) { Debug.WriteLineIf(DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name + "] DccFileSession::Send()"); DccFileSession session = null; //Test if we are already using this port if (DccFileSessionManager.DefaultInstance.ContainsSession("S" + listenPort)) { throw new ArgumentException("Already listening on port " + listenPort); } try { session = new DccFileSession(dccUser, dccFileInfo, bufferSize, listenPort, "S" + listenPort); //set turbo mode session.turboMode = turbo; //Set server IP address session.listenIPAddress = listenIPAddress; //Add session to active sessions hashtable DccFileSessionManager.DefaultInstance.AddSession(session); //Create stream to file dccFileInfo.OpenForRead(); //Start session Thread session.thread = new Thread(new ThreadStart(session.Listen)); session.thread.Name = session.ToString(); session.thread.Start(); //Send DCC Send request to remote user session.DccSend(IPAddress.Parse(listenIPAddress)); return session; } catch (Exception ex) { if (session != null) { DccFileSessionManager.DefaultInstance.RemoveSession(session); } throw ex; } }
/// <summary> /// Another user has offered to send a file. This method should be called /// to accept the offer and save the file to the give location. The parameters /// needed to call this method are provided by the <c>OnDccFileTransferRequest()</c> /// event. /// </summary> /// <remarks> /// This method should be called from within a try/catch block /// in case it is unable to connect or there are other socket /// errors. /// </remarks> /// <param name="dccUser">Information on the remote user.</param> /// <param name="dccFileInfo">The local file that will hold the data being sent. If the file /// is the result of a previous incomplete download the the attempt will be made /// to resume where the previous left off.</param> /// <param name="turbo">Will the send ahead protocol be used.</param> /// <returns>A unique session instance for this file and remote user.</returns> /// <exception cref="ArgumentException">If the listen port is already in use.</exception> public static DccFileSession Receive(DccUser dccUser, DccFileInfo dccFileInfo, bool turbo) { Debug.WriteLineIf(DccUtil.DccTrace.TraceInfo, "[" + Thread.CurrentThread.Name + "] DccFileSession::Receive()"); //Test if we are already using this port if (DccFileSessionManager.DefaultInstance.ContainsSession("C" + dccUser.remoteEndPoint.Port)) { throw new ArgumentException("Already listening on port " + dccUser.remoteEndPoint.Port); } DccFileSession session = null; try { session = new DccFileSession(dccUser, dccFileInfo, (64 * 1024), dccUser.remoteEndPoint.Port, "C" + dccUser.remoteEndPoint.Port); //Has the initiator specified the turbo protocol? session.turboMode = turbo; //Open file for writing dccFileInfo.OpenForWrite(); DccFileSessionManager.DefaultInstance.AddSession(session); //Determine if we can resume a download if (session.dccFileInfo.ShouldResume()) { session.waitingOnAccept = true; session.dccFileInfo.SetResumeToFileSize(); session.SendResume(); } else { session.thread = new Thread(new ThreadStart(session.Download)); session.thread.Name = session.ToString(); session.thread.Start(); } return session; } catch (Exception ex) { if (session != null) { DccFileSessionManager.DefaultInstance.RemoveSession(session); } throw ex; } }
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.Error(ReplyCode.UnparseableMessage, "Incorrect CHAT arguments: " + message); return; } //Send event DccUser dccUser = null; try { dccUser = new DccUser( connection, Rfc2812Util.ParseUserLine(requestor), new IPEndPoint(DccUtil.LongToIPAddress(tokens[Address]), int.Parse(tokens[Port], CultureInfo.InvariantCulture))); } catch (ArgumentException) { connection.Listener.Error(ReplyCode.BadDccEndpoint, "Invalid TCP/IP connection information sent."); return; } try { OnDccChatRequest(dccUser); } catch (ArgumentException ae) { connection.Listener.Error(ReplyCode.UnknownEncryptionProtocol, ae.ToString()); } } break; case SEND: //Test for sufficient number of arguments if (tokens.Length < 5) { connection.Listener.Error(ReplyCode.UnparseableMessage, "Incorrect SEND arguments: " + message); return; } if (OnDccSendRequest != null) { DccUser dccUser = null; try { dccUser = new DccUser( connection, Rfc2812Util.ParseUserLine(requestor), new IPEndPoint(DccUtil.LongToIPAddress(tokens[Address]), int.Parse(tokens[Port], CultureInfo.InvariantCulture))); } catch (ArgumentException ae) { connection.Listener.Error(ReplyCode.BadDccEndpoint, ae.ToString()); return; } try { OnDccSendRequest( dccUser, tokens[FileName], int.Parse(tokens[FileSize], CultureInfo.InvariantCulture), IsTurbo(5, tokens)); } catch (ArgumentException ae) { connection.Listener.Error(ReplyCode.UnknownEncryptionProtocol, ae.ToString()); } } break; case GET: //Test for sufficient number of arguments if (tokens.Length < 2) { connection.Listener.Error(ReplyCode.UnparseableMessage, "Incorrect GET arguments: " + message); return; } if (OnDccGetRequest != null) { try { OnDccGetRequest( new DccUser( connection, Rfc2812Util.ParseUserLine(requestor)), tokens[FileName], IsTurbo(2, tokens)); } catch (ArgumentException ae) { connection.Listener.Error(ReplyCode.UnknownEncryptionProtocol, ae.ToString()); } } break; case ACCEPT: //Test for sufficient number of arguments if (tokens.Length < 4) { connection.Listener.Error(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.Error(ReplyCode.UnableToResume, e.ToString()); } break; case RESUME: //Test for sufficient number of arguments if (tokens.Length < 4) { connection.Listener.Error(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.Error(ReplyCode.UnableToResume, e.ToString()); } break; default: connection.Listener.Error(ReplyCode.UnparseableMessage, message); Debug.WriteLineIf(DccUtil.DccTrace.TraceError, "[" + Thread.CurrentThread.Name + "] DccListener::Parse() Unknown DCC command"); break; } }