CChatCore类

//
// ChatCore.h
//
// Copyright (c) Shareaza Development Team, 2002-2005.
// This file is part of SHAREAZA (
www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#if !defined(AFX_CHATCORE_H__F550EC04_AC7C_42B1_BE5B_7CDF69EA2286__INCLUDED_)
#define AFX_CHATCORE_H__F550EC04_AC7C_42B1_BE5B_7CDF69EA2286__INCLUDED_

#pragma once

class CConnection;

class CChatSession;


class CChatCore
{

// Construction

public:

 CChatCore();

 virtual ~CChatCore();

// Attributes

public:

 CMutex  m_pSection;

protected:

 CPtrList m_pSessions;
 
 HANDLE  m_hThread;
 
 BOOL  m_bThread;
 
 CEvent  m_pWakeup;

// Operations

public:

 POSITION  GetIterator() const;

 CChatSession* GetNext(POSITION& pos) const;

 int    GetCount() const;

 BOOL   Check(CChatSession* pSession) const;

 void   Close();

 void   OnAccept(CConnection* pConnection,
                PROTOCOLID nProtocol = PROTOCOL_NULL);

 BOOL   OnPush(GGUID* pGUID, CConnection* pConnection);

 void   OnED2KMessage(CEDClient* pClient, CEDPacket* pPacket);

 CChatSession* FindSession(CEDClient* pClient);

 void   StopThread();

protected:

 void   Add(CChatSession* pSession);

 void   Remove(CChatSession* pSession);

 void   StartThread();

protected:

 static UINT  ThreadStart(LPVOID pParam);

 void   OnRun();

 friend class CChatSession;
};

extern CChatCore ChatCore;

//
// ChatCore.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2005.
// This file is part of SHAREAZA (
www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "EDClient.h"
#include "ChatSession.h"
#include "ChatCore.h"
#include "Buffer.h"


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

CChatCore ChatCore;


//
// CChatCore construction

CChatCore::CChatCore()
{
 m_hThread = NULL;

 m_bThread = FALSE;
}

CChatCore::~CChatCore()
{
 Close();
}

//
// CChatCore session access

//CChatSession数组m_pSessions的一些获取函数

POSITION CChatCore::GetIterator() const
{
 return m_pSessions.GetHeadPosition();
}

CChatSession* CChatCore::GetNext(POSITION& pos) const
{
 return (CChatSession*)m_pSessions.GetNext( pos );
}

int CChatCore::GetCount() const
{
 return m_pSessions.GetCount();
}

//在m_pSessions中寻找参数pSession所指定的CChatSession

BOOL CChatCore::Check(CChatSession* pSession) const
{
 return m_pSessions.Find( pSession ) != NULL;
}

//
// CChatCore accept new connections

/*

创建一个CChatSession对象,将这个对象的协议设置为参数协议

同时将当前的Session链接到参数CConnection对象pConnection上

*/

void CChatCore::OnAccept(CConnection* pConnection,
       PROTOCOLID nProtocol)
{
 CSingleLock pLock( &m_pSection );

 if ( ! pLock.Lock( 250 ) )
 {
  return;
 }
 
 CChatSession* pSession = new CChatSession();

 pSession->m_nProtocol = nProtocol;

 pSession->AttachTo( pConnection );
}

//对每个CChatSession调用OnPush方法,参数是同样的

//只要有一个成功了就返回真

BOOL CChatCore::OnPush(GGUID* pGUID,
        CConnection* pConnection)
{
 CSingleLock pLock( &m_pSection );

 if ( ! pLock.Lock( 250 ) )
 {
  return FALSE;
 }
 
 for ( POSITION pos = GetIterator() ; pos ; )
 {
  CChatSession* pSession = GetNext( pos );

  if ( pSession->OnPush( pGUID, pConnection ) )
  {
   return TRUE;
  }
 }
 
 return FALSE;
}

//
// CChatCore ED2K chat handling

//在ChatSession中找到pClient指定的那个Session然后调用OnED2KMessage函数处理

