Skip to content

Commit

Permalink
Merge pull request #2917 from Rob-NY/server_bind_address
Browse files Browse the repository at this point in the history
JSON-RPC: Add option to specify bind address for server
  • Loading branch information
hoffie committed Nov 10, 2022
2 parents d2052e9 + 22dd69b commit 18dd1b1
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 6 deletions.
3 changes: 3 additions & 0 deletions docs/JSON-RPC.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ It can be generated like this:
$ openssl rand -base64 10 > /file/with/a/secret.txt
```

The JSON-RPC server defaults to listening on the local loopback network interface (127.0.0.1). This can be optionally changed by using the `--jsonrpcbindip <ip address>` command line option. **IPv4 only. IPv6 support has not been tested.**


## Wire protocol

The JSON-RPC server is based on the [JSON-RPC 2.0](https://www.jsonrpc.org/specification) protocol, using [streaming newline-delimited JSON over TCP](https://clue.engineering/2018/introducing-reactphp-ndjson) as the transport. There are three main types of messages being exchanged:
Expand Down
4 changes: 2 additions & 2 deletions src/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ LED bar: lbr
// minimum length of JSON-RPC secret string (main.cpp)
#define JSON_RPC_MINIMUM_SECRET_LENGTH 16

// JSON-RPC listen address
#define JSON_RPC_LISTEN_ADDRESS "127.0.0.1"
// JSON-RPC listen address (Default)
#define DEFAULT_JSON_RPC_LISTEN_ADDRESS "127.0.0.1"

#define _MAXSHORT 32767
#define _MINSHORT ( -32768 )
Expand Down
38 changes: 37 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ int main ( int argc, char** argv )
int iNumServerChannels = DEFAULT_USED_NUM_CHANNELS;
quint16 iPortNumber = DEFAULT_PORT_NUMBER;
int iJsonRpcPortNumber = INVALID_PORT;
QString strJsonRpcBindIP = DEFAULT_JSON_RPC_LISTEN_ADDRESS;
quint16 iQosNumber = DEFAULT_QOS_NUMBER;
ELicenceType eLicenceType = LT_NO_LICENCE;
QString strMIDISetup = "";
Expand Down Expand Up @@ -209,6 +210,15 @@ int main ( int argc, char** argv )
continue;
}

// JSON-RPC bind address ------------------------------------------------
if ( GetStringArgument ( argc, argv, i, "--jsonrpcbindip", "--jsonrpcbindip", strArgument ) )
{
strJsonRpcBindIP = QString ( strArgument );
qInfo() << qUtf8Printable ( QString ( "- JSON-RPC will bind to: %1 if enabled" ).arg ( strJsonRpcBindIP ) );
CommandLineOptions << "--jsonrpcbindip";
continue;
}

// Quality of Service --------------------------------------------------
if ( GetNumericArgument ( argc, argv, i, "-Q", "--qos", 0, 255, rDbleArgument ) )
{
Expand Down Expand Up @@ -783,6 +793,31 @@ int main ( int argc, char** argv )
strServerBindIP = "";
}
}

#ifndef NO_JSON_RPC
//
// strJsonRpcBind address defaults to loopback and should not be empty, but
// in the odd chance that an empty IP is passed, we'll check for it here.

if ( strJsonRpcBindIP.trimmed().isEmpty() )
{
qCritical() << qUtf8Printable ( QString ( "JSON-RPC is enabled but no bind address was provided, exiting." ) );
exit ( 1 );
}

// This means of testing the validity of IP addresses is far from perfect but
// we do it here as an upfront check. The downstream network calls will error
// out on malformed addresses not caught here.
{
QHostAddress InetAddr;
if ( !InetAddr.setAddress ( strJsonRpcBindIP ) )
{
qCritical() << qUtf8Printable ( QString ( "The JSON-RPC address specified is not valid, exiting. " ) );
exit ( 1 );
}
}

#endif
}

// Application/GUI setup ---------------------------------------------------
Expand Down Expand Up @@ -880,7 +915,7 @@ int main ( int argc, char** argv )
qWarning() << "- JSON-RPC: This interface is experimental and is subject to breaking changes even on patch versions "
"(not subject to semantic versioning) during the initial phase.";

pRpcServer = new CRpcServer ( pApp, iJsonRpcPortNumber, strJsonRpcSecret );
pRpcServer = new CRpcServer ( pApp, strJsonRpcBindIP, iJsonRpcPortNumber, strJsonRpcSecret );
if ( !pRpcServer->Start() )
{
qCritical() << qUtf8Printable ( QString ( "- JSON-RPC: Server failed to start. Exiting." ) );
Expand Down Expand Up @@ -1072,6 +1107,7 @@ QString UsageArguments ( char** argv )
" --jsonrpcsecretfile\n"
" path to a single-line file which contains a freely\n"
" chosen secret to authenticate JSON-RPC users.\n"
" --jsonrpcbindip optional network address to bind RPC server. Defaults to 127.0.0.1 (IPv4 only, IPv6 not tested).\n"
" -Q, --qos set the QoS value. Default is 128. Disable with 0\n"
" (see the Jamulus website to enable QoS on Windows)\n"
" -t, --notranslation disable translation (use English language)\n"
Expand Down
5 changes: 3 additions & 2 deletions src/rpcserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
#include "global.h"
#include "rpcserver.h"

CRpcServer::CRpcServer ( QObject* parent, int iPort, QString strSecret ) :
CRpcServer::CRpcServer ( QObject* parent, QString strBindIP, int iPort, QString strSecret ) :
QObject ( parent ),
strBindIP ( strBindIP ),
iPort ( iPort ),
strSecret ( strSecret ),
pTransportServer ( new QTcpServer ( this ) )
Expand Down Expand Up @@ -60,7 +61,7 @@ bool CRpcServer::Start()
{
return false;
}
if ( pTransportServer->listen ( QHostAddress ( JSON_RPC_LISTEN_ADDRESS ), iPort ) )
if ( pTransportServer->listen ( QHostAddress ( strBindIP ), iPort ) )
{
qInfo() << qUtf8Printable ( QString ( "- JSON-RPC: Server started on %1:%2" )
.arg ( pTransportServer->serverAddress().toString() )
Expand Down
3 changes: 2 additions & 1 deletion src/rpcserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class CRpcServer : public QObject
Q_OBJECT

public:
CRpcServer ( QObject* parent, int iPort, QString secret );
CRpcServer ( QObject* parent, QString strBindIP, int iPort, QString secret );
virtual ~CRpcServer();

bool Start();
Expand All @@ -64,6 +64,7 @@ class CRpcServer : public QObject
static const int iErrUnauthenticated = 401;

private:
QString strBindIP;
int iPort;
QString strSecret;
QTcpServer* pTransportServer;
Expand Down
3 changes: 3 additions & 0 deletions tools/generate_json_rpc_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ def to_markdown(self):
$ openssl rand -base64 10 > /file/with/a/secret.txt
```
The JSON-RPC server defaults to listening on the local loopback network interface (127.0.0.1). This can be optionally changed by using the `--jsonrpcbindip <ip address>` command line option. **IPv4 only. IPv6 support has not been tested.**
## Wire protocol
The JSON-RPC server is based on the [JSON-RPC 2.0](https://www.jsonrpc.org/specification) protocol, using [streaming newline-delimited JSON over TCP](https://clue.engineering/2018/introducing-reactphp-ndjson) as the transport. There are three main types of messages being exchanged:
Expand Down

0 comments on commit 18dd1b1

Please sign in to comment.