Auto execute plugin puttyforward for linux.

При наличии такого плагина:
```
; 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
и если он закрыт то запускается выше указанный плагин для организации туннеля.
This commit is contained in:
lsv 2026-03-17 11:57:33 +05:00
parent 903fd8ea9e
commit 2cde1c04f4
5 changed files with 88 additions and 9 deletions

View file

@ -267,8 +267,12 @@ frmMain::frmMain(const wxString &title)
browser->SetFocus(); browser->SetFocus();
wxString selServerName=settings->Read(wxT("Servers/SelectItem"), ""); wxString selServerName=settings->Read(wxT("Servers/SelectItem"), "");
if (selServerName.Len()>0) { if (selServerName.Len()>0) {
wxTreeItemId sel=browser->FindItem(root,selServerName,true); wxTreeItemId sel=browser->FindItem(root,selServerName,false);
if (sel.IsOk()) browser->SelectItem(sel); 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) 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. // Create a server object and connect it.
wxBusyInfo waiting(wxString::Format(_("Connecting to server %s (%s:%d)"), wxBusyInfo waiting(wxString::Format(_("Connecting to server %s (%s:%d)"),
server->GetDescription().c_str(), server->GetName().c_str(), server->GetPort()), this); server->GetDescription().c_str(), server->GetName().c_str(), server->GetPort()), this);
@ -1312,7 +1335,7 @@ void frmMain::StoreServers()
{ {
wxString key; wxString key;
++numServers; ++numServers;
if (cursoritem==serveritem) selServerName=server->GetName(); if (cursoritem==serveritem) selServerName=browser->GetItemText((serveritem));
key.Printf(wxT("Servers/%d/"), numServers); key.Printf(wxT("Servers/%d/"), numServers);
settings->Write(key + wxT("Server"), server->GetName()); settings->Write(key + wxT("Server"), server->GetName());
settings->Write(key + wxT("HostAddr"), server->GetHostAddr()); settings->Write(key + wxT("HostAddr"), server->GetHostAddr());

View file

@ -382,7 +382,7 @@ wxWindow *pluginUtilityFactory::StartDialog(frmMain *form, pgObject *obj)
return 0; return 0;
} }
extern pluginUtilityFactory *puttyTunnel;
bool pluginUtilityFactory::CheckEnable(pgObject *obj) bool pluginUtilityFactory::CheckEnable(pgObject *obj)
{ {
// First check that this is one of the supported server types // 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) if (server_types.Index(serverType) == wxNOT_FOUND)
return false; return false;
} }
// Now check that this is one of the supported object types // Now check that this is one of the supported object types
// for this plugin. If none are specified, then anything goes // for this plugin. If none are specified, then anything goes
if (obj && applies_to.Count() > 0) if (obj && applies_to.Count() > 0)
@ -414,11 +413,14 @@ bool pluginUtilityFactory::CheckEnable(pgObject *obj)
else { else {
//"puttyforward" //"puttyforward"
int id=GetId(); int id=GetId();
if (winMain==NULL) return false; wxMenu *m=NULL;
wxMenu *m=winMain->GetPluginsMenu(); if (winMain) {
m->SetLabel(id,"[Putty tunnel forward]"); m=winMain->GetPluginsMenu();
m->SetLabel(id,"[Putty tunnel forward]");
}
if (obj->GetMetaType()==PGM_SERVER) { if (obj->GetMetaType()==PGM_SERVER) {
pgServer* srv = (pgServer*) obj; pgServer* srv = (pgServer*) obj;
srv->SetPuttyTunnel(NULL);
wxString host=obj->GetName(); wxString host=obj->GetName();
wxString sport=NumToStr((long)srv->GetPort()); wxString sport=NumToStr((long)srv->GetPort());
wxString f ; wxString f ;
@ -447,8 +449,10 @@ bool pluginUtilityFactory::CheckEnable(pgObject *obj)
if (port.Len()>0 && port[0]=='L' && sport==port.substr(1)) { if (port.Len()>0 && port[0]=='L' && sport==port.substr(1)) {
// found putty config // found putty config
title=filename; title=filename;
m->SetLabel(id,title); if (winMain) m->SetLabel(id,title);
isfound=true; isfound=true;
srv->SetPuttyTunnel(this);
if (!winMain) return false;
return true; return true;
} }
} }

View file

@ -17,6 +17,7 @@
class frmMain; class frmMain;
class pgServer; class pgServer;
class pluginUtilityFactory;
class pgServerFactory : public pgaFactory class pgServerFactory : public pgaFactory
{ {
@ -366,6 +367,10 @@ public:
void ShowTreeDetail(ctlTree *browser, frmMain *form = 0, ctlListView *properties = 0, ctlSQLBox *sqlPane = 0); void ShowTreeDetail(ctlTree *browser, frmMain *form = 0, ctlListView *properties = 0, ctlSQLBox *sqlPane = 0);
void ShowHint(frmMain *form, bool force); void ShowHint(frmMain *form, bool force);
void ShowStatistics(frmMain *form, ctlListView *statistics); void ShowStatistics(frmMain *form, ctlListView *statistics);
void SetPuttyTunnel(pluginUtilityFactory *puttytunnel) {
puttyTunnel=puttytunnel;
}
pluginUtilityFactory* GetPuttyTunnel() {return puttyTunnel;}
wxString GetHelpPage(bool forCreate) const wxString GetHelpPage(bool forCreate) const
{ {
return wxT("pg/managing-databases"); return wxT("pg/managing-databases");
@ -449,6 +454,7 @@ public:
sslcompression = b; sslcompression = b;
} }
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT) #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
//SSH Tunnel //SSH Tunnel
bool GetSSHTunnel() const bool GetSSHTunnel() const
@ -560,6 +566,7 @@ private:
bool inRecovery, replayPaused; bool inRecovery, replayPaused;
wxString receiveLoc, replayLoc, replayTimestamp; wxString receiveLoc, replayLoc, replayTimestamp;
wxDateTime confLoadedSince; wxDateTime confLoadedSince;
pluginUtilityFactory *puttyTunnel=NULL; // if exists putty tunnel for pgServer
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT) #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
bool createSSHTunnel(); bool createSSHTunnel();

View file

@ -282,6 +282,7 @@ wxString qtTypeIdent(const wxString &value); // add " if necessary
bool make_identifier(const wxString &strname, wxString &s, wxString &n, bool islower); bool make_identifier(const wxString &strname, wxString &s, wxString &n, bool islower);
wxSize getScreenSizeForPoint(const wxPoint screenPos); wxSize getScreenSizeForPoint(const wxPoint screenPos);
void showHelpHtml(wxWindow *parent, const wxString &htmlHelp,wxPoint screenPos, wxSize size); void showHelpHtml(wxWindow *parent, const wxString &htmlHelp,wxPoint screenPos, wxSize size);
bool isPortOpen(const wxString& host, int port , int timeout_ms);
#endif #endif

View file

@ -1535,5 +1535,49 @@ void showHelpHtml(wxWindow *parent, const wxString &htmlHelp,wxPoint screenPos,
} }
#include <wx/socket.h>
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<sockaddr*>(&addr), sizeof(addr));
close(sock);
return result == 0; // true, если порт открыт (сервер принимает соединения)
*/
}