5.8 KiB
RNS Patches for Columba
This directory contains patched versions of Reticulum Network Stack (RNS) files that fix resource management issues discovered during Columba development.
Why Patches Are Needed
These patches address real bugs in upstream RNS that cause ResourceWarning messages visible in Chaquopy/Android environments. While these warnings are hidden by default in desktop Python, they indicate actual resource leaks that can exhaust file descriptors over time.
Why We See The Warnings
- Chaquopy 13.0+ enables ResourceWarning by default (since November 2022)
- This is intentional to help Android developers catch resource leaks early
- Desktop Python requires
-W defaultflag to see these warnings - Android has stricter file descriptor limits (typically 256-512 vs 1024+ on desktop)
Root Cause
RNS uses the pattern file = open(...); ...; file.close() in multiple places. This is:
- Not exception-safe: If an exception occurs before
.close(), the file handle leaks - Non-deterministic: Files eventually close via garbage collection, but timing is unpredictable
- Against Python best practices: Should use context managers (
withstatements)
Patched Files
1. RNS/Destination.py
Lines Fixed: 216-218 (_persist_ratchets), 441-448 (_reload_ratchets)
Problem:
- Line 441: No
.close()at all - file handle never explicitly closed (the ResourceWarning we saw) - Line 216: Has
.close()but not exception-safe
Impact:
- Ratchet files are loaded/saved during destination initialization
- Retry logic can leak 2 file handles per failure
- High-impact on LXMF router with many destinations
Fix:
# Before (line 441 - NO close at all!):
ratchets_file = open(ratchets_path, "rb")
persisted_data = umsgpack.unpackb(ratchets_file.read())
# ... rest of function ...
# File never closed!
# After (exception-safe):
with open(ratchets_path, "rb") as ratchets_file:
persisted_data = umsgpack.unpackb(ratchets_file.read())
# ... rest of function ...
# File automatically closed, even on exception
2. RNS/__init__.py
Lines Fixed: 149-151 (log function)
Problem:
- Has
.close()but not exception-safe - Logging is called very frequently throughout RNS
- File handle leaks can accumulate quickly
Impact:
- Every log message to file opens a new file handle
- High-frequency logging scenarios (DEBUG/EXTREME levels) are especially vulnerable
- Can exhaust file descriptors under heavy logging
Fix:
# Before (not exception-safe):
file = open(logfile, "a")
file.write(logstring+"\n")
file.close() # If exception in write(), never reached
# After (exception-safe):
with open(logfile, "a") as file:
file.write(logstring+"\n")
# File always closed, even on exception
Additional Files With Issues (Not Patched Yet)
These files have similar issues but with explicit .close() calls (better than Destination.py:441, but still not exception-safe). Lower priority for patching:
RNS/Transport.py
- Lines 187-190, 229-231, 276-278, 2933-2935
- All have explicit
.close()calls - Risk: Medium (not as critical as Destination.py)
RNS/Resource.py
- Lines 689-691, 697-699, 719-721, 726-732
- All have explicit
.close()calls - Risk: Medium (resource assembly operations)
Deployment Process
The patched files are deployed during Reticulum initialization:
- Chaquopy pip installs RNS to:
app/build/python/pip/debug/common/RNS/ - ReticulumWrapper copies patches from:
python/patches/RNS/ - Patches override pip-installed files at runtime
See: python/reticulum_wrapper.py - _deploy_rns_patches() method
Testing
After deploying patches, verify in logcat:
adb logcat | grep -E "ResourceWarning|unclosed file"
Expected: No ResourceWarning messages for Destination.py or init.py file operations
Upstream Status
Reported: [TODO: Add GitHub issue link]
Status: Not yet reported to RNS project
Reason: Desktop users don't see warnings (disabled by default), so issue likely unknown
Plan:
- Test patches thoroughly in Columba
- Report issue to RNS GitHub with detailed explanation
- Submit PR with fixes
- Remove local patches when RNS upstream includes fix
When To Remove These Patches
These patches can be safely removed when:
- RNS upstream fixes the file handling issues
- Columba updates to the fixed RNS version
- Testing confirms ResourceWarnings are gone
Technical Details
Context Manager Pattern
Python's with statement uses the context manager protocol:
with open(path, "mode") as file:
# do stuff
# __exit__() always called here, closes file
Guarantees:
- File is closed when exiting the
withblock - Works even if exception is raised
- Works even if
returnstatement executed - Cleaner, more Pythonic code
Exception Safety
The original pattern fails if exception occurs:
file = open(path) # ← File opened
data = process(file.read()) # ← Exception here!
file.close() # ← Never reached, file stays open
With context manager:
with open(path) as file: # ← File opened
data = process(file.read()) # ← Exception here!
# ← File ALWAYS closed here via __exit__()
References
- Chaquopy Release Notes: https://chaquo.com/chaquopy/doc/current/changelog.html#id63
- Version 13.0.0 (2022-11-21): "Enable all warnings including ResourceWarning"
- Python ResourceWarning: https://docs.python.org/3/library/exceptions.html#ResourceWarning
- Context Managers: https://docs.python.org/3/reference/datamodel.html#context-managers
- PEP 343: https://peps.python.org/pep-0343/ (The "with" statement)
Version Info
- Created: 2025-11-06
- RNS Version: Latest from pip (as of 2025-11-06)
- Columba Version: Development
- Python: 3.11 (Chaquopy)
- Platform: Android (Chaquopy environment)