void CChatCore::OnED2KMessage(CEDClient* pClient,
         CEDPacket* pPacket)
{
 ASSERT ( pClient != NULL );

 // Note: Null packet is valid- in that case we have no pending message, but want to open
 // a chat window.

 CSingleLock pLock( &m_pSection );

 if ( ! pLock.Lock( 250 ) )
 {
  return;
 }
 
 CChatSession* pSession = FindSession( pClient );

 pSession->OnED2KMessage( pPacket );
}

//找到协议是ED2K,地址和pClient地址相同的那个session,如果没有找到则创建一个新的

CChatSession* CChatCore::FindSession(CEDClient* pClient)
{
 CChatSession* pSession;

 for ( POSITION pos = GetIterator() ; pos ; )
 {
  pSession = GetNext( pos );

  // If we already have a session,guid和client的guid相等并且地址也相等

  //而且session的协议还必须是PROTOCOL_ED2K

  if ( ( ( ! pSession->m_bGUID ) || ( pSession->m_pGUID == pClient->m_pGUID ) )
   && ( pSession->m_pHost.sin_addr.S_un.S_addr
      == pClient->m_pHost.sin_addr.S_un.S_addr )
      && ( pSession->m_nProtocol == PROTOCOL_ED2K ) )
  {

   // Update details

   pSession->m_bGUID  = pClient->m_bGUID;

   pSession->m_pGUID  = pClient->m_pGUID;

   pSession->m_pHost  = pClient->m_pHost;

   pSession->m_sAddress = pClient->m_sAddress;

   pSession->m_sUserNick = pClient->m_sNick;
   
   pSession->m_sUserAgent = pClient->m_sUserAgent;
   
   pSession->m_bUnicode = pClient->m_bEmUnicode;
   
   pSession->m_nClientID = pClient->m_nClientID;
   
   pSession->m_pServer  = pClient->m_pServer;

   pSession->m_bMustPush = ( ( pClient->m_nClientID > 0 )
    && ( pClient->m_nClientID < 16777216 ) );

   // return existing session

   return pSession;
  }
 }

 // Create a new chat session,没有找到符合条件的session

 //则创建一个新的session,然后根据参数pClient设置session的各个属性的值

 pSession = new CChatSession();

 pSession->m_nProtocol = PROTOCOL_ED2K;
 
 pSession->m_hSocket  = INVALID_SOCKET;   // Should always remain invalid- has no real connection
 
 pSession->m_nState  = cssActive;
 
 pSession->m_bConnected = TRUE;
 
 pSession->m_tConnected = GetTickCount();

 // Set details
 
 pSession->m_bGUID  = pClient->m_bGUID;
 
 pSession->m_pGUID  = pClient->m_pGUID;
 
 pSession->m_pHost  = pClient->m_pHost;
 
 pSession->m_sAddress = pClient->m_sAddress;
 
 pSession->m_sUserNick = pClient->m_sNick;
 
 pSession->m_sUserAgent = pClient->m_sUserAgent;
 
 pSession->m_bUnicode = pClient->m_bEmUnicode;
 
 pSession->m_nClientID = pClient->m_nClientID;
 
 pSession->m_pServer  = pClient->m_pServer;

 pSession->m_bMustPush = ( ( pClient->m_nClientID > 0 ) && ( pClient->m_nClientID < 16777216 ) );

 // Make new input and output buffer objects
 
 DWORD nLimit = 0;
 
 pSession->m_pInput  = new CBuffer( &nLimit );
 
 pSession->m_pOutput  = new CBuffer( &nLimit );

 Add( pSession );

 return pSession;
}

//
// CChatCore session add and remove

/*

如果在sessions中找不到参数pSession,则将参数指定的pSession加入

到session链表,并设置事件m_pWakeup为socket的通知,

同时开启线程,开始处理各个session

*/

void CChatCore::Add(CChatSession* pSession)
{
 CSingleLock pLock( &m_pSection, TRUE );

 if ( m_pSessions.Find( pSession ) == NULL )
 {
  m_pSessions.AddTail( pSession );
 }

 if ( pSession->m_hSocket != INVALID_SOCKET )
 {
  WSAEventSelect( pSession->m_hSocket, m_pWakeup,
   FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE );
 }

 StartThread();
}

