From 2cde1c04f4f9e05f78d8a0775457e28ac0acacfb Mon Sep 17 00:00:00 2001 From: lsv Date: Tue, 17 Mar 2026 11:57:33 +0500 Subject: [PATCH] Auto execute plugin puttyforward for linux. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit При наличии такого плагина: ``` ; SSH (Unix): tunnel putty forward ; Title=[Putty tunnel forward] Command=putty -load "$$TITLE" appliesto=puttyforward Description=Putty forward tunnel from local port. KeyFile= Platform=unix ServerType=postgresql Database=No SetPassword=No ; ``` При попытке подключения к БД если существует конфигурация туннеля описанного в putty то будет проверятся наличие открытого порта на localhost и если он закрыт то запускается выше указанный плагин для организации туннеля. --- frm/frmMain.cpp | 29 +++++++++++++++++++++++--- frm/plugins.cpp | 16 ++++++++------ include/schema/pgServer.h | 7 +++++++ include/utils/misc.h | 1 + utils/misc.cpp | 44 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 9 deletions(-) diff --git a/frm/frmMain.cpp b/frm/frmMain.cpp index 12db8ef..fd52c91 100644 --- a/frm/frmMain.cpp +++ b/frm/frmMain.cpp @@ -267,8 +267,12 @@ frmMain::frmMain(const wxString &title) browser->SetFocus(); wxString selServerName=settings->Read(wxT("Servers/SelectItem"), ""); if (selServerName.Len()>0) { - wxTreeItemId sel=browser->FindItem(root,selServerName,true); - if (sel.IsOk()) browser->SelectItem(sel); + wxTreeItemId sel=browser->FindItem(root,selServerName,false); + if (sel.IsOk()) { + browser->SelectItem(sel); + currentObject=browser->GetObject(sel); + //execSelChange(sel, true); + } } @@ -1148,6 +1152,25 @@ wxTreeItemId frmMain::RestoreEnvironment(pgServer *server) int frmMain::ReconnectServer(pgServer *server, bool restore) { + if (server->GetPuttyTunnel()) { + // check open port + int port=server->GetPort(); + wxString localhost=server->GetName(); // localhost + if (!isPortOpen(localhost,port,500)) { + server->GetPuttyTunnel()->StartDialog(winMain, server); // execute plugin + int count=0; + do { + wxMilliSleep(200); + count++; + } while (!isPortOpen(localhost,port,500) && count<20); // wait create putty tunnel + if (count>=20) { + StartMsg(_("Create putty tunnel error.")); + EndMsg(true); + return -1; + } + } + } + // Create a server object and connect it. wxBusyInfo waiting(wxString::Format(_("Connecting to server %s (%s:%d)"), server->GetDescription().c_str(), server->GetName().c_str(), server->GetPort()), this); @@ -1312,7 +1335,7 @@ void frmMain::StoreServers() { wxString key; ++numServers; - if (cursoritem==serveritem) selServerName=server->GetName(); + if (cursoritem==serveritem) selServerName=browser->GetItemText((serveritem)); key.Printf(wxT("Servers/%d/"), numServers); settings->Write(key + wxT("Server"), server->GetName()); settings->Write(key + wxT("HostAddr"), server->GetHostAddr()); diff --git a/frm/plugins.cpp b/frm/plugins.cpp index ec815c4..3c45579 100644 --- a/frm/plugins.cpp +++ b/frm/plugins.cpp @@ -382,7 +382,7 @@ wxWindow *pluginUtilityFactory::StartDialog(frmMain *form, pgObject *obj) return 0; } - +extern pluginUtilityFactory *puttyTunnel; bool pluginUtilityFactory::CheckEnable(pgObject *obj) { // First check that this is one of the supported server types @@ -403,7 +403,6 @@ bool pluginUtilityFactory::CheckEnable(pgObject *obj) if (server_types.Index(serverType) == wxNOT_FOUND) return false; } - // Now check that this is one of the supported object types // for this plugin. If none are specified, then anything goes if (obj && applies_to.Count() > 0) @@ -414,11 +413,14 @@ bool pluginUtilityFactory::CheckEnable(pgObject *obj) else { //"puttyforward" int id=GetId(); - if (winMain==NULL) return false; - wxMenu *m=winMain->GetPluginsMenu(); - m->SetLabel(id,"[Putty tunnel forward]"); + wxMenu *m=NULL; + if (winMain) { + m=winMain->GetPluginsMenu(); + m->SetLabel(id,"[Putty tunnel forward]"); + } if (obj->GetMetaType()==PGM_SERVER) { pgServer* srv = (pgServer*) obj; + srv->SetPuttyTunnel(NULL); wxString host=obj->GetName(); wxString sport=NumToStr((long)srv->GetPort()); wxString f ; @@ -447,8 +449,10 @@ bool pluginUtilityFactory::CheckEnable(pgObject *obj) if (port.Len()>0 && port[0]=='L' && sport==port.substr(1)) { // found putty config title=filename; - m->SetLabel(id,title); + if (winMain) m->SetLabel(id,title); isfound=true; + srv->SetPuttyTunnel(this); + if (!winMain) return false; return true; } } diff --git a/include/schema/pgServer.h b/include/schema/pgServer.h index 6637a8d..1a8cad6 100644 --- a/include/schema/pgServer.h +++ b/include/schema/pgServer.h @@ -17,6 +17,7 @@ class frmMain; class pgServer; +class pluginUtilityFactory; class pgServerFactory : public pgaFactory { @@ -366,6 +367,10 @@ public: void ShowTreeDetail(ctlTree *browser, frmMain *form = 0, ctlListView *properties = 0, ctlSQLBox *sqlPane = 0); void ShowHint(frmMain *form, bool force); void ShowStatistics(frmMain *form, ctlListView *statistics); + void SetPuttyTunnel(pluginUtilityFactory *puttytunnel) { + puttyTunnel=puttytunnel; + } + pluginUtilityFactory* GetPuttyTunnel() {return puttyTunnel;} wxString GetHelpPage(bool forCreate) const { return wxT("pg/managing-databases"); @@ -448,6 +453,7 @@ public: { sslcompression = b; } + #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT) //SSH Tunnel @@ -560,6 +566,7 @@ private: bool inRecovery, replayPaused; wxString receiveLoc, replayLoc, replayTimestamp; wxDateTime confLoadedSince; + pluginUtilityFactory *puttyTunnel=NULL; // if exists putty tunnel for pgServer #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT) bool createSSHTunnel(); diff --git a/include/utils/misc.h b/include/utils/misc.h index 7b93cac..c1e4ce9 100644 --- a/include/utils/misc.h +++ b/include/utils/misc.h @@ -282,6 +282,7 @@ wxString qtTypeIdent(const wxString &value); // add " if necessary bool make_identifier(const wxString &strname, wxString &s, wxString &n, bool islower); wxSize getScreenSizeForPoint(const wxPoint screenPos); void showHelpHtml(wxWindow *parent, const wxString &htmlHelp,wxPoint screenPos, wxSize size); +bool isPortOpen(const wxString& host, int port , int timeout_ms); #endif diff --git a/utils/misc.cpp b/utils/misc.cpp index f842c8f..fc61af6 100644 --- a/utils/misc.cpp +++ b/utils/misc.cpp @@ -1535,5 +1535,49 @@ void showHelpHtml(wxWindow *parent, const wxString &htmlHelp,wxPoint screenPos, } +#include +bool isPortOpen(const wxString& host, int port , int timeout_ms) { + wxSocketClient client; + //client.SetTimeout(1); // 1 секунда таймаут (можно уменьшить до 0.5 или 0.2) + + wxIPV4address addr; + addr.Hostname(host); + addr.Service(port); + // Issue the connection request + client.Connect(addr, false); + + // Wait until the request completes or until we decide to give up + while ( !client.WaitOnConnect(0, timeout_ms) ) + { + break; + } + bool success = client.IsConnected(); +return success; + +/* int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + return false; + } + + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + inet_pton(AF_INET, host.c_str(), &addr.sin_addr); + + // Установка таймаута (опционально, для ускорения) + timeval tv{}; + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; + setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + + int result = connect(sock, reinterpret_cast(&addr), sizeof(addr)); + + close(sock); + + return result == 0; // true, если порт открыт (сервер принимает соединения) + */ +} +