Added listening r2 server for Jupyter + r2pipe

This commit is contained in:
xarkes 2018-01-29 15:13:16 +01:00 committed by xarkes
parent 1ba8e03f04
commit 7526965b26
6 changed files with 143 additions and 12 deletions

View File

@ -83,7 +83,7 @@ static void registerCustomFonts()
ret = QFontDatabase::addApplicationFont(":/fonts/Inconsolata-Regular.ttf"); ret = QFontDatabase::addApplicationFont(":/fonts/Inconsolata-Regular.ttf");
assert(-1 != ret && "unable to register Inconsolata-Regular.ttf"); assert(-1 != ret && "unable to register Inconsolata-Regular.ttf");
// do not issue a warning in release // Do not issue a warning in release
Q_UNUSED(ret) Q_UNUSED(ret)
} }
@ -99,6 +99,7 @@ MainWindow::MainWindow(QWidget *parent) :
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
delete configuration;
} }
void MainWindow::initUI() void MainWindow::initUI()
@ -389,22 +390,18 @@ void MainWindow::closeEvent(QCloseEvent *event)
QMessageBox::StandardButton ret = QMessageBox::question(this, APPNAME, QMessageBox::StandardButton ret = QMessageBox::question(this, APPNAME,
tr("Do you really want to exit?\nSave your project before closing!"), tr("Do you really want to exit?\nSave your project before closing!"),
(QMessageBox::StandardButtons)(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel)); (QMessageBox::StandardButtons)(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel));
//qDebug() << ret;
if (ret == QMessageBox::Save) if (ret == QMessageBox::Save)
{ {
if (saveProject(true)) if (saveProject(true))
{ {
saveSettings(); saveSettings();
QMainWindow::closeEvent(event);
}
else
{
event->ignore();
} }
QMainWindow::closeEvent(event);
} }
else if (ret == QMessageBox::Discard) else if (ret == QMessageBox::Discard)
{ {
saveSettings(); saveSettings();
QMainWindow::closeEvent(event);
} }
else else
{ {

View File

@ -93,7 +93,8 @@ SOURCES += \
widgets/VTablesWidget.cpp \ widgets/VTablesWidget.cpp \
CutterApplication.cpp \ CutterApplication.cpp \
utils/JupyterConnection.cpp \ utils/JupyterConnection.cpp \
widgets/JupyterWidget.cpp widgets/JupyterWidget.cpp \
utils/CommandServer.cpp
HEADERS += \ HEADERS += \
cutter.h \ cutter.h \
@ -156,7 +157,8 @@ HEADERS += \
CutterApplication.h \ CutterApplication.h \
widgets/VTablesWidget.h \ widgets/VTablesWidget.h \
utils/JupyterConnection.h \ utils/JupyterConnection.h \
widgets/JupyterWidget.h widgets/JupyterWidget.h \
utils/CommandServer.h
FORMS += \ FORMS += \
dialogs/AboutDialog.ui \ dialogs/AboutDialog.ui \

View File

@ -0,0 +1,89 @@
#include "CommandServer.h"
#include "cutter.h"
CommandServer::CommandServer(QObject *parent) : QObject(parent)
{
}
CommandServer::~CommandServer()
{
}
/**
* @brief Open a local TCP server on port 1234 to read and execute commands.
* This is useful for Jupyter Notebook to access radare2 context using r2pipe
* Example usage:
* import r2pipe; r2 = r2pipe.open('tcp://localhost:1234'); print(r2.cmd('i'))
*/
bool CommandServer::startCommandServer()
{
RCore* core = Core()->core();
const char* port = "1234";
unsigned char buf[4097];
RSocket *ch = NULL;
RSocket *s;
int i, ret;
char *str;
s = r_socket_new (0);
r_socket_listen (s, port, NULL);
if (false) {
eprintf ("Error listening on port %s\n", port);
r_socket_free (s);
return false;
}
eprintf ("Listening for commands on port %s\n", port);
while (isRunning) {
ch = r_socket_accept (s);
buf[0] = 0;
ret = r_socket_read (ch, buf, sizeof (buf) - 1);
if (ret > 0) {
buf[ret] = 0;
for (i = 0; buf[i]; i++) {
if (buf[i] == '\n') {
buf[i] = buf[i + 1]? ';': '\0';
}
}
if ((!r_config_get_i (core->config, "scr.prompt") &&
!strcmp ((char *)buf, "q!")) ||
!strcmp ((char *)buf, ".--")) {
r_socket_close (ch);
break;
}
str = r_core_cmd_str (core, (const char *)buf);
if (str && *str) {
r_socket_write (ch, str, strlen (str));
} else {
const char nl[] = "\n";
r_socket_write (ch, (void*) nl, 1);
}
free (str);
}
r_socket_close (ch);
r_socket_free (ch);
ch = NULL;
}
r_socket_free (s);
r_socket_free (ch);
eprintf ("TCP Server (on %s) exited.\n", port);
return true;
}
void CommandServer::process()
{
startCommandServer();
emit finished();
}
/**
* Stops the server.
*/
void CommandServer::stop()
{
isRunning = false;
}

26
src/utils/CommandServer.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef COMMANDSERVER_H
#define COMMANDSERVER_H
#include <QObject>
class CommandServer : public QObject
{
Q_OBJECT
public:
explicit CommandServer(QObject *parent = nullptr);
~CommandServer();
void stop();
signals:
void finished();
void error(QString err);
public slots:
void process();
private:
bool isRunning = true;
bool startCommandServer();
};
#endif // COMMANDSERVER_H

View File

@ -2,6 +2,8 @@
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject> #include <QJsonObject>
#include <QDebug>
#include <QThread>
#include "JupyterConnection.h" #include "JupyterConnection.h"
@ -12,6 +14,9 @@ JupyterConnection::JupyterConnection(QObject *parent) : QObject(parent)
JupyterConnection::~JupyterConnection() JupyterConnection::~JupyterConnection()
{ {
cmdServer->stop();
process->terminate();
urlProcess->terminate();
} }
const char *urlPy = "from notebook import notebookapp\n" const char *urlPy = "from notebook import notebookapp\n"
@ -28,23 +33,34 @@ void JupyterConnection::start()
process = new QProcess(this); process = new QProcess(this);
connect(process, &QProcess::readyReadStandardError, this, &JupyterConnection::readStandardError); connect(process, &QProcess::readyReadStandardError, this, &JupyterConnection::readStandardError);
connect(process, &QProcess::readyReadStandardOutput, this, &JupyterConnection::readStandardOutput); connect(process, &QProcess::readyReadStandardOutput, this, &JupyterConnection::readStandardOutput);
connect(process, &QProcess::errorOccurred, this, [](QProcess::ProcessError error){ qWarning() << "Jupyter error occurred:" << error; });
process->start("jupyter", {"notebook", "--no-browser", "-y"}); process->start("jupyter", {"notebook", "--no-browser", "-y"});
urlProcess = new QProcess(this); urlProcess = new QProcess(this);
connect(urlProcess, &QProcess::readyReadStandardOutput, this, &JupyterConnection::readUrlStandardOutput); connect(urlProcess, &QProcess::readyReadStandardOutput, this, &JupyterConnection::readUrlStandardOutput);
urlProcess->start("python3", {"-c", urlPy}); urlProcess->start("python3", {"-c", urlPy});
QThread *cmdServerThread = new QThread(this);
cmdServer = new CommandServer();
cmdServer->moveToThread(cmdServerThread);
connect(cmdServer, &CommandServer::error, this, [](QString err){ qWarning() << "CmdServer error:" << err; });
connect(cmdServerThread, SIGNAL (started()), cmdServer, SLOT (process()));
connect(cmdServer, SIGNAL (finished()), cmdServerThread, SLOT (quit()));
connect(cmdServer, SIGNAL (finished()), cmdServer, SLOT (deleteLater()));
connect(cmdServerThread, SIGNAL (finished()), cmdServerThread, SLOT (deleteLater()));
cmdServerThread->start();
} }
void JupyterConnection::readStandardError() void JupyterConnection::readStandardError()
{ {
auto data = process->readAllStandardError(); auto data = process->readAllStandardError();
printf("jupyter stderr: %s\n", data.constData()); printf("Jupyter stderr: %s", data.constData());
} }
void JupyterConnection::readStandardOutput() void JupyterConnection::readStandardOutput()
{ {
auto data = process->readAllStandardOutput(); auto data = process->readAllStandardOutput();
printf("jupyter stdout: %s\n", data.constData()); printf("Jupyter stdout: %s", data.constData());
} }
void JupyterConnection::readUrlStandardOutput() void JupyterConnection::readUrlStandardOutput()

View File

@ -1,8 +1,8 @@
#ifndef JUPYTERCONNECTION_H #ifndef JUPYTERCONNECTION_H
#define JUPYTERCONNECTION_H #define JUPYTERCONNECTION_H
#include <QProcess> #include <QProcess>
#include "CommandServer.h"
class JupyterConnection : public QObject class JupyterConnection : public QObject
{ {
@ -20,6 +20,7 @@ signals:
private: private:
QProcess *process; QProcess *process;
QProcess *urlProcess; QProcess *urlProcess;
CommandServer *cmdServer;
private slots: private slots:
void readStandardError(); void readStandardError();