📄 calldlg.cpp
字号:
// CallDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Chat.h"
#include "CallDlg.h"
#include "ProxyAuthDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define ID_TIMER_CONNECT 1000
/////////////////////////////////////////////////////////////////////////////
// CCallDlg dialog
CCallDlg::CCallDlg(CWnd* pParent /*=NULL*/)
: CDialog(CCallDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CCallDlg)
m_nPort = CHAT_PORT;
m_szServer = _T("127.0.0.1");
m_szCallTips = _T("等待");
m_bUseProxy = FALSE;
//}}AFX_DATA_INIT
m_pClientThread = NULL;
m_bState = CALL_ORIGIN;
m_bMode = FALSE; //不用代理
m_lpReceiveBuffer = NULL;
}
void CCallDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CCallDlg)
DDX_Control(pDX, IDC_CALL_PROGRESS, m_ctrlProgress);
DDX_Text(pDX, IDC_CALL_PORT, m_nPort);
DDV_MinMaxUInt(pDX, m_nPort, 1, 65535);
DDX_Text(pDX, IDC_CALL_SERVER, m_szServer);
DDV_MaxChars(pDX, m_szServer, 128);
DDX_Text(pDX, IDC_CALL_TIP, m_szCallTips);
DDV_MaxChars(pDX, m_szCallTips, 10);
DDX_Check(pDX, IDC_CALL_USEPROXY, m_bUseProxy);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CCallDlg, CDialog)
//{{AFX_MSG_MAP(CCallDlg)
ON_WM_TIMER()
ON_MESSAGE( WM_CALL_TIMEOUT, OnCallTimeOut )
ON_MESSAGE( WM_THREAD_QUIT, OnThreadQuit )
ON_MESSAGE( WM_THREAD_DATA, OnThreadData )
ON_MESSAGE( WM_THREAD_CONNECT, OnConnectOK )
ON_MESSAGE( SOCKET_THREAD_CONNECT, OnThreadConnect )
ON_MESSAGE( SOCKET_THREAD_RESOLVE, OnThreadResolve )
ON_MESSAGE( SOCKET_THREAD_WRITE, OnThreadWrite )
ON_MESSAGE( SOCKET_THREAD_TRANSFER, OnTransfer )
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCallDlg message handlers
BOOL CCallDlg::OnInitDialog()
{
m_hMainWnd = GetParent()->GetSafeHwnd();
CDialog::OnInitDialog();
// TODO: Add extra initialization here
m_ctrlProgress.ShowPercent( TRUE );
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CCallDlg::OnOK()
{
// TODO: Add extra validation here
//进行连接, 如果一切正常,结束对话框,开始下棋
UpdateData();
m_bMode = m_bUseProxy;
if( m_bState == CALL_ORIGIN )
{
//用户点击连接
//进行语法检查
//以及是否采用代理
if( m_szServer.IsEmpty() )
{
MessageBox( "主机不许为空,请输入主机名称或IP地址。", "错误", MB_OK|MB_ICONSTOP );
return;
}
//创建线程
ASSERT( m_pClientThread == NULL );
m_pClientThread = new CClientThread(m_szServer, m_nPort, m_bUseProxy, GetSafeHwnd(), m_hMainWnd );
if( m_pClientThread == NULL )
{
MessageBox("创建客户线程失败,请释放资源。", "错误", MB_OK|MB_ICONSTOP );
return;
}
//创建成功,启动它
m_pClientThread->CreateThread();
//启动记数器
SetTimer( ID_TIMER_CONNECT, 1000, NULL );
//设置按钮为取消
GetDlgItem( IDOK )->SetWindowText("取消" );
m_ctrlProgress.SetRange( 0, confChat.nWaitTime );
m_ctrlProgress.SetStep(1);
m_ctrlProgress.SetPos( 0 );
m_bState = CALL_CONNECTING;
}
else
{
//选择取消
if( m_pClientThread )
{
m_pClientThread->KillThread();
m_pClientThread = NULL;
}
m_bState = CALL_ORIGIN;
KillTimer( ID_TIMER_CONNECT );
CDialog::OnCancel();
}
}
void CCallDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if( nIDEvent == ID_TIMER_CONNECT )
{
//调整进度,并进行判断是否达到最大
m_ctrlProgress.StepIt();
if( (UINT)m_ctrlProgress.GetPos() == confChat.nWaitTime )
{
//ASSERT( m_bState == CALL_CONNECTING );
//Stop it
PostMessage( WM_CALL_TIMEOUT, 0, 0 );
}
}
CDialog::OnTimer(nIDEvent);
}
void CCallDlg::OnCallTimeOut(WPARAM wParam, LPARAM lParam)
{
//时间到
if( m_pClientThread )
{
m_pClientThread->KillThread();
m_pClientThread = NULL;
}
if( m_bState != CALL_ORIGIN )
{
GetDlgItem(IDOK)->SetWindowText("连接");
KillTimer( ID_TIMER_CONNECT );
m_ctrlProgress.SetPos( 0 );
m_bState = CALL_ORIGIN;
}
}
void CCallDlg::OnCancel()
{
if( m_bState != CALL_ORIGIN )
{
// 停止连接,退出
if( m_pClientThread )
{
m_pClientThread->KillThread();
m_pClientThread = NULL;
}
}
m_bState = CALL_ORIGIN;
CDialog::OnCancel();
}
void CCallDlg::OnThreadConnect( WPARAM wParam, LPARAM lParam )
{
//收到连接消息
// wParam是socket
// HIWORD(lParam)是错误码
// LOWORD(lParam)是消息,例如FD_CONNECT等
int nError=HIWORD(lParam);
//和Client线程保持同步
CSingleLock single( &g_cMutexClient );
single.Lock();
if( m_bState != CALL_CONNECTING ) return;
if( m_pClientThread == NULL ) return;
if( (SOCKET)wParam != m_pClientThread->GetSocket() ) return;
//连接成功
m_pClientThread->OnSocketConnect();
switch( nError )
{
case 0:
if( m_bMode == FALSE )
{
//已经连接好,不通过代理
KillTimer( ID_TIMER_CONNECT );
//等待线程发回 WM_THREAD_CONNECT消息
return;
}
//采用Proxy,准备接收数据
if( m_lpReceiveBuffer == NULL )
m_lpReceiveBuffer = (LPBYTE)GlobalAlloc( GPTR,
MAX_PACKET_SIZE*2 );
break;
case WSAECONNREFUSED:
//必须停止线程
KillTimer( ID_TIMER_CONNECT );
m_pClientThread->KillThread();
m_pClientThread = NULL;
MessageBox( "对方机器已经启动,但不能提供聊天服务。", "错误", MB_OK|MB_ICONSTOP );
break;
case WSAETIMEDOUT:
KillTimer( ID_TIMER_CONNECT );
m_pClientThread->KillThread();
m_pClientThread = NULL;
MessageBox( "您指定的主机无法连接,请重新输入。", "错误", MB_OK|MB_ICONSTOP );
break;
default:
CString szTemp;
KillTimer( ID_TIMER_CONNECT );
szTemp.Format( "SOCKET连接返回错误码:%d", nError );
MessageBox( szTemp, "错误", MB_OK|MB_ICONSTOP );
m_pClientThread->KillThread();
m_pClientThread = NULL;
break;
}
}
void CCallDlg::OnThreadQuit( WPARAM wParam, LPARAM lParam )
{
//收到退出消息
int nError = LOWORD(lParam);
//和Client线程保持同步
CSingleLock single( &g_cMutexClient );
single.Lock();
if( !wParam )
{
//错误
//ASSERT( m_pClientThread != NULL );
KillTimer( ID_TIMER_CONNECT );
if( m_pClientThread )
{
m_pClientThread->KillThread();
m_pClientThread = NULL;
}
//m_pClientThread=NULL;
GetDlgItem(IDOK)->SetWindowText("连接");
m_ctrlProgress.SetPos(0);
m_bState = CALL_ORIGIN;
switch( nError )
{
case SOCKET_ERROR_REFUSE:
MessageBox( "对方机器已经启动,但不能提供聊天服务。", "错误", MB_OK|MB_ICONSTOP );
break;
case SOCKET_ERROR_TIMEOUT:
MessageBox( "您指定的主机无法连接,请重新输入。", "错误", MB_OK|MB_ICONSTOP );
break;
default: break;
}
}
}
void CCallDlg::OnThreadResolve(WPARAM wParam, LPARAM lParam )
{
//得到解析消息
if( m_pClientThread )
{
m_pClientThread->OnSocketConnect();
}
}
void CCallDlg::OnThreadWrite( WPARAM wParam, LPARAM lParam )
{
//发送连接请求,然后等候响应
//读入数据进行分析后,在进行判断
int bSuccess = (int)wParam;
int nResult = (int)lParam;
if( bSuccess == TRUE ) return;
switch( nResult )
{
case SOCKET_ERROR_NOERROR:
//发送成功,等候数据
m_bState = CALL_WAITING;
break;
case SOCKET_ERROR_RESET:
MessageBox( "传输通道重置,放弃连接。", "错误", MB_OK|MB_ICONSTOP );
m_bState = CALL_CONNECTED;
OnCancel();
break;
case SOCKET_ERROR_CLOSE:
MessageBox("传输通道异常关闭,放弃连接。", "错误", MB_OK|MB_ICONSTOP );
m_bState = CALL_CONNECTED;
OnCancel();
break;
default:
MessageBox("发送数据时发生错误。", "错误", MB_OK|MB_ICONSTOP );
m_bState = CALL_CONNECTED;
OnCancel();
break;
}
}
void CCallDlg::OnTransfer(WPARAM wParam, LPARAM lParam )
{
//收到FD_READ,FD_WRITE,FD_CLOSE的消息
int nError = HIWORD(lParam);
int nMessage=LOWORD(lParam);
//和Client线程保持同步
CSingleLock single( &g_cMutexClient );
single.Lock();
if( m_pClientThread == NULL ) return;
if( wParam == m_pClientThread->GetSocket() )
{
if( nError == 0 )
{
if( nMessage == FD_READ )
{
::PostThreadMessage( m_pClientThread->m_nThreadID,
SOCKET_THREAD_READ, 0, 0 );
}
else if(nMessage == FD_WRITE )
{
::PostThreadMessage( m_pClientThread->m_nThreadID,
SOCKET_THREAD_WRITE, 0, 0 );
}
else if( nMessage == FD_CLOSE )
{
//代理把网络关闭了
if( m_bState == CALL_WAITING )
{
//还没读出数据就关了
MessageBox("代理服务器关闭了网络连接,请重试。", "错误", MB_OK|MB_ICONSTOP );
}
if( m_pClientThread )
{
m_pClientThread->KillThread();
m_pClientThread = NULL;
}
m_bState = CALL_ORIGIN;
m_ctrlProgress.SetPos(0);
KillTimer( ID_TIMER_CONNECT );
GetDlgItem(IDOK)->SetWindowText("连接" );
}
}
}
}
void CCallDlg::OnThreadData(WPARAM wParam, LPARAM lParam )
{
//收到线程发来的数据读消息
//处理代理服务器发来的响应
int nBytes = (int)wParam;
LPCTSTR lpTemp = (LPCTSTR)m_lpReceiveBuffer;
CProxyAuthDlg *pDlg = NULL;
int nResult;
CString szPassword;
char pBaseCode[512];
//和Client线程保持同步
CSingleLock single( &g_cMutexClient );
single.Lock();
memcpy( m_lpReceiveBuffer, (LPBYTE)lParam, nBytes );
//应该是 HTTP 200 OK就好了
//可以考虑重新挂接消息
////////////////////////////////////////////////
///////// HTTP 200
///////// 已经连接好了
////////////////////////////////////////////////
if( strstr( lpTemp, "HTTP/1.0 200 ") != NULL )
{
if( confChat.bProxyUsable == PROXY_AUTH_UNSET )
{
confChat.bProxyUsable = PROXY_AUTH_NOPASS;
}
else confChat.bProxyUsable = PROXY_AUTH_SETPASS;
//本次连接就可以用
//重新挂接网络消息
if( m_pClientThread )
{
nResult = m_pClientThread->ChangeHandle();
if( nResult == FALSE )
{
m_bState = CALL_DISCONNECT;
MessageBox("不能和窗口绑定网络消息,请重新连接。", "错误", MB_OK|MB_ICONSTOP );
OnCancel();
return;
}
if( m_lpReceiveBuffer ) GlobalFree( m_lpReceiveBuffer );
CDialog::OnOK();
}
return ;
}
////////////////////////////////////////////////
///////// HTTP 407
///////// 要口令
////////////////////////////////////////////////
if( strstr( lpTemp, "HTTP/1.0 407 ") != NULL )
{
pDlg = new CProxyAuthDlg;
if( pDlg != NULL )
{
//记忆上次输入的内容
pDlg->m_szUserName = confChat.szProxyUser;
pDlg->m_szProxy = confChat.szProxyIP;
nResult = pDlg->DoModal();
if( nResult != IDOK )
{
delete pDlg;
return ;
}
//用局部变量保存起来
confChat.szProxyUser = pDlg->m_szUserName;
szPassword = pDlg->m_szPass;
confChat.bProxyUsable = PROXY_AUTH_SETTING;
delete pDlg;
// 提交密码后,再次连接
// 进行BASE64编码
memset( pBaseCode ,0, 512 );
HTTPAuth( (LPSTR)(LPCTSTR)confChat.szProxyUser, (LPSTR)(LPCTSTR)szPassword, pBaseCode );
confChat.szProxyPass.Format( "%s", pBaseCode );
// 再次连接远程服务
//首先中断线程,再启动一个新的
if( m_pClientThread != NULL )
{
m_pClientThread->KillThread();
m_pClientThread = NULL;
}
m_pClientThread = new CClientThread(m_szServer, m_nPort, m_bUseProxy, GetSafeHwnd(), m_hMainWnd );
if( m_pClientThread == NULL )
{
MessageBox("创建客户线程失败,请释放资源。", "错误", MB_OK|MB_ICONSTOP );
return;
}
//创建成功,启动它
m_pClientThread->CreateThread();
m_bState = CALL_CONNECTING;
//重新记数
KillTimer( ID_TIMER_CONNECT );
m_ctrlProgress.SetPos(0);
SetTimer( ID_TIMER_CONNECT, 1000, NULL );
GetDlgItem( IDOK )->SetWindowText("取消");
return;
}
OnCancel();
return;
}
////////////////////////////////////////////////
///////// HTTP 403
///////// 被禁止
////////////////////////////////////////////////
if( strstr( lpTemp, "HTTP/1.0 403 ") != NULL )
{
MessageBox("您的连接请求被代理服务器拒绝,请重新连接。", "错误", MB_OK|MB_ICONSTOP );
m_bState = CALL_CONNECTING;
OnCancel();
return;
}
//MessageBox("您的连接请求代理服务器认为无效,请联系网络管理员。", "错误", MB_OK|MB_ICONSTOP );
//m_bState = CALL_CONNECTING;
//OnCancel();
//return;
}
void CCallDlg::HTTPAuth(char *uid, char *pass, char *outbuf)
{
char temp[512];
char buf[256];
int ret = -1;
memset(buf,0,256);
memset(temp,0,512);
memcpy(buf,uid,strlen(uid));
memcpy(buf+strlen(uid),":",1);
memcpy(buf+strlen(uid)+1,pass,strlen(pass));
Base64Code(buf,temp);
strcpy(outbuf,HTTP_AUTH_HEAD);
strcat(outbuf+strlen(HTTP_AUTH_HEAD),temp);
ret = strlen(outbuf) ;
}
void CCallDlg::Base64Code(char *inbuf, char *outbuf)
{
int ret = -1 ;
int i = 0 ;
int remain;
int oneout;
int num;
int c = 0 ;
int now;
char CODETABLE[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
if ( *inbuf <= 0 )
{
goto end;
}
num = 8 ;
remain = *inbuf;
oneout = 0 ;
now = 0 ;
while ( 1 )
{
while ( num >= 6 )
{
oneout = ( remain >> (num-6) ) & 0x3f ;
memcpy( outbuf+now, &CODETABLE[oneout] , 1 );
now++;
num -=6;
if ( num == 2 )
c = 0x0300;
else
if ( num == 4 )
c = 0x0f00;
else
if ( num == 6 )
c = 0x3f00;
else
c = 0x0000;
if ( num != 6 )
remain = ( remain <<8 ) & c ;
}
if ( *(++inbuf)==NULL )
break;
if ( num == 2 )
c = 0x03ff;
else
if ( num == 4 )
c = 0x0fff;
else
c = 0x00ff;
remain = ( remain | ( *inbuf & 0x00ff ) ) & c ;
num+=8;
}
if ( ( num < 6 ) && ( num != 0 ) )
{
remain = remain >> 8 ;
remain = ( remain <<( 6 - num )) & 0x00003f;
memcpy( outbuf+now, &CODETABLE[remain] , 1 ) ;
now++;
memcpy( outbuf+now, "==" , 6/2 - num/2 ) ;
now +=6/2 - num/2;
}
ret = 0 ;
end:
return;
}
void CCallDlg::OnConnectOK(WPARAM wParam, LPARAM lParam)
{
//和Client线程保持同步
CSingleLock single( &g_cMutexClient );
single.Lock();
if( m_bState != CALL_CONNECTING ) return;
m_bState = CALL_CONNECTED;
//如果有Proxy,连通不算真正能用
if( m_bMode == TRUE ) return;
//已经收到连接好的消息
if( m_lpReceiveBuffer != NULL )
{
GlobalFree( m_lpReceiveBuffer );
m_lpReceiveBuffer = NULL;
}
m_bState = CALL_CONNECTED;
CDialog::OnOK();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -