Skip to content

Commit 9d5735b

Browse files
committed
add TLS support in socket server
1 parent d368ea2 commit 9d5735b

21 files changed

+354
-114
lines changed

.github/workflows/checkpr.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99
strategy:
1010
matrix:
11-
python-version: ["3.10", "3.11", "3.12", "3.13"]
11+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
1212

1313
steps:
1414
- uses: actions/checkout@v4
@@ -25,4 +25,4 @@ jobs:
2525
- name: Scan security vulnerabilities with bandit
2626
run: bandit -c pyproject.toml -r .
2727
- name: Generate coverage report
28-
run: pytest
28+
run: pytest

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111
strategy:
1212
matrix:
13-
python-version: ["3.10", "3.11", "3.12", "3.13"]
13+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
1414

1515
steps:
1616
- uses: actions/checkout@v4

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
"python.analysis.addHoverSummaries": false,
2323
"python-envs.defaultEnvManager": "ms-python.python:venv",
2424
"python-envs.pythonProjects": [],
25-
"python.defaultInterpreterPath": "${userHome}/pygpsclient/bin/python3"
25+
"python.defaultInterpreterPath": "${userHome}/pygpsclient/bin/python3",
26+
"python.testing.unittestEnabled": false
2627
}

CONTRIBUTING.md

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ If you're intending to make significant changes, please raise them in the [Discu
66

77
Being one of our contributors, you agree and confirm that:
88

9-
* The work is all your own.
9+
* The work is all your own. For the avoidance of doubt, this means **no AI coding agents such as Copilot**.
1010
* Your work will be distributed under a BSD 3-Clause License once your pull request is merged.
1111
* You submitted work fulfils or mostly fulfils our coding conventions, styles and standards.
1212

@@ -15,29 +15,21 @@ Please help us keep our issue list small by adding fixes: #{$ISSUE_NO} to the co
1515
## Coding conventions
1616

