int CStreamCgcProxy::avsRequestP2PUser(const tstring & sRequestUser, long nP2PType, long nP2PParam)
{
	if (!avsIsOpenSession()) return -1;
	if (m_sCurrentUser.empty()) return -1;

	char buffer[30];
	sprintf(buffer, ":%d-%d", nP2PType, nP2PParam);
	tstring sP2PKey(sRequestUser);
	sP2PKey.append(buffer);
	CDoP2PClientHandler::pointer pP2PClient;
	if (!m_p2pProxy.find(sP2PKey, pP2PClient, false))
	{
		DoSotpClientHandler::pointer pDoHandler = m_sotpClient.startClient(nP2PType == CDoP2PClientHandler::P2P_AUDIO || nP2PType == CDoP2PClientHandler::P2P_VIDEO ? m_rtpAddr : m_udpAddr);
		if (pDoHandler.get() == NULL) return -1;
		pDoHandler->doSetAppName(const_Avs_AppName);

		pP2PClient = P2PClient::create(pDoHandler);
		m_p2pProxy.insert(sP2PKey, pP2PClient);
	}else if (pP2PClient->getLocalP2PStatus() && pP2PClient->getRemoteP2PStatus())
	{
		return 1;	// is already P2P state
	}

	pP2PClient->setP2PInfo(sRequestUser, nP2PType);
	pP2PClient->clearP2PStatus();

	DoSotpClientHandler::pointer pDoHandler = pP2PClient->dohandler();
	BOOST_ASSERT(pDoHandler.get() != NULL);

	pDoHandler->doSetResponseHandler(this);
	pDoHandler->doSetRemoteAddr(nP2PType == CDoP2PClientHandler::P2P_AUDIO || nP2PType == CDoP2PClientHandler::P2P_VIDEO
		? m_rtpAddr.address() : m_udpAddr.address());
	pDoHandler->doSetMediaType(const_CGCMediaType);

	if (nP2PType == CDoP2PClientHandler::P2P_AUDIO || nP2PType == CDoP2PClientHandler::P2P_VIDEO)
	{
		for (int i=0; i<=2; i++)
		{
			pDoHandler->doBeginCallLock();
			pDoHandler->doSendAppCall(0, const_Avs_Api_RequestP2PUser);
		}
	}

	pDoHandler->doSetDisableSotpParser(false);
	pDoHandler->doBeginCallLock();
	pDoHandler->doAddParameter(CGC_PARAMETER(_T("FromUser"), m_sCurrentUser));
	pDoHandler->doAddParameter(CGC_PARAMETER(_T("ToUser"), sRequestUser));
	pDoHandler->doAddParameter(CGC_PARAMETER(_T("P2PType"), (long)nP2PType));
	pDoHandler->doAddParameter(CGC_PARAMETER(_T("P2PParam"), nP2PParam));
	pDoHandler->doSendAppCall(const_CallSign_RequestP2PUser, const_Avs_Api_RequestP2PUser);

	return 0;
}
void CStreamCgcProxy::OnCgcResponse(const cgcParserSotp & response)
{
	if (response.isResulted() && response.isOpenType())
	{
		return;
	}
	if (m_handler == NULL || m_cgcClient == NULL) return;

	long resultValue = response.getResultValue();
	switch (response.getSign())
	{
	case 1001:
		{
			// Text Message
			tstring sFromUser = response.getRecvParameterValue(_T("FromUser"));
			tstring sMsg = response.getRecvParameterValue(_T("Msg"));

			//m_handler->onSendTextMessage(sFromUser, sMsg);
		}break;
	case 1002:
		{
			// From TCP/IP
			// P2P Request Message, From Server
			tstring sFromUser = response.getRecvParameterValue(_T("FromUser"));
			tstring sRemoteAddr = response.getRecvParameterValue(_T("RemoteAddr"));
			long nP2PType = response.getRecvParameterValue(_T("P2PType"), 0);
			long nP2PParam = response.getRecvParameterValue(_T("P2PParam"), 0);

			char buffer[30];
			sprintf(buffer, ":%d-%d", nP2PType, nP2PParam);
			tstring sP2PKey(sFromUser);
			sP2PKey.append(buffer);
			CDoP2PClientHandler::pointer pP2PClient;
			if (!m_p2pProxy.find(sP2PKey, pP2PClient, false))
			{
				DoSotpClientHandler::pointer pDoHandler = m_sotpClient.startClient(nP2PType == CDoP2PClientHandler::P2P_AUDIO || nP2PType == CDoP2PClientHandler::P2P_VIDEO
					? m_rtpAddr : m_udpAddr);
				if (pDoHandler.get() == NULL) break;
				pDoHandler->doSetAppName(const_Avs_AppName);

				pP2PClient = P2PClient::create(pDoHandler);
				m_p2pProxy.insert(sP2PKey, pP2PClient);
			}
			pP2PClient->setP2PInfo(sFromUser, nP2PType);
			pP2PClient->setP2PAddress(sRemoteAddr);
			pP2PClient->setP2PParam(nP2PParam);

			// Response P2P Request, To Server
			avsResponseP2PUser(sFromUser, nP2PType, nP2PParam);
		}break;
	case 1003:
		{
			// From TCP/IP
			// P2P Response Message, From Server
			tstring sFromUser = response.getRecvParameterValue(_T("FromUser"));
			tstring sRemoteAddr = response.getRecvParameterValue(_T("RemoteAddr"));
			long nP2PType = response.getRecvParameterValue(_T("P2PType"), 0);
			long nP2PParam = response.getRecvParameterValue(_T("P2PParam"), 0);

			char buffer[30];
			sprintf(buffer, ":%d-%d", nP2PType, nP2PParam);
			tstring sP2PKey(sFromUser);
			sP2PKey.append(buffer);
			CDoP2PClientHandler::pointer pP2PClient;
			if (!m_p2pProxy.find(sP2PKey, pP2PClient, false))
				break;

			pP2PClient->setP2PInfo(sFromUser, nP2PType);
			pP2PClient->setP2PAddress(sRemoteAddr);
			pP2PClient->setP2PParam(nP2PParam);

			// 1003: P2P ACK
			DoSotpClientHandler::pointer pDoHandler = pP2PClient->dohandler();
			BOOST_ASSERT(pDoHandler.get() != NULL);

			pDoHandler->doSetRemoteAddr(sRemoteAddr);
			for (int i=0; i<=2; i++)
				pDoHandler->doSendData((const unsigned char*)"p2ptest", 7);
			for (int i=0; i<20; i++)
			{
				if (m_bDoAccountUnRegister)
					break;

				if (pP2PClient->getLocalP2PStatus())
					sendP2PAck(pP2PClient, nP2PType, nP2PParam, true);
				else
					sendP2PAck(pP2PClient, nP2PType, nP2PParam, false);
#ifdef WIN32
				Sleep(500);
#else
				usleep(500000);
#endif

				if (pP2PClient->getLocalP2PStatus() && pP2PClient->getRemoteP2PStatus())
					break;
			}

			//CDoP2PClientHandler * pClientHandler = (CDoP2PClientHandler*)pP2PClient.get();
			if (pP2PClient->getLocalP2PStatus() && pP2PClient->getRemoteP2PStatus())
			{
				bool disableSotpParse = true;
				CP2PHandler * pP2PHandler = m_handler->onP2PUserAck(pP2PClient, disableSotpParse);
				if (pP2PHandler != NULL)
					pP2PClient->setP2PHandler(pP2PHandler, disableSotpParse);

			}else
			{
				m_handler->onP2PRequestTimeout(pP2PClient);
			}
		}break;
	case 1004:
		{
			// From TCP/IP
			// P2P Response Message return From Server
			tstring sToUser = response.getRecvParameterValue(_T("ToUser"));
			long nP2PType = response.getRecvParameterValue(_T("P2PType"), 0);
			long nP2PParam = response.getRecvParameterValue(_T("P2PParam"), 0);

			char buffer[30];
			sprintf(buffer, ":%d-%d", nP2PType, nP2PParam);
			tstring sP2PKey(sToUser);
			sP2PKey.append(buffer);
			CDoP2PClientHandler::pointer pP2PClient;
			if (!m_p2pProxy.find(sP2PKey, pP2PClient, false))
				break;

			DoSotpClientHandler::pointer pDoHandler = pP2PClient->dohandler();
			BOOST_ASSERT(pDoHandler.get() != NULL);

			pDoHandler->doSetRemoteAddr(pP2PClient->getP2PAddress());
	
			// 1003: P2P ACK
			for (int i=0; i<=2; i++)
				pDoHandler->doSendData((const unsigned char*)"p2ptest", 7);
			for (int i=0; i<20; i++)
			{
				if (m_bDoAccountUnRegister)
					break;

				if (pP2PClient->getLocalP2PStatus())
					sendP2PAck(pP2PClient, nP2PType, nP2PParam, true);
				else
					sendP2PAck(pP2PClient, nP2PType, nP2PParam, false);
#ifdef WIN32
				Sleep(500);
#else
				usleep(500000);
#endif
				if (pP2PClient->getLocalP2PStatus() && pP2PClient->getRemoteP2PStatus())
					break;
			}

			if (pP2PClient->getLocalP2PStatus() && pP2PClient->getRemoteP2PStatus())
			{
				bool disableSotpParse = true;
				//CDoP2PClientHandler * pClientHandler = (CDoP2PClientHandler*)pP2PClient.get();
				CP2PHandler * pP2PHandler = m_handler->onP2PUserAck(pP2PClient, disableSotpParse);
				if (pP2PHandler != NULL)
					pP2PClient->setP2PHandler(pP2PHandler, disableSotpParse);

			}

		}break;
	case 1005:
		{
			// From TCP/IP
			// P2P Disconnect Message, From Server
			tstring sFromUser = response.getRecvParameterValue(_T("FromUser"));
			long nP2PType = response.getRecvParameterValue(_T("P2PType"), 0);
			long nP2PParam = response.getRecvParameterValue(_T("P2PParam"), 0);

			char buffer[30];
			sprintf(buffer, ":%d-%d", nP2PType, nP2PParam);
			tstring sP2PKey(sFromUser);
			sP2PKey.append(buffer);
			CDoP2PClientHandler::pointer pP2PClient;
			if (m_p2pProxy.find(sP2PKey, pP2PClient, true))
			{
				//CDoP2PClientHandler * pClientHandler = (CDoP2PClientHandler*)pP2PClient.get();
				pP2PClient->clearP2PStatus();
				m_handler->onP2PUserDisconnect(pP2PClient);

				DoSotpClientHandler::pointer pDoHandler = pP2PClient->dohandler();
				BOOST_ASSERT(pDoHandler.get() != NULL);
				pDoHandler->doSetRemoteAddr(nP2PType == CDoP2PClientHandler::P2P_AUDIO || nP2PType == CDoP2PClientHandler::P2P_VIDEO ? m_rtpAddr.address() : m_udpAddr.address());
				m_sotpClient.stopClient(pDoHandler);
			}
		}break;
	case 1006:
		{
			tstring sFromUser = response.getRecvParameterValue(_T("FromUser"));
			long nP2PType = response.getRecvParameterValue(_T("P2PType"), 0);
			long nP2PParam = response.getRecvParameterValue(_T("P2PParam"), 0);


			m_handler->onP2PRequestResult(sFromUser, nP2PType, resultValue);
			if (resultValue != 0)
			{
				char buffer[30];
				sprintf(buffer, ":%d-%d", nP2PType, nP2PType);
				tstring sP2PKey(sFromUser);
				sP2PKey.append(buffer);
				CDoP2PClientHandler::pointer pP2PClient;
				if (m_p2pProxy.find(sP2PKey, pP2PClient, true))
				{
					DoSotpClientHandler::pointer pDoHandler = pP2PClient->dohandler();
					BOOST_ASSERT(pDoHandler.get() != NULL);
					pDoHandler->doSetRemoteAddr(nP2PType == CDoP2PClientHandler::P2P_AUDIO || nP2PType == CDoP2PClientHandler::P2P_VIDEO
						? m_rtpAddr.address() : m_udpAddr.address());
					m_sotpClient.stopClient(pDoHandler);
				}
			}
		}break;
	case 2001:
		{
			// User login notify
			tstring sFromUser = response.getRecvParameterValue(_T("FromUser"));
			m_handler->onUserLogined(sFromUser);
		}break;
	case 2002:
		{
			// User login notify
			tstring sFromUser = response.getRecvParameterValue(_T("FromUser"));
			m_handler->onUserLogouted(sFromUser);
		}break;
/*	case 3001:
		{
			// 3001: Transfer Request Message, From Server
			const tstring & sCfid = response.getRecvParameterValue(_T("cfid"));
			const tstring & sFromUser = response.getRecvParameterValue(_T("FromUser"));
			const tstring & sTransferType = response.getRecvParameterValue(_T("TransferType"));
			const tstring & sTransferName = response.getRecvParameterValue(_T("TransferName"));
			const tstring & sRemoteAddr = response.getRecvParameterValue(_T("RemoteAddr"));


			tstring sIp = cgcString::formatStr(sRemoteAddr, _T(""), _T(":"));
			tstring sPort = cgcString::formatStr(sRemoteAddr, _T(":"), _T(""));
			unsigned short nPort = (unsigned short)_ttoi(sPort.c_str());
		}break;
	case 3002:
		{
			// 3002: Transfer Response Message, From Server
			const tstring & sFromUser = response.getRecvParameterValue(_T("FromUser"));
			const tstring & sTransferType = response.getRecvParameterValue(_T("TransferType"));
			const tstring & sTransferName = response.getRecvParameterValue(_T("TransferName"));

			std::fstream fsClientPath;
			fsClientPath.open("d:/myvideoM16.avi", std::ios::out);
			if (fsClientPath.is_open())
			{
				//
				char buffer[1024];
				memset(buffer, 0, 1024);
				fsClientPath.read(buffer, 1024);
				//std::streambuf * rdBuffer = fsClientPath.rdbuf();
				//rdBuffer->g

				//m_transfClient.SendData((const unsigned char*)buffer, 1024, 1);

				fsClientPath.close();
			}
		}break;
	case const_CallSign_UpFile:
		{
			// 开始传附件
			const tstring & sFileName = response.getRecvParameterValue(_T("FileName"));
			const UINT nOneSize = 1024*3;
			char buffer[nOneSize+1];
			memset(buffer, 0, nOneSize+1);
			if (resultValue == 1)
			{
				if (fsClientPath.is_open())
					fsClientPath.close();
				fsClientPath.open("d:/myvideoM16.avi", std::ios::in|std::ios::binary);
				if (fsClientPath.is_open())
				{
					fsClientPath.seekp(0, std::ios::end);
					nTotal = fsClientPath.tellp();
					fsClientPath.seekp(0, std::ios::beg);
					//
					fsClientPath.read(buffer, nOneSize);

					cgc::cgcAttachment::pointer attach(cgcAttachment::create());
					if (fsClientPath.eof())
						attach->setAttach((const unsigned char*)buffer, nTotal);
					else
						attach->setAttach((const unsigned char*)buffer, nOneSize);
					attach->setName("file");
					attach->setTotal(nTotal);
					attach->setIndex(0);
					m_cgcClient->doAddParameter(CGC_PARAMETER(_T("FileName"), sFileName));
					m_cgcClient->doSendAppCall(const_CallSign_UpFile, const_Avs_Api_UpFile, attach);
				}
			}else if (resultValue == 0)
			{
				cgcParameter::pointer pIndex = response.getRecvParameter(_T("INDEX"));

				ULONG nIndex = 0;
				if (pIndex.get() != NULL)
				{
					nIndex = cgcString::toULongValue(pIndex->getValue().c_str(), 0);
				}

				if (!fsClientPath.is_open())
					break;

				if (nIndex + nOneSize >= nTotal)
					break;

				nIndex += nOneSize;
				fsClientPath.seekp(nIndex);
				fsClientPath.read(buffer, nOneSize);

				cgc::cgcAttachment::pointer attach(cgcAttachment::create());
				if (fsClientPath.eof())
				{
					attach->setAttach((const unsigned char*)buffer, nTotal-nIndex);
					fsClientPath.close();
				}else
					attach->setAttach((const unsigned char*)buffer, nOneSize);
				if (attach->getAttachSize() == 0)
				{
					fsClientPath.close();
					break;
				}
				attach->setName("file");
				attach->setTotal(nTotal);
				attach->setIndex(nIndex);
				m_cgcClient->doAddParameter(CGC_PARAMETER(_T("FileName"), sFileName));
				m_cgcClient->doSendAppCall(const_CallSign_UpFile, const_Avs_Api_UpFile, attach);
			}
		}break;
	case const_CallSign_DownFile:
		{
			if (resultValue == 1)
			{
				fsClientPath.close();
			}
			const tstring & sFilename = response.getRecvParameterValue(_T("FileName"));
			if (response.isRecvHasAttachInfo())
			{
				cgcAttachment::pointer attach = response.getRecvAttachment();

				if (attach.get() == NULL || attach->getIndex() == 0)
				{
					fsClientPath.open("d:/myvideoM16-2.avi", std::ios::out|std::ios::binary);
				}

				if (fsClientPath.is_open())
				{
					fsClientPath.seekp(attach->getIndex());
					fsClientPath.write((const char*)attach->getAttachData(), attach->getAttachSize());
					fsClientPath.flush();
				}

				if (attach->getIndex() + attach->getAttachSize() >= attach->getTotal())
				{
					fsClientPath.close();
				}

				//CString sTemp = _T("");
				//sTemp.Format(_T("%d"), attach->getIndex());
				char sTemp[10];
				memset(sTemp, 0, sizeof(sTemp));
				sprintf(sTemp, _T("%d"), attach->getIndex());
				m_cgcClient->doAddParameter(CGC_PARAMETER(_T("FileName"), sFilename));
				m_cgcClient->doAddParameter(CGC_PARAMETER(cgcParameter::PT_INT, _T("INDEX"), sTemp));
				m_cgcClient->doSendAppCall(const_CallSign_DownFile, const_Avs_Api_DownFile);
			}
		}break;
	case const_CallSign_TransferFile:
		{
			// 开始传附件
			const UINT nOneSize = 1024*2;
			if (resultValue == 1)
			{
				if (fsClientPath.is_open())
					fsClientPath.close();
				fsClientPath.open("d:/myvideoM16.avi", std::ios::in|std::ios::binary);
				if (fsClientPath.is_open())
				{
					fsClientPath.seekp(0, std::ios::end);
					std::fstream::pos_type posTotal = fsClientPath.tellp();
					fsClientPath.seekp(0, std::ios::beg);
					//
					char buffer[nOneSize+1];
					memset(buffer, 0, nOneSize+1);
					fsClientPath.read(buffer, nOneSize);

					cgc::cgcAttachment::pointer attach(cgcAttachment::create());
					if (fsClientPath.eof())
						attach->setAttach((const unsigned char*)buffer, posTotal);
					else
						attach->setAttach((const unsigned char*)buffer, nOneSize);
					attach->setName("file");
					attach->setTotal(posTotal);
					attach->setIndex(0);
					m_cgcClient->doSendAppCall(const_CallSign_TransferFile, const_Avs_Api_TransferFile, attach);
				}
			}else if (resultValue == 0)
			{
				cgcParameter::pointer pTotal = response.getRecvParameter(_T("TOTAL"));
				cgcParameter::pointer pIndex = response.getRecvParameter(_T("INDEX"));

//				ULONG nTotal = 0;
				ULONG nIndex = 0;
				if (pTotal.get() != NULL && pIndex.get() != NULL)
				{
					if (nTotal == 0)
						nTotal = cgcString::toULongValue(pTotal->getValue().c_str(), 0);
					nIndex = cgcString::toULongValue(pIndex->getValue().c_str(), 0);
				}

				if (!fsClientPath.is_open())
					break;

				if (nIndex + nOneSize >= nTotal)
					break;

				char buffer[nOneSize+1];
				memset(buffer, 0, nOneSize+1);
				nIndex += nOneSize;
				fsClientPath.seekp(nIndex);
				fsClientPath.read(buffer, nOneSize);

				cgc::cgcAttachment::pointer attach(cgcAttachment::create());
				if (fsClientPath.eof())
				{
					attach->setAttach((const unsigned char*)buffer, nTotal-nIndex);
					fsClientPath.close();
				}else
					attach->setAttach((const unsigned char*)buffer, nOneSize);
				if (attach->getAttachSize() == 0)
				{
					fsClientPath.close();
					break;
				}
				attach->setName("file");
				attach->setTotal(nTotal);
				attach->setIndex(nIndex);
				m_cgcClient->doSendAppCall(const_CallSign_TransferFile, const_Avs_Api_TransferFile, attach);
			}

		}break;
	case const_CallSign_RequestTransfer:
		{
			const tstring & sCfid = response.getRecvParameterValue(_T("cfid"));
			const tstring & sRemoteAddr = response.getRecvParameterValue(_T("RemoteAddr"));

			tstring sIp = cgcString::formatStr(sRemoteAddr, _T(""), _T(":"));
			tstring sPort = cgcString::formatStr(sRemoteAddr, _T(":"), _T(""));
			unsigned short nPort = (unsigned short)_ttoi(sPort.c_str());

//			m_transfClient.CleaerDest();
//			m_transfClient.AddDest(sIp.c_str(), nPort);
//			//std::string sCommConferCmd = "ss:join";
//			//m_transfClient.SendData((const unsigned char*)sCommConferCmd.c_str(), sCommConferCmd.length(), 2);
//			char pBuffer[100];
//			memset(pBuffer, 0, sizeof(pBuffer));
//			sprintf(pBuffer,
//				"JOIN \n"
//				"Cfid: %s\n",
//#ifdef _UNICODE
//				cgcString::W2Char(sCfid).c_str());
//#else
//				sCfid.c_str());
//#endif // _UNICODE
//			m_transfClient.SendData((const unsigned char*)pBuffer, strlen(pBuffer), 1);

		}break;
	case const_CallSign_ResponseTransfer:
		break;*/
	case const_CallSign_LoadSetting:
		{
			tstring sP2PRtpServer = response.getRecvParameterValue(_T("P2PRTPSERVER"));
			tstring sP2PUdpServer = response.getRecvParameterValue(_T("P2PUDPSERVER"));

			std::string::size_type find = sP2PRtpServer.find(":");
			if (find == std::string::npos)
			{
				tstring sTemp = m_serverAddr.getip();
				sTemp.append(":");
				sTemp.append(sP2PRtpServer);
				m_rtpAddr = CCgcAddress(sTemp, CCgcAddress::ST_RTP);
			}else
			{
				m_rtpAddr = CCgcAddress(sP2PRtpServer, CCgcAddress::ST_RTP);
			}
			find = sP2PUdpServer.find(":");
			if (find == std::string::npos)
			{
				tstring sTemp = m_serverAddr.getip();
				sTemp.append(":");
				sTemp.append(sP2PUdpServer);
				m_udpAddr = CCgcAddress(sTemp, CCgcAddress::ST_UDP);
			}else
			{
				m_udpAddr = CCgcAddress(sP2PUdpServer, CCgcAddress::ST_UDP);
			}

			m_bLoadSettingReturned = true;
		}break;
	case const_CallSign_AccountRegister:
		{
			// 登录成功
			if (resultValue == 0)
			{
				cgcParameter::pointer pUserName = response.getRecvParameter(_T("UserName"));
				if (pUserName.get() != NULL)
				{
					this->m_sCurrentUser = pUserName->getStr();
					m_handler->onUserLogined(m_sCurrentUser);
				}
			}
			return;
		}break;
	case const_CallSign_AccountUnRegister:
		{
			m_handler->onUserLogouted(m_sCurrentUser);
			m_sCurrentUser = _T("");
		}break;
	case const_CallSign_GetAllUser:
		{
			cgcParameter::pointer pUserId = response.getRecvParameter(_T("UserId"));
			cgcParameter::pointer pUserName = response.getRecvParameter(_T("FromUser"));
			if (pUserId.get() != NULL && pUserName.get() != NULL)
			{
				m_handler->onUserInfo(pUserId->getStr(), pUserName->getStr());
			}

		}break;
	case const_CallSign_RequestP2PUser:
	case const_CallSign_ResponseP2PUser:
	case const_CallSign_SendTextMessage:
		break;
	case const_CallSign_DisconnectP2PUser:
		{
			if (m_bDoAccountUnRegister)
				break;
			// From TCP/IP
			// P2P Disconnect Message, From Server
			tstring sFromUser = response.getRecvParameterValue(_T("FromUser"));
			long nP2PType = response.getRecvParameterValue(_T("P2PType"), 0);
			long nP2PParam = response.getRecvParameterValue(_T("P2PParam"), 0);

			char buffer[30];
			sprintf(buffer, ":%d-%d", nP2PType, nP2PParam);
			tstring sP2PKey(sFromUser);
			sP2PKey.append(buffer);
			CDoP2PClientHandler::pointer pP2PClient;
			if (m_p2pProxy.find(sP2PKey, pP2PClient, true))
			{
				//CDoP2PClientHandler * pClientHandler = (CDoP2PClientHandler*)pP2PClient.get();
				pP2PClient->clearP2PStatus();
				m_handler->onP2PUserDisconnect(pP2PClient);

				DoSotpClientHandler::pointer pDoHandler = pP2PClient->dohandler();
				BOOST_ASSERT(pDoHandler.get() != NULL);
				pDoHandler->doSetRemoteAddr(nP2PType == CDoP2PClientHandler::P2P_AUDIO || nP2PType == CDoP2PClientHandler::P2P_VIDEO
					? m_rtpAddr.address() : m_udpAddr.address());
				m_sotpClient.stopClient(pDoHandler);
			}
		}break;
	case const_CallSign_P2PAck:
		{
			// P2P ACK, From P2P user
			tstring sP2PAckAck = response.getRecvParameterValue(_T("P2PACKACK"));
			tstring sFromUser = response.getRecvParameterValue(_T("FromUser"));
			long nP2PType = response.getRecvParameterValue(_T("P2PType"), 0);
			long nP2PParam = response.getRecvParameterValue(_T("P2PParam"), 0);

			char buffer[30];
			sprintf(buffer, ":%d-%d", nP2PType, nP2PParam);
			tstring sP2PKey(sFromUser);
			sP2PKey.append(buffer);
			CDoP2PClientHandler::pointer pP2PClient;
			if (!m_p2pProxy.find(sP2PKey, pP2PClient, false))
				break;

			if (sP2PAckAck.compare(_T("1")) == 0)
			{
				pP2PClient->setRemoteP2PStatus(true);
			}else if (!sFromUser.empty())
			{
				if (pP2PClient->getLocalP2PStatus())
				{
					DoSotpClientHandler::pointer pDoHandler = pP2PClient->dohandler();
					BOOST_ASSERT(pDoHandler.get() != NULL);

					//pDoHandler->doSetRemoteAddr(destIp, destPort);
					//pDoHandler->doSetRemoteAddr(pP2PClient->getP2PAddress());
					for (int i=1; i<=2; i++)
						pDoHandler->doSendData((const unsigned char*)"p2ptest", 7);
					sendP2PAck(pP2PClient, nP2PType, nP2PParam, false);	// 对方请求打通本地状态
				}else
				{
					pP2PClient->setLocalP2PStatus(true);
					sendP2PAck(pP2PClient, nP2PType, nP2PParam, true);
				}
			}
		}break;
	default:
		{
		}break;
	}

}