// RTSPExTestDlg.cpp : implementation file // #include "stdafx.h" #include "RTSPExTest.h" #include "RTSPExTestDlg.h" #include "our_md5.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CRTSPExTestDlg dialog CRTSPExTestDlg::CRTSPExTestDlg(CWnd* pParent /*=NULL*/) : CDialog(CRTSPExTestDlg::IDD, pParent) { //{{AFX_DATA_INIT(CRTSPExTestDlg) m_strExtCmd = _T(""); m_strIP = _T("192.168.13.4"); m_uPort = 554; m_strExtRes = _T(""); //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_bSetup = FALSE; } void CRTSPExTestDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CRTSPExTestDlg) DDX_Control(pDX, IDC_CHK_CONNECT, m_btnConnect); DDX_Control(pDX, IDC_CB_OP, m_cbOperation); DDX_Control(pDX, IDC_CB_NAME, m_cbName); DDX_Control(pDX, IDC_CB_KEYWORD, m_cbKeyword); DDX_Control(pDX, IDC_CB_CMD, m_cbCmd); DDX_Text(pDX, IDC_EDIT_EXT_CMD, m_strExtCmd); DDX_Text(pDX, IDC_EDT_IP, m_strIP); DDX_Text(pDX, IDC_EDT_PORT, m_uPort); DDX_Text(pDX, IDC_EDIT_EXT_RESPONSE, m_strExtRes); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CRTSPExTestDlg, CDialog) //{{AFX_MSG_MAP(CRTSPExTestDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BTN_SEND_CMD, OnBtnSendCmd) ON_WM_DESTROY() ON_BN_CLICKED(IDC_BTN_CLEAR, OnBtnClear) ON_CBN_SELCHANGE(IDC_CB_CMD, OnSelchangeCbCmd) ON_EN_CHANGE(IDC_EDIT_EXT_CMD, OnChangeEditExtCmd) ON_CBN_SELCHANGE(IDC_CB_OP, OnSelchangeCbOp) ON_CBN_SELCHANGE(IDC_CB_KEYWORD, OnSelchangeCbKeyword) ON_CBN_SELCHANGE(IDC_CB_NAME, OnSelchangeCbName) ON_BN_CLICKED(IDC_CHK_CONNECT, OnChkConnect) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CRTSPExTestDlg message handlers BOOL CRTSPExTestDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here m_uSock = 0; WSAData WsaData; WSAStartup(MAKEWORD(2,2), &WsaData); m_cbCmd.AddString("EXT_CMD"); m_cbCmd.AddString("EXT_SUBSESSION_CMD"); m_cbOperation.AddString("GET"); m_cbOperation.AddString("SET"); return TRUE; // return TRUE unless you set the focus to a control } void CRTSPExTestDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CRTSPExTestDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CRTSPExTestDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } #define MAX_STR_LENGTH 32 #define MAX_KEYWORD_COUNT 32 #define MAX_NAME_COUNT 32 #define MAX_AUTH_STR_LENGTH 1024 typedef struct _KEYWORD_TABLE { char szKeyword[MAX_STR_LENGTH]; char szName[MAX_NAME_COUNT][MAX_STR_LENGTH]; } KEYWORD_TABLE; KEYWORD_TABLE g_ExtKeywordTable[MAX_KEYWORD_COUNT] = { { "EXT_CMD_SPEC", { "client_version", "server_version" } }, { "SYSTEM_INFO", { "cpu_usage", "traffic_info" } }, { "HARDWARE_INFO", { "firmware_version", "hw_revision", "model_id", "max_video_ch", "max_audio_ch", "max_video_out_ch", "max_video_loopback_ch", "max_audio_out_ch", "max_di", "max_do", "max_serial_port", "has_factory_default", "has_watchdog", "has_rtc", "usn", "user_region", "information_string" } }, { "NETWORK", { "mode", "ipaddr", "subnetmask", "gateway", "dns1", "dns2", "pppoe_id", "pppoe_pswd", "time_mode", "ntp_server", "ntp_update", "rtsp_port", "timeout", "packet_size", "padding" } }, { "QOS", { "video_dscp", "audio_dscp", "event_dscp" } }, { "SYSTEM_MGR", { "system_name", "time", "login_mode", "save_mode", "server_mode", "timezone" } }, { "CMD_REBOOT", { "reboot", "factory_default" } }, { "DAYLIGHT_SAVING_TIME", { "enable", "offset", "start_day", "start_month", "start_time", "start_type_of_date", "stop_day", "stop_month", "stop_time", "stop_type_of_date" } }, { "SERIAL_PORT", { "portid", "baudrate", "databits", "parity", "stopbit", "flow_control" } }, { "SERIAL_DATA", { "portid", "mode", "data" } }, { "DI", { "ch", "on" } }, { "DO", { "ch", "on" } }, { "WATCHDOG", { "enable", "timeout" } }, { "VIDEO_OUT", { "ch", "outch" } }, { "VIDEO_LOOPBACK", { "ch", "enable" } }, { "DDNS", { "address", "user_id", "user_pw", "update_time", "dns_name" } }, { "ADD_USER", { "name", "password", "access_level" } }, { "DEL_USER", { "name" } }, { "USER_INFO", { "name", "password", "access_level" } }, { "USER_LIST", { "count", "list" } }, { "CONNECTION_LIST", { "count", "list" } }, { "STORAGE", { "type", "command" } }, { "EVENT_NOTIFICATION", { "event_id", "event_type", "dst_type", "dst_url" } }, }; KEYWORD_TABLE g_ExtSubKeywordTable[MAX_KEYWORD_COUNT] = { { "VIDEO_INFO", { "name" } }, { "VIDEO_FORMAT", { "tv_mode", "tv_standard", "defined_imagesize", "width", "height" } }, { "FRAME_RATE", { "method", "fps1000", "skip_frame", "max_fps" } }, { "BITRATE", { "mode", "cbr_bitrate", "vbr_quant", "vbr_quant_i", "vbr_quant_b", "vbr_quant_p" } }, { "VIDEO_CODEC", { "type", "gop_size", "noisefilter", "profile_level" } }, { "VIDEO_COLOR_ATTR", { "brightness", "contrast", "saturation", "hue" } }, { "VIDEO_STATUS", { "on" } }, { "VIDEO_SNAPSHOT", { "enable" } }, { "RTP_MULTICAST", { "type", "enable", "address", "port", "ttl" } }, { "AUDIO_IN", { "enable", "stream_type", "sample_rate", "data_bits", "channels", "gain" } }, { "AUDIO_OUT", { "owner", "enable", "stream_type", "sample_rate", "data_bits", "channels", "gain", "data" } }, { "MOTION_DETECTION_PROPERTY", { "max_layer_count", "area_type_list" } }, { "MOTION_DETECTION", { "layer_id", "enable", "activity", "threshold", "area_type", "area_count", "rect_id", "rc_x", "rc_y", "rc_width", "rc_height" } }, { "OSD_STRING", { "enable", "method", "x", "y", "string", "color" } }, { "OSD_TIME", { "enable", "format", "x", "y" } }, { "RECORD", { "enable", "type", "path" } }, { "ENCRYPTION", { "video_encryption_mode", "video_encryption_key", "video_encryption_type", "video_encryption_size", "audio_encryption_mode", "audio_encryption_type", "audio_encryption_size" } }, }; void CRTSPExTestDlg::SetKeyword(ULONG uIndex) { if (uIndex == 0) { for (ULONG i=0; i::)::md5(:)) // or, if "fPasswordIsMD5" is True: // md5(::md5(:)) char ha1Buf[33]; if (0) { strncpy(ha1Buf, password, 32); ha1Buf[32] = '\0'; // just in case } else { unsigned const ha1DataLen = strlen(username) + 1 + strlen(realm) + 1 + strlen(password); unsigned char* ha1Data = new unsigned char[ha1DataLen+1]; sprintf((char*)ha1Data, "%s:%s:%s", username, realm, password); our_MD5Data(ha1Data, ha1DataLen, ha1Buf); delete[] ha1Data; } unsigned const ha2DataLen = strlen(cmd) + 1 + strlen(url); unsigned char* ha2Data = new unsigned char[ha2DataLen+1]; sprintf((char*)ha2Data, "%s:%s", cmd, url); char ha2Buf[33]; our_MD5Data(ha2Data, ha2DataLen, ha2Buf); delete[] ha2Data; unsigned const digestDataLen = 32 + 1 + strlen(nonce) + 1 + 32; unsigned char* digestData = new unsigned char[digestDataLen+1]; sprintf((char*)digestData, "%s:%s:%s", ha1Buf, nonce, ha2Buf); char const* result = our_MD5Data(digestData, digestDataLen, NULL); delete[] digestData; return result; } void CRTSPExTestDlg::MakeAuthenticationString(char *pResponse, char *pAuthStr) { char *pszCmd = strstr(pResponse, "WWW-Authenticate"); char realm[128], nonce[128], url[128]; sprintf(url, "/"); /*if (m_uPort == 554) { sprintf(url, "rtsp://%s", (LPSTR)(LPCSTR)m_strIP); } else { sprintf(url, "rtsp://%s:%d", (LPSTR)(LPCSTR)m_strIP, m_uPort); }*/ ZeroMemory(realm, sizeof(realm)); ZeroMemory(nonce, sizeof(nonce)); sscanf(pszCmd, "WWW-Authenticate: Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce); //sscanf(pszCmd, "WWW-Authenticate: Basic realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce); char const* response = computeDigestResponse("root", "pass", realm, nonce, "DESCRIBE", url); sprintf(pAuthStr, "Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", //sprintf(auth, "Authorization: Basic username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", "root", realm, nonce, url, response); free((char*)response); } #define MAX_RESPONSE_LENGTH 4096 void CRTSPExTestDlg::OnBtnSendCmd() { // TODO: Add your control notification handler code here char szResponse[MAX_RESPONSE_LENGTH]; char szRequest[1024]; if (m_cbCmd.GetCurSel() == 1 && !m_bSetup) { sprintf(szRequest, "SETUP /%s RTSP/1.0\r\nCSeq: 1\r\nTransport: RTP/AVP;unicast\r\n\r\n", m_szTrackID); if (send(m_uSock, (LPSTR)(LPCSTR)szRequest, strlen(szRequest), 0) == SOCKET_ERROR) { MessageBox("Cannot send SETUP command"); return; } ZeroMemory(szResponse, MAX_RESPONSE_LENGTH); if (recv(m_uSock, szResponse, MAX_RESPONSE_LENGTH, 0) == SOCKET_ERROR) { MessageBox("Cannot receive response"); return; } char *pFoundStr = strstr(szResponse, "200 OK"); if (!pFoundStr) { m_strExtRes = szResponse; UpdateData(FALSE); return; } m_bSetup = TRUE; } ULONG uLen = m_strExtCmd.GetLength(); if (m_strExtCmd.Right(4) != "\r\n\r\n") { m_strExtCmd += "\r\n\r\n"; } if (send(m_uSock, (LPSTR)(LPCSTR)m_strExtCmd, m_strExtCmd.GetLength(), 0) == SOCKET_ERROR) { MessageBox("Cannot send command"); return; } ZeroMemory(szResponse, MAX_RESPONSE_LENGTH); if (recv(m_uSock, szResponse, MAX_RESPONSE_LENGTH, 0) == SOCKET_ERROR) { MessageBox("Cannot receive response"); return; } m_strExtRes = szResponse; UpdateData(FALSE); } void CRTSPExTestDlg::OnDestroy() { CDialog::OnDestroy(); // TODO: Add your message handler code here if (m_uSock) { closesocket(m_uSock); } WSACleanup(); } void CRTSPExTestDlg::OnBtnClear() { // TODO: Add your control notification handler code here m_strExtCmd = ""; m_strExtRes = ""; m_cbCmd.SetCurSel(-1); m_cbOperation.SetCurSel(-1); m_cbKeyword.SetCurSel(-1); m_cbName.SetCurSel(-1); UpdateData(FALSE); } void CRTSPExTestDlg::OnSelchangeCbCmd() { // TODO: Add your control notification handler code here if (m_cbCmd.GetCurSel() == 0) { m_strExtCmd += "EXT_CMD / RTSP/1.0\r\nCSeq: 1\r\nCmdCount: 1"; }else{ m_strExtCmd += "EXT_SUBSESSION_CMD /"; m_strExtCmd += m_szTrackID; m_strExtCmd += " RTSP/1.0\r\nCSeq: 1\r\nCmdCount: 1"; } m_cbKeyword.ResetContent(); SetKeyword(m_cbCmd.GetCurSel()); UpdateData(FALSE); } void CRTSPExTestDlg::OnChangeEditExtCmd() { // TODO: If this is a RICHEDIT control, the control will not // send this notification unless you override the CDialog::OnInitDialog() // function and call CRichEditCtrl().SetEventMask() // with the ENM_CHANGE flag ORed into the mask. // TODO: Add your control notification handler code here UpdateData(TRUE); } void CRTSPExTestDlg::OnSelchangeCbOp() { // TODO: Add your control notification handler code here if (m_cbOperation.GetCurSel() == 0) { m_strExtCmd += "\r\nGET "; }else{ m_strExtCmd += "\r\nSET "; } UpdateData(FALSE); } void CRTSPExTestDlg::OnSelchangeCbKeyword() { // TODO: Add your control notification handler code here char szKeyword[MAX_STR_LENGTH]; m_cbKeyword.GetLBText(m_cbKeyword.GetCurSel(), szKeyword); m_cbName.ResetContent(); if (m_cbCmd.GetCurSel() == 0) { SetExtName(szKeyword); }else{ SetExtSubName(szKeyword); } m_strExtCmd += szKeyword; m_strExtCmd += " "; UpdateData(FALSE); } void CRTSPExTestDlg::OnSelchangeCbName() { // TODO: Add your control notification handler code here char szName[MAX_STR_LENGTH]; m_cbName.GetLBText(m_cbName.GetCurSel(), szName); m_strExtCmd += szName; UpdateData(FALSE); } void CRTSPExTestDlg::OnChkConnect() { // TODO: Add your control notification handler code here char szResponse[MAX_RESPONSE_LENGTH]; char szRequest[1024]; char szIP[32]; char szCh[8]; if (m_btnConnect.GetCheck()) { UpdateData(TRUE); m_uSock = socket(AF_INET, SOCK_STREAM, 0); if (m_uSock == SOCKET_ERROR) { MessageBox("Cannot create socket"); return; } szCh[0] = 0; ZeroMemory(m_szTrackID, sizeof(m_szTrackID)); strcpy(szIP, (LPSTR)(LPCSTR)m_strIP); char *pFoundStr = strstr(szIP, "/"); if (pFoundStr) { strcpy(szCh, &pFoundStr[1]); pFoundStr[0] = 0; } memset(&m_ServerAddr, 0, sizeof(m_ServerAddr)); m_ServerAddr.sin_family = AF_INET; m_ServerAddr.sin_addr.s_addr = inet_addr(szIP); m_ServerAddr.sin_port = htons(m_uPort); if (connect(m_uSock, (struct sockaddr*)&m_ServerAddr, sizeof(m_ServerAddr)) == SOCKET_ERROR) { MessageBox("Cannot connect to server"); return; } SetDlgItemText(IDC_CHK_CONNECT, "Disconnect"); sprintf(szRequest, "DESCRIBE /%s RTSP/1.0\r\nCSeq: 1\r\nAccept: application/sdp\r\n\r\n", szCh); if (send(m_uSock, (LPSTR)(LPCSTR)szRequest, strlen(szRequest), 0) == SOCKET_ERROR) { MessageBox("Cannot send SETUP command"); return; } ZeroMemory(szResponse, MAX_RESPONSE_LENGTH); if (recv(m_uSock, szResponse, MAX_RESPONSE_LENGTH, 0) == SOCKET_ERROR) { MessageBox("Cannot receive response"); return; } char *pszCmd = strstr(szResponse, "WWW-Authenticate"); char szAuthStr[MAX_AUTH_STR_LENGTH]; if (pszCmd) { MakeAuthenticationString(szResponse, szAuthStr); sprintf(szRequest, "DESCRIBE /%s RTSP/1.0\r\nCSeq: 1\r\nAccept: application/sdp\r\n%s\r\n\r\n", szCh, szAuthStr); send(m_uSock, (LPSTR)(LPCSTR)szRequest, strlen(szRequest), 0); recv(m_uSock, szResponse, MAX_RESPONSE_LENGTH, 0); } pFoundStr = strstr(szResponse, "EVENT-NVE"); if (!pFoundStr) { m_szTrackID[0] = 0; return; } pFoundStr = strstr(pFoundStr, "track"); if (szCh[0]) { strcpy(m_szTrackID, szCh); strcat(m_szTrackID, "/"); strncat(m_szTrackID, pFoundStr, 6); } else { strncpy(m_szTrackID, pFoundStr, 6); } }else{ if (m_uSock) { closesocket(m_uSock); m_uSock = 0; } OnBtnClear(); m_bSetup = FALSE; SetDlgItemText(IDC_CHK_CONNECT, "Connect"); } }