/*

在m_pSessions中找到参数pSession指定的session,然后删除之,

如果session的socket句柄是有效的,则将这个socket和事件

m_pWakeup关联起来。

*/

void CChatCore::Remove(CChatSession* pSession)
{
 CSingleLock pLock( &m_pSection, TRUE );

 POSITION pos = m_pSessions.Find( pSession );

 if ( pos != NULL )
 {
  m_pSessions.RemoveAt( pos );
 }

 if ( pSession->m_hSocket != INVALID_SOCKET )
 {
  WSAEventSelect( pSession->m_hSocket, m_pWakeup, 0 );
 }
}

//调用每个CChatSession的Close,然后停止线程

void CChatCore::Close()
{
 for ( POSITION pos = GetIterator() ; pos ; )
 {
  GetNext( pos )->Close();
 }
 
 StopThread();
}

//
// CChatCore thread control 开启一个线程,设置m_bThread为真

void CChatCore::StartThread()
{
 //如果m_bThread为真,而且线程m_hThread已经创建了,直接返回

 if ( m_hThread != NULL && m_bThread )
 {
  return;
 }

 if ( GetCount() == 0 )//没有ChatSession了,直接返回
 {
  return;
 }

 //设置m_bThread为真,开启一个线程,开始执行
 
 m_bThread = TRUE;

 CWinThread* pThread =
  AfxBeginThread( ThreadStart, this,
  THREAD_PRIORITY_NORMAL );

 m_hThread = pThread->m_hThread;
}

//结束线程m_hThread,设置m_pWakeup事件

void CChatCore::StopThread()
{
 if ( m_hThread == NULL ) // 线程还没有启动呢,直接返回
 {
  return;
 }
 
 m_pWakeup.SetEvent();//设置醒来事件

 //等待5次,每次睡100毫秒,看线程m_hThread能否结束
 
    int nAttempt = 5;

 for ( ; nAttempt > 0 ; nAttempt-- )
 {
  DWORD nCode;

  if ( ! GetExitCodeThread( m_hThread, &nCode ) )
  {
   break;
  }

  if ( nCode != STILL_ACTIVE )
  {
   break;
  }

  Sleep( 100 );
 }
 
 if ( nAttempt == 0 ) // 线程还没有结束,强制结束之
 {
  TerminateThread( m_hThread, 0 );

  theApp.Message( MSG_DEBUG,
   _T("WARNING: Terminating CChatCore thread.") );

  Sleep( 100 );
 }
 
 m_hThread = NULL;//线程结束了,设置为NULL
}

//
// CChatCore thread run 线程函数

UINT CChatCore::ThreadStart(LPVOID pParam)
{
 CChatCore* pChatCore = (CChatCore*)pParam;

 pChatCore->OnRun();

 return 0;
}

//循环处理每个session,调用每个session的OnRun函数

void CChatCore::OnRun()
{
 CSingleLock pLock( &m_pSection );
 
 while ( m_bThread )
 {
  Sleep( 50 );

  //先睡上50毫秒,然后等待m_pWakeup事件

     /*

  DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD dwMilliseconds
);

参数hHandle是一个事件的句柄,第二个参数dwMilliseconds是时间间隔。

如果时间是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值

但时间事件还是无信号状态则返回WAIT_TIMEOUT。

WaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间

超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将

直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到

WaitForSingleObject有返回直才执行后面的代码。

  */

  WaitForSingleObject( m_pWakeup, 100 );
  
  if ( pLock.Lock( 250 ) )
  {
   if ( GetCount() == 0 ) // 没有session了就返回
   {
    break;
   }

   //调用每个CChatSession的Run函数
   
   for ( POSITION pos = GetIterator() ; pos ; )
   {
    GetNext( pos )->DoRun();
   }
   
   pLock.Unlock();
  }
 }
 
 m_bThread = FALSE;
}

#endif // !defined(AFX_CHATCORE_H__F550EC04_AC7C_42B1_BE5B_7CDF69EA2286__INCLUDED_)
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值