This is the last post in the series about how to install and use libraries needed to do SSH communication from a wxWidgets application, on Windows, using the MinGW compiler system.
In previous posts, we have looked at:
In this post, we will learn how to combine the components that we have built so far. We will build on the Hello World example in the previous post to develop a simple application to read the response from a remote machine given a command through SSH.
The application is based on a wxFrame which holds two menus. One "Help" menu contain the common "About" entry which displays information about the application in a dialog. The other menu, the "File" menu, contains two entries; One entry to quit the application and one entry to send a command to a remote server through SSH.
When the user clicks the "Execute command remotely..." menu entry, a serie of dialogs to retrieve information from the user are displayed. There is no error checking performed here so be advised to rearrange this as you see fit. When the user has supplied the command to execute, the IP number of the remote machine and user login credentials, a SSH connection is established to execute the command. Any output from the command is collected and finally displayed in a message box.
The source code for the example is displayed below.
// wxWidgets + ssh example program // Executing a command on a remote machine through ssh and displays any // output in a message box. // This source code is dedicated to the public domain. // @author Peter Jansson http://www.p-jansson.com // @date 2012-09-30 // // For compilers that support precompilation, includes "wx/wx.h". #include <wx/wxprec.h> #ifndef WX_PRECOMP #include <wx/wx.h> #endif // For libssh2 functionality. #include <libssh2.h> #include <winsock2.h> // For std::auto_ptr #include <memory> class wxSshApp: public wxApp { public: virtual bool OnInit(); }; class wxSshFrame: public wxFrame { public: wxSshFrame(); private: // Do the requested action to execute // a remote command and display the // response. This is the method that // contain all the SSH logic we will // use. void OnExecute(wxCommandEvent&); void OnExit(wxCommandEvent&); void OnAbout(wxCommandEvent&); wxDECLARE_EVENT_TABLE(); }; enum { ID_EXE = 1 }; wxBEGIN_EVENT_TABLE(wxSshFrame, wxFrame) EVT_MENU(ID_EXE, wxSshFrame::OnExecute) EVT_MENU(wxID_EXIT, wxSshFrame::OnExit) EVT_MENU(wxID_ABOUT, wxSshFrame::OnAbout) wxEND_EVENT_TABLE() wxIMPLEMENT_APP(wxSshApp); bool wxSshApp::OnInit() { wxSshFrame *frame = new wxSshFrame; frame->Show( true ); return true; } wxSshFrame::wxSshFrame() : wxFrame(NULL, wxID_ANY, "wxSSH") { wxMenu *menuFile = new wxMenu; menuFile->Append(ID_EXE, "&Execute command remotely...\tCtrl-E", "Execute command remotely."); menuFile->AppendSeparator(); menuFile->Append(wxID_EXIT); wxMenu *menuHelp = new wxMenu; menuHelp->Append(wxID_ABOUT); wxMenuBar *menuBar = new wxMenuBar; menuBar->Append( menuFile, "&File" ); menuBar->Append( menuHelp, "&Help" ); SetMenuBar( menuBar ); CreateStatusBar(); SetStatusText( "Welcome to wxSSH!" ); } void wxSshFrame::OnExit(wxCommandEvent&) { Close( true ); } void wxSshFrame::OnAbout(wxCommandEvent&) { wxMessageBox( "This is an example wxWidgets' program for\n" "executing a command on a remote machine\n" "through ssh.", "About wxSSH", wxOK | wxICON_INFORMATION ); } void wxSshFrame::OnExecute(wxCommandEvent&) { const wxString Command = wxGetTextFromUser("Please enter command to execute."); SetStatusText( "Command set: " + Command ); const wxString remote_ip = wxGetTextFromUser("Please enter IP address of remote machine."); SetStatusText( "Remote machine IP address set: " + remote_ip ); const wxString user = wxGetTextFromUser("Please enter remote user name."); const wxString passwd = wxGetPasswordFromUser("Please enter password of remote user."); // We now have the user, password and remote command to execute, // let's actually do it. // We use the libssh2 library to execute the command through SSH. // First, we need to startup a socket. std::auto_ptr<wxBusyCursor> wait(new wxBusyCursor); WSADATA wsadata; WSAStartup(MAKEWORD(2,0), &wsadata); int rc = libssh2_init(0); if (rc != 0) { SetStatusText("libssh2 initialization failed!"); return; } int sock = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(22); sin.sin_addr.s_addr = inet_addr(remote_ip.c_str()); if(connect(sock,(struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) { SetStatusText("Failed to connect!"); return; } // Create a libssh2 session instance, startup and authenticate. LIBSSH2_SESSION* session = libssh2_session_init(); if(!session) return; if( 0 > libssh2_session_startup(session,sock) ) { SetStatusText("Could not startup the SSH communication" " session."); return; } if( libssh2_userauth_password(session,user.c_str(),passwd.c_str()) ) { SetStatusText("Access denied"); return; } LIBSSH2_CHANNEL* ch = libssh2_channel_open_session(session); if( NULL == ch ) { SetStatusText("Could not open SSH communication channel."); return; } // Execute the command in blocking style. libssh2_channel_set_blocking(ch,1); if( -1 == libssh2_channel_exec(ch,Command.c_str())) { SetStatusText("Failed to execute command."); return; } // Get rid of the busy cursor. wait.reset(); SetStatusText("Command executed successfully."); // Read the reponse from the remote machine. char buf[1024]; int num_of_read_bytes; wxString response("Response:\n"); do { num_of_read_bytes = libssh2_channel_read(ch,buf,1024); response.Append(buf,num_of_read_bytes); } while(1==libssh2_poll_channel_read(ch,0) || 1024==num_of_read_bytes ); // Clean up allocated libssh2 resources. libssh2_channel_close(ch); libssh2_channel_free(ch); libssh2_session_disconnect(session,"Goodbye."); libssh2_session_free(session); closesocket(sock); libssh2_exit(); // Display the respone from the remote machine. wxMessageBox(response,"Remote response"); }
To build this example using the libraries we have built in the previous posts, the following Makefile can be used. The source code above should be saved in a file called wxSSH.cpp.
# Directories where the library components are installed,
# modifiy according to your setup.
WX=C:/wxWidgets-2.9.4
SSH2=C:/libssh2-1.4.2
OPENSSL=C:/openssl-1.0.1c
CXXFLAGS += -I$(WX)/include -I$(WX)/lib/gcc_lib/mswu \
-I$(SSH2)/include
WIN_LIBS = -lgdi32 -lcomdlg32 -lwinspool -lwinmm \
-lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -lwsock32 -lodbc32
LDFLAGS += -L$(WX)/lib/gcc_lib \
-lwxmsw29u_core -lwxbase29u -lwxexpat -lwxpng -lwxzlib \
-L$(SSH2)/win32 -lssh2 \
-L$(OPENSSL)/out -lssl -lssl32 -lcrypto -leay32 \
$(WIN_LIBS)
default: wxSSH.exe
wxSSH.exe: wxSSH.cpp
$(CXX) -o $@ $< $(CXXFLAGS) \
-Wl,--subsystem,windows -mwindows $(LDFLAGS)
An executable application wxSSH.exe will be built using the following command:
mingw32-make default
Executing wxSSH on my machine and connecting to a remote Linux machine to execute the command uptime yields the following display on my screen:
This is it! This was the end of this blog series. If you followed all posts you will now be able to build your own wxWidgets applications with SSH functionality built in. :)

Thanks for your grateful informations, this blogs will be really help for Tutorial.
ReplyDelete