mirror of
https://github.com/logos-storage/nim-libplum.git
synced 2026-06-07 01:29:27 +00:00
Add nph formating
This commit is contained in:
parent
f7993b02bf
commit
5a3600278f
4
.dockerignore
Normal file
4
.dockerignore
Normal file
@ -0,0 +1,4 @@
|
||||
vendor/libplum/build/
|
||||
tests/test_plum
|
||||
nimcache/
|
||||
.git/
|
||||
@ -111,6 +111,14 @@ Three env vars control verbosity:
|
||||
TEST_VERBOSE=1 MINIUPNPD_VERBOSE=1 LIBPLUM_VERBOSE=1 nimble testIntegration
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
Format the code with [nph](https://github.com/arnetheduck/nph):
|
||||
|
||||
```bash
|
||||
nimble format
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed and distributed under either of
|
||||
|
||||
@ -19,6 +19,9 @@ proc compileStaticLibraries() =
|
||||
exec("cmake --build build")
|
||||
cpFile("build/libplum.a", "libplum.a")
|
||||
|
||||
task format, "format Nim code using nph":
|
||||
exec "nph libplum/ tests/"
|
||||
|
||||
task buildBundledLibs, "build bundled libraries":
|
||||
compileStaticLibraries()
|
||||
|
||||
|
||||
@ -19,11 +19,13 @@ const
|
||||
# Nim has no equivalent, so the generated C code drops the `const`, causing
|
||||
# a type mismatch warning in GCC 15+. This pragma suppresses that warning
|
||||
# only in this translation unit and is valid for both C and C++.
|
||||
{.emit: """
|
||||
{.
|
||||
emit: """
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic ignored "-Wno-incompatible-pointer-types"
|
||||
#endif
|
||||
""".}
|
||||
"""
|
||||
.}
|
||||
|
||||
when defined(windows):
|
||||
{.passl: "-lws2_32 -liphlpapi -lbcrypt".}
|
||||
@ -31,69 +33,74 @@ else:
|
||||
{.passl: "-lpthread".}
|
||||
|
||||
const
|
||||
PLUM_ERR_SUCCESS* = cint(0)
|
||||
PLUM_ERR_INVALID* = cint(-1)
|
||||
PLUM_ERR_FAILED* = cint(-2)
|
||||
PLUM_ERR_SUCCESS* = cint(0)
|
||||
PLUM_ERR_INVALID* = cint(-1)
|
||||
PLUM_ERR_FAILED* = cint(-2)
|
||||
PLUM_ERR_NOT_AVAIL* = cint(-3)
|
||||
|
||||
PLUM_MAX_HOST_LEN* = 256
|
||||
PLUM_MAX_HOST_LEN* = 256
|
||||
PLUM_MAX_ADDRESS_LEN* = 64
|
||||
|
||||
|
||||
# Import plum enums with cint size
|
||||
|
||||
type
|
||||
plum_log_level_t* {.importc: "plum_log_level_t", header: "plum.h",
|
||||
size: sizeof(cint).} = enum
|
||||
plum_log_level_t* {.
|
||||
importc: "plum_log_level_t", header: "plum.h", size: sizeof(cint)
|
||||
.} = enum
|
||||
PLUM_LOG_LEVEL_VERBOSE = 0
|
||||
PLUM_LOG_LEVEL_DEBUG = 1
|
||||
PLUM_LOG_LEVEL_INFO = 2
|
||||
PLUM_LOG_LEVEL_WARN = 3
|
||||
PLUM_LOG_LEVEL_ERROR = 4
|
||||
PLUM_LOG_LEVEL_FATAL = 5
|
||||
PLUM_LOG_LEVEL_NONE = 6
|
||||
PLUM_LOG_LEVEL_DEBUG = 1
|
||||
PLUM_LOG_LEVEL_INFO = 2
|
||||
PLUM_LOG_LEVEL_WARN = 3
|
||||
PLUM_LOG_LEVEL_ERROR = 4
|
||||
PLUM_LOG_LEVEL_FATAL = 5
|
||||
PLUM_LOG_LEVEL_NONE = 6
|
||||
|
||||
plum_ip_protocol_t* {.importc: "plum_ip_protocol_t", header: "plum.h",
|
||||
size: sizeof(cint).} = enum
|
||||
plum_ip_protocol_t* {.
|
||||
importc: "plum_ip_protocol_t", header: "plum.h", size: sizeof(cint)
|
||||
.} = enum
|
||||
PLUM_IP_PROTOCOL_TCP = 0
|
||||
PLUM_IP_PROTOCOL_UDP = 1
|
||||
|
||||
plum_state_t* {.importc: "plum_state_t", header: "plum.h",
|
||||
size: sizeof(cint).} = enum
|
||||
PLUM_STATE_DESTROYED = 0
|
||||
PLUM_STATE_PENDING = 1
|
||||
PLUM_STATE_SUCCESS = 2
|
||||
PLUM_STATE_FAILURE = 3
|
||||
plum_state_t* {.importc: "plum_state_t", header: "plum.h", size: sizeof(cint).} = enum
|
||||
PLUM_STATE_DESTROYED = 0
|
||||
PLUM_STATE_PENDING = 1
|
||||
PLUM_STATE_SUCCESS = 2
|
||||
PLUM_STATE_FAILURE = 3
|
||||
PLUM_STATE_DESTROYING = 4
|
||||
|
||||
plum_mapping_protocol_t* {.importc: "plum_mapping_protocol_t", header: "plum.h",
|
||||
size: sizeof(cint).} = enum
|
||||
plum_mapping_protocol_t* {.
|
||||
importc: "plum_mapping_protocol_t", header: "plum.h", size: sizeof(cint)
|
||||
.} = enum
|
||||
PLUM_MAPPING_PROTOCOL_UNKNOWN = 0
|
||||
PLUM_MAPPING_PROTOCOL_PCP = 1
|
||||
PLUM_MAPPING_PROTOCOL_NATPMP = 2
|
||||
PLUM_MAPPING_PROTOCOL_UPNP = 3
|
||||
PLUM_MAPPING_PROTOCOL_DIRECT = 4
|
||||
|
||||
PLUM_MAPPING_PROTOCOL_PCP = 1
|
||||
PLUM_MAPPING_PROTOCOL_NATPMP = 2
|
||||
PLUM_MAPPING_PROTOCOL_UPNP = 3
|
||||
PLUM_MAPPING_PROTOCOL_DIRECT = 4
|
||||
|
||||
# Define the callback to receive the plum logs
|
||||
plum_log_callback_t* = proc(level: plum_log_level_t, message: cstring) {.cdecl.}
|
||||
|
||||
# Define the config struct, passed by copy (usual for struct).
|
||||
plum_config_t* {.importc: "plum_config_t", header: "plum.h", bycopy.} = object
|
||||
log_level* {.importc: "log_level".}: plum_log_level_t
|
||||
log_callback* {.importc: "log_callback".}: plum_log_callback_t
|
||||
dummytls_domain* {.importc: "dummytls_domain".}: cstring
|
||||
discover_timeout* {.importc: "discover_timeout".}: cint # msecs, 0 means use default (10000)
|
||||
mapping_timeout* {.importc: "mapping_timeout".}: cint # msecs, 0 means use default (10000)
|
||||
recheck_period* {.importc: "recheck_period".}: cint # msecs, 0 means use default (300000)
|
||||
log_level* {.importc: "log_level".}: plum_log_level_t
|
||||
log_callback* {.importc: "log_callback".}: plum_log_callback_t
|
||||
dummytls_domain* {.importc: "dummytls_domain".}: cstring
|
||||
discover_timeout* {.importc: "discover_timeout".}: cint
|
||||
# msecs, 0 means use default (10000)
|
||||
mapping_timeout* {.importc: "mapping_timeout".}: cint
|
||||
# msecs, 0 means use default (10000)
|
||||
recheck_period* {.importc: "recheck_period".}: cint
|
||||
# msecs, 0 means use default (300000)
|
||||
|
||||
# Define the mapping struct, passed by copy (usual for struct).
|
||||
# The user_ptr is a pointer to the MappingHandle in order to receive the result
|
||||
plum_mapping_t* {.importc: "plum_mapping_t", header: "plum.h", bycopy.} = object
|
||||
protocol* {.importc: "protocol".}: plum_ip_protocol_t
|
||||
protocol* {.importc: "protocol".}: plum_ip_protocol_t
|
||||
mapping_protocol* {.importc: "mapping_protocol".}: plum_mapping_protocol_t
|
||||
internal_port* {.importc: "internal_port".}: uint16
|
||||
external_port* {.importc: "external_port".}: uint16
|
||||
external_host* {.importc: "external_host".}: array[PLUM_MAX_HOST_LEN, char]
|
||||
user_ptr* {.importc: "user_ptr".}: pointer
|
||||
internal_port* {.importc: "internal_port".}: uint16
|
||||
external_port* {.importc: "external_port".}: uint16
|
||||
external_host* {.importc: "external_host".}: array[PLUM_MAX_HOST_LEN, char]
|
||||
user_ptr* {.importc: "user_ptr".}: pointer
|
||||
|
||||
# Define the callback to receive the mapping result
|
||||
plum_mapping_callback_t* =
|
||||
@ -101,22 +108,24 @@ type
|
||||
|
||||
# Import plum functions
|
||||
|
||||
proc plum_init*(config: ptr plum_config_t): cint
|
||||
{.importc: "plum_init", header: "plum.h".}
|
||||
proc plum_init*(
|
||||
config: ptr plum_config_t
|
||||
): cint {.importc: "plum_init", header: "plum.h".}
|
||||
|
||||
proc plum_cleanup*(): cint
|
||||
{.importc: "plum_cleanup", header: "plum.h".}
|
||||
proc plum_cleanup*(): cint {.importc: "plum_cleanup", header: "plum.h".}
|
||||
|
||||
proc plum_create_mapping*(mapping: ptr plum_mapping_t,
|
||||
callback: plum_mapping_callback_t): cint
|
||||
{.importc: "plum_create_mapping", header: "plum.h".}
|
||||
proc plum_create_mapping*(
|
||||
mapping: ptr plum_mapping_t, callback: plum_mapping_callback_t
|
||||
): cint {.importc: "plum_create_mapping", header: "plum.h".}
|
||||
|
||||
proc plum_query_mapping*(id: cint, state: ptr plum_state_t,
|
||||
mapping: ptr plum_mapping_t): cint
|
||||
{.importc: "plum_query_mapping", header: "plum.h".}
|
||||
proc plum_query_mapping*(
|
||||
id: cint, state: ptr plum_state_t, mapping: ptr plum_mapping_t
|
||||
): cint {.importc: "plum_query_mapping", header: "plum.h".}
|
||||
|
||||
proc plum_destroy_mapping*(id: cint): cint
|
||||
{.importc: "plum_destroy_mapping", header: "plum.h".}
|
||||
proc plum_destroy_mapping*(
|
||||
id: cint
|
||||
): cint {.importc: "plum_destroy_mapping", header: "plum.h".}
|
||||
|
||||
proc plum_get_local_address*(buffer: cstring, size: csize_t): cint
|
||||
{.importc: "plum_get_local_address", header: "plum.h".}
|
||||
proc plum_get_local_address*(
|
||||
buffer: cstring, size: csize_t
|
||||
): cint {.importc: "plum_get_local_address", header: "plum.h".}
|
||||
|
||||
@ -12,11 +12,13 @@ import chronos/threadsync
|
||||
import results
|
||||
import ./libplum
|
||||
|
||||
{.emit: """
|
||||
{.
|
||||
emit: """
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
|
||||
#endif
|
||||
""".}
|
||||
"""
|
||||
.}
|
||||
|
||||
export results
|
||||
|
||||
@ -28,18 +30,18 @@ type
|
||||
UDP = PLUM_IP_PROTOCOL_UDP.int
|
||||
|
||||
PlumState* = enum
|
||||
Destroyed = PLUM_STATE_DESTROYED.int
|
||||
Pending = PLUM_STATE_PENDING.int
|
||||
Success = PLUM_STATE_SUCCESS.int
|
||||
Failure = PLUM_STATE_FAILURE.int
|
||||
Destroyed = PLUM_STATE_DESTROYED.int
|
||||
Pending = PLUM_STATE_PENDING.int
|
||||
Success = PLUM_STATE_SUCCESS.int
|
||||
Failure = PLUM_STATE_FAILURE.int
|
||||
Destroying = PLUM_STATE_DESTROYING.int
|
||||
|
||||
MappingProtocol* = enum
|
||||
Unknown = PLUM_MAPPING_PROTOCOL_UNKNOWN.int
|
||||
PCP = PLUM_MAPPING_PROTOCOL_PCP.int
|
||||
NatPmp = PLUM_MAPPING_PROTOCOL_NATPMP.int
|
||||
UPnP = PLUM_MAPPING_PROTOCOL_UPNP.int
|
||||
Direct = PLUM_MAPPING_PROTOCOL_DIRECT.int
|
||||
PCP = PLUM_MAPPING_PROTOCOL_PCP.int
|
||||
NatPmp = PLUM_MAPPING_PROTOCOL_NATPMP.int
|
||||
UPnP = PLUM_MAPPING_PROTOCOL_UPNP.int
|
||||
Direct = PLUM_MAPPING_PROTOCOL_DIRECT.int
|
||||
|
||||
PlumMapping* = object
|
||||
protocol*: PlumProtocol
|
||||
@ -52,8 +54,7 @@ type
|
||||
id*: cint
|
||||
mapping*: PlumMapping
|
||||
|
||||
PlumStateCallback* =
|
||||
proc(state: PlumState, mapping: PlumMapping) {.callback.}
|
||||
PlumStateCallback* = proc(state: PlumState, mapping: PlumMapping) {.callback.}
|
||||
|
||||
MappingHandle = ref object
|
||||
signal: ThreadSignalPtr
|
||||
@ -76,9 +77,11 @@ type
|
||||
# libplum calls mappingCallback from its own C thread. Under refc, any thread
|
||||
# that touches Nim objects must register with the GC first.
|
||||
template foreignThreadGc(body: untyped) =
|
||||
when declared(setupForeignThreadGc): setupForeignThreadGc()
|
||||
when declared(setupForeignThreadGc):
|
||||
setupForeignThreadGc()
|
||||
body
|
||||
when declared(tearDownForeignThreadGc): tearDownForeignThreadGc()
|
||||
when declared(tearDownForeignThreadGc):
|
||||
tearDownForeignThreadGc()
|
||||
|
||||
var activeMappingsLock: Lock
|
||||
var activeMappings {.guard: activeMappingsLock.}: Table[cint, MappingHandle]
|
||||
@ -92,8 +95,9 @@ template withSafeLock(body: untyped) =
|
||||
withLock activeMappingsLock:
|
||||
body
|
||||
|
||||
proc mappingCallback(id: cint, state: plum_state_t,
|
||||
raw: ptr plum_mapping_t) {.cdecl, raises: [].} =
|
||||
proc mappingCallback(
|
||||
id: cint, state: plum_state_t, raw: ptr plum_mapping_t
|
||||
) {.cdecl, raises: [].} =
|
||||
## Called from libplum's internal C thread on SUCCESS, FAILURE, and DESTROYED.
|
||||
|
||||
foreignThreadGc:
|
||||
@ -139,7 +143,7 @@ proc mappingCallback(id: cint, state: plum_state_t,
|
||||
mappingProtocol: MappingProtocol(raw[].mapping_protocol.int),
|
||||
internalPort: raw[].internal_port,
|
||||
externalPort: raw[].external_port,
|
||||
externalHost: $cast[cstring](addr raw[].external_host)
|
||||
externalHost: $cast[cstring](addr raw[].external_host),
|
||||
)
|
||||
handle.onStateChange(plumState, mapping)
|
||||
|
||||
@ -147,7 +151,7 @@ proc init*(
|
||||
logLevel: plum_log_level_t = PLUM_LOG_LEVEL_NONE,
|
||||
discoverTimeout: int = 0,
|
||||
mappingTimeout: int = 0,
|
||||
recheckPeriod: int = 0
|
||||
recheckPeriod: int = 0,
|
||||
): Result[void, string] {.raises: [].} =
|
||||
## init MUST be called to setup internal plum thread (plum_init).
|
||||
|
||||
@ -157,7 +161,7 @@ proc init*(
|
||||
dummytls_domain: nil,
|
||||
discover_timeout: discoverTimeout.cint,
|
||||
mapping_timeout: mappingTimeout.cint,
|
||||
recheck_period: recheckPeriod.cint
|
||||
recheck_period: recheckPeriod.cint,
|
||||
)
|
||||
|
||||
let res = plum_init(addr config)
|
||||
@ -180,21 +184,18 @@ proc createMapping*(
|
||||
internalPort: uint16,
|
||||
externalPort: uint16 = 0,
|
||||
timeout: Duration = seconds(30),
|
||||
onStateChange: PlumStateCallback = nil
|
||||
onStateChange: PlumStateCallback = nil,
|
||||
): Future[Result[MappingResult, string]] {.async: (raises: [CancelledError]).} =
|
||||
let signal = ThreadSignalPtr.new().valueOr:
|
||||
return err("plum: cannot create signal: " & $error)
|
||||
|
||||
let handle = MappingHandle(
|
||||
signal: signal,
|
||||
onStateChange: onStateChange
|
||||
)
|
||||
let handle = MappingHandle(signal: signal, onStateChange: onStateChange)
|
||||
|
||||
var req = plum_mapping_t(
|
||||
protocol: plum_ip_protocol_t(protocol.int),
|
||||
internal_port: internalPort,
|
||||
external_port: externalPort,
|
||||
user_ptr: cast[pointer](handle)
|
||||
user_ptr: cast[pointer](handle),
|
||||
)
|
||||
|
||||
# Avoid issue with refc.
|
||||
@ -252,7 +253,7 @@ proc createMapping*(
|
||||
mappingProtocol: h.resolvedMappingProtocol,
|
||||
internalPort: h.resolvedInternalPort,
|
||||
externalPort: h.resolvedExternalPort,
|
||||
externalHost: $cast[cstring](unsafeAddr h.resolvedExternalHost)
|
||||
externalHost: $cast[cstring](unsafeAddr h.resolvedExternalHost),
|
||||
)
|
||||
|
||||
if resolvedState == Success:
|
||||
|
||||
@ -41,14 +41,20 @@ const miniupnp_protocol {.strdefine.} = ""
|
||||
# must fall back to NAT-PMP on its own (tests the silent-timeout fallback fix).
|
||||
when miniupnp_protocol != "":
|
||||
const expectedMappingProtocol =
|
||||
when miniupnp_protocol == "pcp": PCP
|
||||
elif miniupnp_protocol == "natpmp": NatPmp
|
||||
else: UPnP
|
||||
when miniupnp_protocol == "pcp":
|
||||
PCP
|
||||
elif miniupnp_protocol == "natpmp":
|
||||
NatPmp
|
||||
else:
|
||||
UPnP
|
||||
|
||||
suite "plum - " & miniupnp_protocol & " using miniupnp":
|
||||
test "createMapping TCP and destroyMapping":
|
||||
let logLevel = if getEnv("LIBPLUM_VERBOSE") == "1": PLUM_LOG_LEVEL_VERBOSE
|
||||
else: PLUM_LOG_LEVEL_NONE
|
||||
let logLevel =
|
||||
if getEnv("LIBPLUM_VERBOSE") == "1":
|
||||
PLUM_LOG_LEVEL_VERBOSE
|
||||
else:
|
||||
PLUM_LOG_LEVEL_NONE
|
||||
check init(discoverTimeout = 15000, logLevel = logLevel).isOk()
|
||||
|
||||
let r = waitFor createMapping(TCP, 8101, timeout = seconds(40))
|
||||
@ -60,14 +66,18 @@ when miniupnp_protocol != "":
|
||||
check res.mapping.mappingProtocol == expectedMappingProtocol
|
||||
check hasMapping(res.id)
|
||||
if getEnv("TEST_VERBOSE") == "1":
|
||||
echo miniupnp_protocol & " TCP: " & res.mapping.externalHost & ":" & $res.mapping.externalPort
|
||||
echo miniupnp_protocol & " TCP: " & res.mapping.externalHost & ":" &
|
||||
$res.mapping.externalPort
|
||||
destroyMapping(res.id)
|
||||
|
||||
discard cleanup()
|
||||
|
||||
test "createMapping UDP and destroying":
|
||||
let logLevel = if getEnv("LIBPLUM_VERBOSE") == "1": PLUM_LOG_LEVEL_VERBOSE
|
||||
else: PLUM_LOG_LEVEL_NONE
|
||||
let logLevel =
|
||||
if getEnv("LIBPLUM_VERBOSE") == "1":
|
||||
PLUM_LOG_LEVEL_VERBOSE
|
||||
else:
|
||||
PLUM_LOG_LEVEL_NONE
|
||||
check init(discoverTimeout = 2000, logLevel = logLevel).isOk()
|
||||
|
||||
let r = waitFor createMapping(UDP, 8090, timeout = seconds(40))
|
||||
@ -77,7 +87,8 @@ when miniupnp_protocol != "":
|
||||
check res.mapping.externalPort > 0
|
||||
check res.mapping.mappingProtocol == expectedMappingProtocol
|
||||
if getEnv("TEST_VERBOSE") == "1":
|
||||
echo miniupnp_protocol & " UDP: " & res.mapping.externalHost & ":" & $res.mapping.externalPort
|
||||
echo miniupnp_protocol & " UDP: " & res.mapping.externalHost & ":" &
|
||||
$res.mapping.externalPort
|
||||
destroyMapping(res.id)
|
||||
|
||||
discard cleanup()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user