standardserverconsole.cpp
1 //------------------------------------------------------------------------------
2 // standardserverconsole.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2009 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "standardserverconsole.h"
24 
25 #include <QMessageBox>
26 
27 #ifndef Q_OS_WIN32
28 #include <csignal>
29 #include <QTextStream>
30 #endif
31 
32 StandardServerConsole::StandardServerConsole(const QIcon &icon, const QString &program, const QStringList &arguments)
33 {
34  // Have the console delete itself
35  setAttribute(Qt::WA_DeleteOnClose);
36 
37  // Set up the window.
38  setWindowTitle("Server Console");
39  setWindowIcon(icon);
40  resize(640, 400);
41 
42  // Add our console widget
43  console = new ServerConsole();
44  setCentralWidget(console);
45 
46  // Start the process
47  process = new QProcess();
48  process->start(program, arguments);
49  if (process->waitForStarted())
50  {
51  show();
52  connect(console, SIGNAL(messageSent(const QString&)), this, SLOT(writeToStandardInput(const QString&)));
53  connect(process, SIGNAL(readyReadStandardError()), this, SLOT(errorDataReady()));
54  connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(outputDataReady()));
55  connect(process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finish(int,QProcess::ExitStatus)));
56  }
57  else // Didn't start get rid of this console.
58  close();
59 }
60 
61 StandardServerConsole::~StandardServerConsole()
62 {
63  #ifndef Q_OS_WIN32
64  if (process->pid() != 0)
65  {
66  // On non-Windows systems try to find child processes and kill them.
67  // Unfortunately it doesn't look like Qt can help us here (which kind of
68  // makes sense considering it seems like there no real API to do it).
69  // Ideally only one process started and we don't have to do this.
70  auto ps = new QProcess();
71  ps->start(QString("ps h --ppid %1 -o pid").arg(process->pid()));
72  ps->waitForFinished();
73  QByteArray psOutput = ps->readAllStandardOutput();
74  QTextStream stream(&psOutput);
75  stream.skipWhiteSpace();
76  while (!stream.atEnd())
77  {
78  unsigned int cpid;
79  stream >> cpid;
80  stream.skipWhiteSpace();
81  kill(cpid, SIGTERM);
82  }
83  delete ps;
84  }
85  #endif
86 
87  process->disconnect(this);
88  process->terminate();
89  process->waitForFinished(1000);
90  process->close();
91  process->waitForFinished();
92  delete process;
93 }
94 
95 void StandardServerConsole::errorDataReady()
96 {
97  console->appendMessage(QString(process->readAllStandardError()));
98 }
99 
100 void StandardServerConsole::finish(int exitCode, QProcess::ExitStatus exitStatus)
101 {
102  if (exitStatus == QProcess::CrashExit && exitCode != 0)
103  QMessageBox::critical(this, "Server crash", QString("The server terminated unexpectedly with exit code: %1").arg(exitCode));
104 
105  close();
106 }
107 
108 void StandardServerConsole::outputDataReady()
109 {
110  console->appendMessage(QString(process->readAllStandardOutput()));
111 }
112 
113 void StandardServerConsole::writeToStandardInput(const QString &message)
114 {
115  process->write((message + "\n").toUtf8());
116 }