Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
QHyodaSsh.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2022 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7#include <QtWidgets>
8#include <QHyodaSsh.h>
9#include <arpa/inet.h>
10
11/******************************************************************************
12 * QHyodaSsh
13 *****************************************************************************/
14QHyodaSsh::QHyodaSsh(QString interactive,
15 QString rankZero,
16 quint32 adrs,
17 quint32 port,
18 bool _singleShot): client_name(QProcessEnvironment::systemEnvironment().value("HOSTNAME")),
19 inter_name(interactive),
20 inter_adrs(QString()),
21 rank_zero(rankZero),
22 tunnelProcess(new QProcess()),
23 ceaHostProcess(new QProcess()),
24 via_interactive_hop(false),
25 tcpAdrs(adrs),
26 tcpPort(port),
27 singleShot(_singleShot){
28 qDebug() << "[QHyodaSsh] NEW";
29 qDebug() << "[QHyodaSsh] interactive:"<<interactive;
30 qDebug() << "[QHyodaSsh] rankZero:"<<rankZero;
31
32 via_interactive_hop=( inter_name.startsWith("germain", Qt::CaseInsensitive)
33 || inter_name.startsWith("cartan", Qt::CaseInsensitive)
34 || inter_name.startsWith("lascaux", Qt::CaseInsensitive)) ? true : false;
35
36 // Dans le cas d'un single shot, il n'y a pas de hop
37 if (singleShot) via_interactive_hop=false;
38
39 // Dans tous les cas, on peut aller chercher le nom du noeud interactif
40 ceaHostProcess->setProcessChannelMode(QProcess::MergedChannels);
41 connect(ceaHostProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(ceaHostReadyReadStandardOutput()));
42 if (!singleShot)
43 ceaHostProcess->start(QString("/usr/local/sr/bin/cea_gethost"), QStringList()<<interactive);
44 else
45 ceaHostProcess->start(QString("/usr/bin/host"), QStringList()<<inter_name);
46
47 if (!ceaHostProcess->waitForStarted())
48 qFatal("QHyodaSsh::run threadProcess NOT started!");
49}
50
51
52/******************************************************************************
53 * ~QHyodaSsh
54 *****************************************************************************/
55QHyodaSsh::~QHyodaSsh(){
56 qDebug() << "~QHyodaSsh";
57 tunnelProcess->close();
58 ceaHostProcess->close();
59 if (tunnelProcess->state()!=QProcess::NotRunning)
60 qFatal("QHyodaSsh tunnelProcess NOT closed!");
61 delete tunnelProcess;
62}
63
64
65/******************************************************************************
66 * QHyodaSsh::run
67 *****************************************************************************/
68void QHyodaSsh::run(){
69 if (isRunning()) return;
70
71 ceaHostProcess->close();
72
73 // Si on a pas besoin d'un tunnel
74 if (!via_interactive_hop){
75 // Il reste juste à troquer le localhost 127.0.0.1 du défaut par la station visée
76 tcpAdrs=inetAton(inter_adrs.toLatin1().data());
77 qDebug()<<"\33[1m[QHyodaSsh::run] tcpAdrs="<<tcpAdrs<<"\33[m";
78 // En single shot, on n'a pas fini!, il faut un tunnel
79 if (!singleShot) return;
80 }
81
82
83 if (singleShot){
84 QString command("ssh");
85 QStringList args = QStringList() << "-xCTR"
86 << QString("%1:%2:%1").arg(QString().setNum(tcpPort),inter_adrs)
87 << rank_zero.toLower()
88 << "-N";
89 //qDebug() << vt100_reverse << command << args << vt100_modesreset;
90 // Lancement du process tunnel
91 tunnelProcess->setProcessChannelMode(QProcess::MergedChannels);
92 connect(tunnelProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(tunnelReadyReadStandardOutput()));
93 qDebug()<<"\33[1m[QHyodaSsh::run] singleShot tunnelProcess command="<<command<<", args="<<args<<"\33[m";
94 tunnelProcess->start(command, args);
95 if (!tunnelProcess->waitForStarted())
96 qFatal("QHyodaSsh::run tunnelProcess NOT started!");
97 return;
98 }
99
100 // Tunnel standard
101 QString command("ssh");
102 QStringList args = QStringList() << "-xCTR" // v
103 << QString("%1:%2:%1").arg(QString().setNum(tcpPort),client_name)
104 << inter_adrs
105 << "ssh"
106 << "-xCTR"
107 << QString("%1:%2:%1").arg(QString().setNum(tcpPort),inter_adrs)
108 << rank_zero.toLower()
109 << "-N";
110 qDebug() << "\33[7m" << command << args << "\33[m";
111 // Lancement du process tunnel
112 tunnelProcess->setProcessChannelMode(QProcess::MergedChannels);
113 connect(tunnelProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(tunnelReadyReadStandardOutput()));
114 tunnelProcess->start(command, args);
115 if (!tunnelProcess->waitForStarted())
116 qFatal("QHyodaSsh::run tunnelProcess NOT started!");
117 //Pas d'exec();
118}
119
120
121/******************************************************************************
122 * QHyodaSsh::readyReadStandardOutput
123 *****************************************************************************/
124void QHyodaSsh::tunnelReadyReadStandardOutput(void){
125 const QStringList read_lines=QString(tunnelProcess->readAllStandardOutput()).split(QRegExp("\n"));
126 for(int i=0,mx=read_lines.size();i<mx;++i){
127 const QString line=read_lines.at(i).trimmed();
128 if (line.isEmpty()) continue;
129 qDebug()<<"\t\t"<<"\33[1m"<<line<<"\33[m";
130 }
131}
132
133
134/******************************************************************************
135 * QHyodaSsh::readyReadStandardOutput
136 *****************************************************************************/
137void QHyodaSsh::ceaHostReadyReadStandardOutput(void){
138 const QStringList read_lines=QString(ceaHostProcess->readAllStandardOutput()).split(QRegExp("\n"));
139 qDebug()<<read_lines;
140 for(int i=0,mx=read_lines.size();i<mx;++i){
141 const QString line=read_lines.at(i).trimmed();
142 if (line.isEmpty()) continue;
143 qDebug()<<"\t\t"<<"\33[1m"<<line<<"\33[m";
144 QStringList tokens = line.split(QRegExp("\\s"));
145 if (singleShot)
146 inter_adrs=tokens[3]; //germainXY.c-germain.calcul.bruyeres.t has address ab.c.d.e.f
147 else
148 inter_adrs=tokens[0];
149 qDebug()<<"[\33[1mQHyodaSsh::ceaHostReadyReadStandardOutput] inter_adrs="<<inter_adrs<<"\33[m";
150 // Maintenant qu'on a le noeud interactif, on lance le tunneling
151 if (!isRunning()) run();
152 // On prend que la première adresse
153 return;
154 }
155}
156
157
158
159/*
160 * Check whether "cp" is a valid ascii representation
161 * of an Internet address and convert to a binary address.
162 * Returns 1 if the address is valid, 0 if not.
163 * This replaces inet_addr, the return value from which
164 * cannot distinguish between failure and a local broadcast address.
165 */
166quint32 QHyodaSsh::inetAton(const char *cp){
167 unsigned int val;
168 int base, n;
169 char c;
170 u_int parts[4];
171 u_int *pp = parts;
172
173 for (;;){
174 // Collect number up to ``.''. Values are specified as for C: 0x=hex, 0=octal, other=decimal.
175 val = 0;
176 base = 10;
177 if (*cp == '0'){
178 if (*++cp == 'x' || *cp == 'X')
179 base = 16, cp++;
180 else
181 base = 8;
182 }
183 while ((c = *cp) != '\0') {
184 if (isascii(c) && isdigit(c)){
185 val = (val * base) + (c - '0');
186 cp++;
187 continue;
188 }
189 if (base == 16 && isascii(c) && isxdigit(c)){
190 val = (val << 4) +
191 (c + 10 - (islower(c) ? 'a' : 'A'));
192 cp++;
193 continue;
194 }
195 break;
196 }
197 if (*cp == '.'){
198 // Internet format: a.b.c.d a.b.c (with c treated as 16-bits) a.b (with b treated as 24 bits)
199 if (pp >= parts + 3 || val > 0xff)
200 return (0);
201 *pp++ = val, cp++;
202 }
203 else
204 break;
205 }
206
207 // Check for trailing characters
208 if (*cp && (!isascii(*cp) || !isspace(*cp)))
209 return (0);
210
211 // Concoct the address according to the number of parts specified
212 n = pp - parts + 1;
213 switch (n){
214 case 1: // a -- 32 bits
215 break;
216 case 2: // a.b -- 8.24 bits
217 if (val > 0xffffff)
218 return (0);
219 val |= parts[0] << 24;
220 break;
221 case 3: // a.b.c -- 8.8.16 bits
222 if (val > 0xffff)
223 return (0);
224 val |= (parts[0] << 24) | (parts[1] << 16);
225 break;
226 case 4: // a.b.c.d -- 8.8.8.8 bits
227 if (val > 0xff)
228 return (0);
229 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
230 break;
231 }
232 return htonl(val);
233}
234