IP parsing C accelerated, use bytes everywhere
This commit is contained in:
parent
7937496882
commit
55877be891
6 changed files with 73 additions and 21 deletions
36
database.py
36
database.py
|
@ -7,7 +7,7 @@ import typing
|
|||
import ipaddress
|
||||
import enum
|
||||
import time
|
||||
import pprint
|
||||
import ctypes
|
||||
|
||||
"""
|
||||
Utility functions to interact with the database.
|
||||
|
@ -20,6 +20,8 @@ C = None # Cursor
|
|||
TIME_DICT: typing.Dict[str, float] = dict()
|
||||
TIME_LAST = time.perf_counter()
|
||||
TIME_STEP = 'start'
|
||||
ACCEL = ctypes.cdll.LoadLibrary('./libaccel.so')
|
||||
ACCEL_IP4_BUF = ctypes.create_unicode_buffer('Z'*32, 32)
|
||||
|
||||
|
||||
def time_step(step: str) -> None:
|
||||
|
@ -127,9 +129,12 @@ def ip_flat(address: ipaddress.IPv4Address) -> str:
|
|||
return ''.join(map(str, ip_get_bits(address)))
|
||||
|
||||
|
||||
def ip4_flat(address: str) -> str:
|
||||
return '{:08b}{:08b}{:08b}{:08b}'.format(
|
||||
*[int(c) for c in address.split('.')])
|
||||
def ip4_flat(address: bytes) -> typing.Optional[str]:
|
||||
carg = ctypes.c_char_p(address)
|
||||
ret = ACCEL.ip4_flat(carg, ACCEL_IP4_BUF)
|
||||
if ret != 0:
|
||||
return None
|
||||
return ACCEL_IP4_BUF.value
|
||||
|
||||
|
||||
RULE_IP4NETWORK_COMMAND = \
|
||||
|
@ -165,23 +170,22 @@ FEED_A_COMMAND_UPSERT = \
|
|||
'WHERE updated=0 OR firstparty<?'
|
||||
|
||||
|
||||
def feed_a(name: str, value_ip: str) -> None:
|
||||
def feed_a(name: bytes, value_ip: bytes) -> None:
|
||||
assert C
|
||||
assert CONN
|
||||
time_step('a_flat')
|
||||
try:
|
||||
value = ip4_flat(value_ip)
|
||||
except (ValueError, IndexError):
|
||||
value_dec = ip4_flat(value_ip)
|
||||
if value_dec is None:
|
||||
# Malformed IPs
|
||||
return
|
||||
time_step('a_fetch')
|
||||
C.execute(FEED_A_COMMAND_FETCH, (value,))
|
||||
C.execute(FEED_A_COMMAND_FETCH, (value_dec,))
|
||||
base = C.fetchone()
|
||||
time_step('a_fetch_confirm')
|
||||
if not base:
|
||||
return
|
||||
b_key, b_firstparty = base
|
||||
if not value.startswith(b_key):
|
||||
if not value_dec.startswith(b_key):
|
||||
return
|
||||
name = name[::-1]
|
||||
time_step('a_upsert')
|
||||
|
@ -212,23 +216,25 @@ FEED_CNAME_COMMAND_UPSERT = \
|
|||
'WHERE updated=0 OR firstparty<?'
|
||||
|
||||
|
||||
def feed_cname(name: str, value: str) -> None:
|
||||
def feed_cname(name: bytes, value: bytes) -> None:
|
||||
assert C
|
||||
assert CONN
|
||||
time_step('cname_decode')
|
||||
value = value[::-1]
|
||||
value_dec = value.decode()
|
||||
time_step('cname_fetch')
|
||||
C.execute(FEED_CNAME_COMMAND_FETCH, (value,))
|
||||
C.execute(FEED_CNAME_COMMAND_FETCH, (value_dec,))
|
||||
base = C.fetchone()
|
||||
time_step('cname_fetch_confirm')
|
||||
if not base:
|
||||
# Should only happen at an extremum of the database
|
||||
return
|
||||
b_key, b_type, b_firstparty = base
|
||||
matching = b_key == value[:len(b_key)] and (
|
||||
len(value) == len(b_key)
|
||||
matching = b_key == value_dec[:len(b_key)] and (
|
||||
len(value_dec) == len(b_key)
|
||||
or (
|
||||
b_type == RowType.DomainTree.value
|
||||
and value[len(b_key)] == '.'
|
||||
and value_dec[len(b_key)] == '.'
|
||||
)
|
||||
)
|
||||
if not matching:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue