-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1016de0
commit 09a1b0f
Showing
20 changed files
with
2,070 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
name: 'Set version' | ||
|
||
runs: | ||
using: "composite" | ||
steps: | ||
- shell: bash | ||
if: "startsWith(github.ref, 'refs/tags/')" | ||
run: | | ||
sed -i'' -e "s/version = [\"]0.1.0[\"]/version = \"$GITHUB_REF_NAME\"/g" pyproject.toml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
name: Build and publish | ||
|
||
on: | ||
push: | ||
tags: | ||
- '*' | ||
workflow_dispatch: | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
linux: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
target: [x86_64, x86, aarch64, armv7, s390x, ppc64le] | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: ./.github/actions/set-version | ||
- uses: actions/setup-python@v4 | ||
with: | ||
python-version: '3.10' | ||
- name: Build wheels | ||
uses: PyO3/maturin-action@v1 | ||
with: | ||
target: ${{ matrix.target }} | ||
args: --release --out dist --find-interpreter | ||
sccache: 'true' | ||
manylinux: auto | ||
- name: Upload wheels | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: wheels | ||
path: dist | ||
|
||
windows: | ||
runs-on: windows-latest | ||
strategy: | ||
matrix: | ||
target: [x64, x86] | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: ./.github/actions/set-version | ||
- uses: actions/setup-python@v4 | ||
with: | ||
python-version: '3.10' | ||
architecture: ${{ matrix.target }} | ||
- name: Build wheels | ||
uses: PyO3/maturin-action@v1 | ||
with: | ||
target: ${{ matrix.target }} | ||
args: --release --out dist --find-interpreter | ||
sccache: 'true' | ||
- name: Upload wheels | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: wheels | ||
path: dist | ||
|
||
macos: | ||
runs-on: macos-latest | ||
strategy: | ||
matrix: | ||
target: [x86_64, aarch64] | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: ./.github/actions/set-version | ||
- uses: actions/setup-python@v4 | ||
with: | ||
python-version: '3.10' | ||
- name: Build wheels | ||
uses: PyO3/maturin-action@v1 | ||
with: | ||
target: ${{ matrix.target }} | ||
args: --release --out dist --find-interpreter | ||
sccache: 'true' | ||
- name: Upload wheels | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: wheels | ||
path: dist | ||
|
||
sdist: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: ./.github/actions/set-version | ||
- name: Build sdist | ||
uses: PyO3/maturin-action@v1 | ||
with: | ||
command: sdist | ||
args: --out dist | ||
- name: Upload sdist | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: wheels | ||
path: dist | ||
|
||
release: | ||
name: Release | ||
runs-on: ubuntu-latest | ||
if: "startsWith(github.ref, 'refs/tags/')" | ||
needs: [linux, windows, macos, sdist] | ||
steps: | ||
- uses: actions/download-artifact@v3 | ||
with: | ||
name: wheels | ||
- name: Publish to PyPI | ||
uses: PyO3/maturin-action@v1 | ||
env: | ||
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} | ||
with: | ||
command: upload | ||
args: --non-interactive --skip-existing * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
name: Unit tests | ||
|
||
on: | ||
pull_request: | ||
branches: | ||
- main | ||
workflow_dispatch: | ||
|
||
jobs: | ||
unit-tests: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: dtolnay/rust-toolchain@stable | ||
with: | ||
toolchain: stable | ||
components: rustfmt | ||
target: x86_64-unknown-linux-gnu | ||
- name: Setup Python 3.8 | ||
uses: actions/setup-python@v4 | ||
with: | ||
python-version: 3.8 | ||
- name: Setup dependencies | ||
run: | | ||
pip install --upgrade pip | ||
pip install pytest typing_extensions | ||
pip install https://github.com/Tribler/py-ipv8/archive/master.zip | ||
- name: Check rust formatting (rustfmt) | ||
run: cargo fmt --all -- --check | ||
- name: Build and run Python tests | ||
run: | | ||
cargo build | ||
cp target/debug/librust_endpoint.so ipv8_rust_tunnels/rust_endpoint.so | ||
export PYTHONPATH=$(pwd):$PYTHONPATH | ||
echo "PYTHONPATH=.:$PYTHONPATH" >> $GITHUB_ENV | ||
pytest ipv8_rust_tunnels |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
[package] | ||
name = "ipv8-rust-tunnels" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[profile.release] | ||
opt-level = 3 | ||
strip = true | ||
debug = false | ||
codegen-units = 1 | ||
lto = true | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
[lib] | ||
name = "rust_endpoint" | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
pyo3 = { version = "0.20.0", features = ["extension-module"] } | ||
tokio = { version = "1.34.0", features = ["full"] } | ||
env_logger = "0.10.1" | ||
log = "0.4.20" | ||
arc-swap = "1.6.0" | ||
chacha20poly1305 = "0.10.1" | ||
socks5-proto = "0.4.0" | ||
socks5-server = "0.10.0" | ||
bytes = "1.5.0" | ||
rand = "0.8.5" | ||
map-macro = "0.2.6" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
# ipv8-rust-tunnels | ||
# IPv8-rust-tunnels | ||
[![](https://img.shields.io/pypi/v/ipv8-rust-tunnels.svg?label=PyPI)](https://pypi.org/project/ipv8-rust-tunnels/)   [![](https://img.shields.io/pypi/pyversions/ipv8-rust-tunnels.svg?label=Python)](https://pypi.org/project/ipv8-rust-tunnels/)   ![Unit tests](https://github.com/egbertbouman/ipv8-rust-tunnels/actions/workflows/test.yml/badge.svg) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
from __future__ import annotations | ||
|
||
from collections import UserDict | ||
from typing import TYPE_CHECKING | ||
|
||
if TYPE_CHECKING: | ||
from ipv8.messaging.anonymization.community import TunnelCommunity, TunnelSettings | ||
from ipv8.messaging.anonymization.payload import CellPayload | ||
from ipv8.types import Address | ||
|
||
import asyncio | ||
|
||
import ipv8_rust_tunnels.rust_endpoint as rust | ||
|
||
from ipv8.messaging.anonymization.crypto import CryptoEndpoint | ||
from ipv8.messaging.interfaces.udp.endpoint import Endpoint, EndpointClosedException, UDPv4Address | ||
from ipv8.taskmanager import TaskManager | ||
from ipv8.util import succeed | ||
|
||
|
||
class ShadowDict(UserDict): | ||
def __init__(self, adder, updater, remover): | ||
self.adder = adder | ||
self.updater = updater | ||
self.remover = remover | ||
super().__init__() | ||
|
||
def __setitem__(self, key, item): | ||
super().__setitem__(key, item) | ||
self.adder(key, item) | ||
|
||
def __getitem__(self, key): | ||
item = super().__getitem__(key) | ||
if getattr(item, 'dirty', False): | ||
self.updater(key, item) | ||
item.dirty = False | ||
return item | ||
|
||
def __delitem__(self, key): | ||
super().__delitem__(key) | ||
self.remover(key) | ||
|
||
|
||
class RustEndpoint(CryptoEndpoint, Endpoint, TaskManager): | ||
|
||
def __init__(self, port=0, ip="0.0.0.0"): | ||
CryptoEndpoint.__init__(self) | ||
Endpoint.__init__(self) | ||
TaskManager.__init__(self) | ||
self.rust_ep = ep = rust.Endpoint(ip, port) | ||
self.loop = asyncio.get_running_loop() | ||
self.bytes_up = self.bytes_down = 0 | ||
self.prefix = self.settings = None | ||
|
||
self.circuits = ShadowDict(ep.add_circuit, ep.update_circuit, ep.remove_circuit) | ||
self.relays = ShadowDict(ep.add_relay, lambda *_: None, ep.remove_relay) | ||
self.exit_sockets = ShadowDict(ep.add_exit, lambda *_: None, ep.remove_exit) | ||
|
||
self.register_task('update_stats', self.update_stats, interval=1) | ||
|
||
def update_stats(self): | ||
for circuit in self.circuits.values(): | ||
self.rust_ep.update_circuit_stats(circuit.circuit_id, circuit) | ||
|
||
for relay in self.relays.values(): | ||
self.rust_ep.update_relay_stats(relay.circuit_id, relay) | ||
|
||
for exit_socket in self.exit_sockets.values(): | ||
self.rust_ep.update_exit_stats(exit_socket.circuit_id, exit_socket) | ||
|
||
def setup_tunnels(self, tunnel_community: TunnelCommunity, settings: TunnelSettings) -> None: | ||
""" | ||
Set up the TunnelCommunity. | ||
""" | ||
self.prefix = tunnel_community.get_prefix() | ||
self.settings = settings | ||
|
||
self.rust_ep.set_prefix(self.prefix) | ||
self.rust_ep.set_max_relay_early(settings.max_relay_early) | ||
self.rust_ep.set_peer_flags(settings.peer_flags) | ||
|
||
def set_max_relay_early(self, max_relay_early: int) -> None: | ||
""" | ||
Set the maximum number of relay_early cells that are allowed to pass a relay. | ||
""" | ||
self.rust_ep.set_max_relay_early(max_relay_early) | ||
|
||
def set_peer_flags(self, max_relay_early: int) -> None: | ||
""" | ||
Set peer flags. | ||
""" | ||
self.rust_ep.set_peer_flags(max_relay_early) | ||
|
||
def datagram_received(self, ip: str, port: int, datagram: bytes) -> None: | ||
""" | ||
Process incoming data that's coming directly from the socket. | ||
""" | ||
self.bytes_down += len(datagram) | ||
self.loop.call_soon_threadsafe(self.notify_listeners, (UDPv4Address(ip, port), datagram)) | ||
|
||
def send(self, socket_address: Address, packet: bytes) -> None: | ||
""" | ||
Send a packet to a given address. | ||
""" | ||
self.assert_open() | ||
try: | ||
self.rust_ep.send((str(socket_address[0]), socket_address[1]), packet) | ||
self.bytes_up += len(packet) | ||
except (TypeError, ValueError, AttributeError, rust.RustError) as exc: | ||
self._logger.warning("Dropping packet due to message formatting error: %s", exc) | ||
|
||
def send_cell(self, target_addr: Address, cell: CellPayload) -> None: | ||
""" | ||
Send the given payload DIRECTLY to the given peer with the appropriate encryption rules. | ||
""" | ||
packet = cell.to_bin(self.prefix) | ||
self.rust_ep.send_cell(target_addr, packet) | ||
self.bytes_up += len(packet) | ||
|
||
async def open(self) -> bool: # noqa: A003 | ||
""" | ||
Open the Endpoint. | ||
:return: True is the Endpoint was successfully opened, False otherwise. | ||
""" | ||
self.rust_ep.open(self.datagram_received) | ||
return succeed(self.rust_ep.is_open()) | ||
|
||
def close(self) -> None: | ||
""" | ||
Closes the Endpoint. | ||
""" | ||
if not self.is_open(): | ||
return | ||
|
||
self.rust_ep.close() | ||
|
||
def assert_open(self) -> None: | ||
""" | ||
Check if we are opened by the programmer and if the underlying transport is fully open. | ||
""" | ||
if not self.is_open(): | ||
raise EndpointClosedException(self) | ||
|
||
def get_address(self) -> Address: | ||
""" | ||
Get the address for this Endpoint. | ||
""" | ||
self.assert_open() | ||
return self.rust_ep.get_address() | ||
|
||
def is_open(self) -> bool: | ||
""" | ||
Check if the underlying socket is open. | ||
""" | ||
return self.rust_ep.is_open() | ||
|
||
def reset_byte_counters(self) -> None: | ||
""" | ||
Set bytes_up and bytes_down to 0. | ||
""" | ||
self.bytes_up = 0 | ||
self.bytes_down = 0 |
Oops, something went wrong.