1717
* This is open source software. Code should be as simple and transparent as possible. Favour clarity over brevity.
18-
* The code should be compatible with Python >= 3.9.
18+
* The code should be compatible with Python >= 3.10.
1919
* Avoid external library dependencies unless there's a compelling reason not to.
2020
* We use and recommend [Visual Studio Code](https://code.visualstudio.com/) with the [Python Extension](https://marketplace.visualstudio.com/items?itemName=ms-python.python) for development and testing.
2121
* Code should be documented in accordance with [Sphinx](https://www.sphinx-doc.org/en/master/) docstring conventions.
22-
* Code should formatted using [black](https://pypi.org/project/black/) (>= 24.4).
23-
* We use and recommend [pylint](https://pypi.org/project/pylint/) (>=3.0.1) for code analysis.
24-
* We use and recommend [bandit](https://pypi.org/project/bandit/) (>=1.7.5) for security vulnerability analysis.
22+
* Code should formatted using [black](https://pypi.org/project/black/).
23+
* We use and recommend [pylint](https://pypi.org/project/pylint/) for code analysis.
24+
* We use and recommend [bandit](https://pypi.org/project/bandit/) for security vulnerability analysis.
2525
* Commits must be [signed](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits).
2626

2727
## Testing
2828

29-
While we endeavour to test on as wide a variety of u-blox devices as possible, as a volunteer project we only have a limited number of devices available. We particularly welcome testing contributions relating to specialised devices (e.g. high precision HP, real-time kinematics RTK, automotive dead-reckoning ADR, etc.).
30-
3129
We use python's native pytest framework for local unit testing, complemented by the GitHub Actions automated build and testing workflow.
3230

3331
Please write pytest examples for new code you create and add them to the `/tests` folder following the naming convention `test_*.py`.
3432

35-
We test on the following platforms using a variety of u-blox devices from Generation 7 throught Generation 10:
36-
* Windows 11
37-
* MacOS (Ventura & Sonoma, Intel & Apple Silicon)
38-
* Linux (Ubuntu 22.04 LTS Jammy Jellyfish, 24.04 LTS Noble Numbat)
39-
* Raspberry Pi OS (32-bit & 64-bit)
40-
4133
## Submitting changes
4234

4335
Please send a [GitHub Pull Request to pygnssutils](https://github.com/semuconsulting/pygnssutils/pulls) with a clear list of what you've done (read more about [pull requests](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/about-pull-requests)). Please follow our coding conventions (above) and make sure all of your commits are atomic (one feature per commit).

README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pygnssutils
88
[gnssserver CLI](#gnssserver) |
99
[gnssntripclient CLI](#gnssntripclient) |
1010
[gnssmqttclient CLI](#gnssmqttclient) |
11+
[socketserver](#socketserver) |
1112
[RTK Demonstration](#rtkdemo) |
1213
[Troubleshooting](#troubleshooting) |
1314
[Graphical Client](#gui) |
@@ -33,6 +34,7 @@ designated output stream.
3334
1. `GNSSMQTTClient` class and its associated [`gnssmqttclient`](#gnssmqttclient) CLI utility. This implements
3435
a simple SPARTN IP (MQTT) Client which receives SPARTN correction data from an SPARTN IP location service and (optionally) sends this to a
3536
designated output stream.
37+
1. `SocketServer` class based on the native Python `ThreadingTCPServer`. Capable of operating in two modes - Socket Server or NTRIP Caster. Provides two alternate client request handler classes - `ClientHandler` (HTTP) or `ClientHandlerTLS` (HTTPS).
3638

3739
The pygnssutils homepage is located at [https://github.com/semuconsulting/pygnssutils](https://github.com/semuconsulting/pygnssutils).
3840

@@ -456,6 +458,31 @@ gnssmqttclient -h
456458

457459
Refer to the [pyspartn documentation](https://github.com/semuconsulting/pyspartn?tab=readme-ov-file#reading) for further details on decrypting encrypted (`eaf=1`) SPARTN payloads.
458460

461+
---
462+
## <a name="socketserver">SocketServer</a>
463+
464+
```
465+
class pygnssutils.socketserver.SocketServer(app, ntripmode, maxclients, msgqueue, **kwargs)
466+
```
467+
468+
A helper class based on the native Python [`ThreadingTCPServer`](https://docs.python.org/3/library/socketserver.html) class, which streams GNSS data from an inbound message queue `msgqueue` to a maximum of `maxclients` TCP clients.
469+
470+
Capable of operating in either of two modes, according to the `ntripmode` argument:
471+
1. ntripmode = 0 - Socket Server; streams incoming GNSS data to any TCP client, without authentication.
472+
2. ntripmode = 1 - NTRIP Caster; acts as a simple NTRIP Server/Caster, streaming incoming RTCM3 data to any authenticated NTRIP client.
473+
474+
Provides two client request handler classes:
475+
- `ClientHandler` - unencrypted HTTP connection.
476+
- `ClientHandlerTLS` - encrypted HTTPS (TLS) connection.
477+
478+
**NB:** HTTPS requires a valid x509 TLS certificate/key pair (in pem format) to be located at a path designated by environment variable `PYGNSSUTILS_PEMPATH`. The default path is `$HOME\pygnssutils.pem`. The following openssl command can be used to create a suitable pem file for test and demonstration purposes:
479+
480+
```shell
481+
openssl req -x509 -newkey rsa:4096 -keyout pygnssutils.pem -out pygnssutils.pem -sha256 -days 3650 -nodes
482+
```
483+
484+
Refer to the [Sphinx API documentation](https://www.semuconsulting.com/pygnssutils/pygnssutils.html#module-pygnssutils.socket_server) for further details.
485+
459486
---
460487
## <a name="rtkdemo">NTRIP RTK demonstration using `gnssserver` and `gnssntripclient`</a>
461488

@@ -531,7 +558,6 @@ gnssntripclient --server 192.168.0.27 --port 2101 --https 0 --mountpoint pygnssu
531558

532559
Refer to [cryptography installation README.md](https://github.com/semuconsulting/pyspartn/blob/main/cryptography_installation/README.md).
533560

534-
535561
---
536562
## <a name="gui">Graphical Client</a>
537563

RELEASE_NOTES.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
# pygnssutils
22

3+
### RELEASE 1.1.19
4+
5+
ENHANCEMENTS:
6+
7+
1. Add support for TLS connections in SocketServer. Introduces two alternative client request handler classes - ClientHandler (HTTP) or ClientHandlerTLS (HTTPS). TLS operation requires a suitable TLS certificate/key pair (in pem format) to be located at a path designated by
8+
environment variable `PYGNSSUTILS_PEMPATH` - the default path is $HOME/pygnssutils.pem. See Sphinx documentation for details.
9+
10+
A self-signed pem file suitable for test and demonstration purposes can be created thus:
11+
```shell
12+
openssl req -x509 -newkey rsa:4096 -keyout pygnssutils.pem -out pygnssutils.pem -sha256 -days 3650 -nodes
13+
```
14+
315
### RELEASE 1.1.18
416

517
ENHANCEMENTS:
618

19+
1. Add gnssreader class.
720
1. Add support for Quectel QGC protocol.
821

922
### RELEASE 1.1.17

pyproject.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ dependencies = [
3737
"certifi>=2025.0.0",
3838
"paho-mqtt>=2.1.0",
3939
"pyserial>=3.5",
40-
"pyspartn>=1.0.7",
41-
"pyubx2>=1.2.58",
42-
"pysbf2>=1.0.0",
43-
"pyubxutils>=1.0.3",
44-
"pyqgc>=0.1.1",
40+
"pyspartn>=1.0.8",
41+
"pyubx2>=1.2.59",
42+
"pysbf2>=1.0.3",
43+
"pyubxutils>=1.0.5",
44+
"pyqgc>=0.1.2",
4545
]
4646

4747
[project.scripts]

src/pygnssutils/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
from pygnssutils.globals import *
1515
from pygnssutils.gnssmqttclient import GNSSMQTTClient
1616
from pygnssutils.gnssntripclient import GNSSNTRIPClient
17+
from pygnssutils.gnssreader import (
18+
NMEA_PROTOCOL,
19+
QGC_PROTOCOL,
20+
RTCM3_PROTOCOL,
21+
SBF_PROTOCOL,
22+
UBX_PROTOCOL,
23+
GNSSReader,
24+
)
1725
from pygnssutils.gnssserver import GNSSSocketServer
1826
from pygnssutils.gnssstreamer import GNSSStreamer
1927
from pygnssutils.helpers import *

src/pygnssutils/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
:license: BSD 3-Clause
99
"""
1010

11-
__version__ = "1.1.18"
11+
__version__ = "1.1.19"

src/pygnssutils/globals.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
:license: BSD 3-Clause
99
"""
1010

11+
OKCOL = "green"
12+
ERRCOL = "salmon"
13+
INFOCOL = "steelblue2"
14+
1115
CLIAPP = "CLI"
1216
DEFAULT_BUFSIZE = 4096 # buffer size for NTRIP client
1317
"""Default socket buffer size"""
@@ -74,6 +78,8 @@
7478
"""Serial output"""
7579
OUTPUT_SOCKET = 3
7680
"""Socket output"""
81+
OUTPUT_SOCKET_TLS = 6
82+
"""Socket output with TLS"""
7783
OUTPUT_HANDLER = 4
7884
"""Custom output handler"""
7985
OUTPUT_TEXT_FILE = 5
@@ -102,7 +108,7 @@
102108
"""Disconnected"""
103109
CONNECTED = 1
104110
"""Connected"""
105-
MAXCONNECTION = 2
111+
MAXCONNECTION = 5
106112
"""Maximum connections reached (for socket server)"""
107113
LOGFORMAT = "{asctime}.{msecs:.0f} - {levelname} - {name} - {message}"
108114
"""Logging format"""
@@ -111,7 +117,7 @@
111117
NOGGA = -1
112118
"""No GGA sentence to be sent (for NTRIP caster)"""
113119
EPILOG = (
114-
"© 2022 SEMU Consulting BSD 3-Clause license"
120+
"© 2022 semuadmin (Steve Smith) BSD 3-Clause license"
115121
" - https://github.com/semuconsulting/pygnssutils/"
116122
)
117123
"""CLI argument parser epilog"""
@@ -195,7 +201,10 @@
195201
MINMMEA_ID = [b"\xf0\x00", b"\xf0\x02", b"\xf0\x03", b"\xf0\x04", b"\xf0\x05"]
196202
ALLUBX_CLS = [b"\x01"]
197203
MINUBX_ID = [b"\x01\x04", b"\x01\x07", b"\x01\x35"]
198-
204+
PYGNSSUTILS_PEM = "pygnssutils.pem"
205+
"""Name of default TLS PEM file"""
206+
PYGNSSUTILS_PEMPATH = "PYGNSSUTILS_PEMPATH"
207+
"""Name of environment variable containing path to TLS PEM file"""
199208
TOPIC_KEY = "/pp/ubx/0236/{}"
200209
TOPIC_ASSIST = "/pp/ubx/mga"
201210
TOPIC_DATA = "/pp/{}/{}"

0 commit comments

Comments
 (0)