Skip to content

Commit 0e0ac6b

Browse files
authored
Update pywwwget_py3_optimized_bluetooth.py
1 parent 2023a79 commit 0e0ac6b

1 file changed

Lines changed: 261 additions & 0 deletions

File tree

pywwwget_py3_optimized_bluetooth.py

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3777,6 +3777,267 @@ def send_from_fileobj(fileobj, host, port, proto="tcp", path_text=None, **kwargs
37773777
return _udp_quic_send(fileobj, host, port, **kwargs)
37783778
return _udp_seq_send(fileobj, host, port, **kwargs)
37793779

3780+
def _udp_raw_send(fileobj, host, port, **kwargs):
3781+
logger = _logger_from_kwargs(kwargs)
3782+
addr = (host or "127.0.0.1", int(port))
3783+
3784+
# ---- normalize bool-ish flags (URL query values may be strings) ----
3785+
handshake = _kw_bool(kwargs.get("handshake", True), True)
3786+
raw_ack = _kw_bool(kwargs.get("raw_ack", False), False)
3787+
raw_meta = _kw_bool(kwargs.get("raw_meta", True), True)
3788+
raw_sha = _kw_bool(kwargs.get("raw_sha", False), False)
3789+
wait = _kw_bool(kwargs.get("wait", True), True) or _kw_bool(kwargs.get("connect_wait", False), False)
3790+
3791+
verbose = _kw_bool(kwargs.get("verbose", False), False)
3792+
3793+
def _log(msg):
3794+
_net_log(verbose, msg, logger=logger)
3795+
3796+
# ---- numeric params ----
3797+
try:
3798+
chunk = int(kwargs.get("chunk", 1200))
3799+
except Exception:
3800+
chunk = 1200
3801+
if chunk < 256:
3802+
chunk = 256
3803+
3804+
try:
3805+
wt = kwargs.get("wait_timeout", None)
3806+
wt = float(wt) if wt is not None else None
3807+
except Exception:
3808+
wt = None
3809+
3810+
try:
3811+
hello_iv = float(kwargs.get("hello_interval", 0.1) or 0.1)
3812+
except Exception:
3813+
hello_iv = 0.1
3814+
if hello_iv <= 0:
3815+
hello_iv = 0.1
3816+
3817+
# ---- compute total remaining length (for META and/or HASH) ----
3818+
total_len = None
3819+
pos = None
3820+
if raw_meta or raw_sha:
3821+
try:
3822+
pos = fileobj.tell()
3823+
fileobj.seek(0, os.SEEK_END)
3824+
end = fileobj.tell()
3825+
fileobj.seek(pos, os.SEEK_SET)
3826+
total_len = int(end - pos)
3827+
if total_len < 0:
3828+
total_len = None
3829+
except Exception:
3830+
total_len = None
3831+
try:
3832+
if pos is not None:
3833+
fileobj.seek(pos, os.SEEK_SET)
3834+
except Exception:
3835+
pass
3836+
3837+
# ---- precompute expected hash (optional) ----
3838+
expected_hex = None
3839+
raw_hash = (kwargs.get("raw_hash", "sha256") or "sha256").lower()
3840+
if raw_sha and total_len is not None:
3841+
try:
3842+
h = hashlib.sha256() if raw_hash != "md5" else hashlib.md5()
3843+
cur = fileobj.tell()
3844+
while True:
3845+
b = fileobj.read(65536)
3846+
if not b:
3847+
break
3848+
h.update(_to_bytes(b))
3849+
expected_hex = h.hexdigest()
3850+
fileobj.seek(cur, os.SEEK_SET)
3851+
except Exception:
3852+
expected_hex = None
3853+
try:
3854+
if pos is not None:
3855+
fileobj.seek(pos, os.SEEK_SET)
3856+
except Exception:
3857+
pass
3858+
3859+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
3860+
3861+
try:
3862+
# ---- handshake / wait-for-receiver ----
3863+
tok = kwargs.get("token")
3864+
tok = _hs_token() if tok is None else _to_bytes(tok)
3865+
3866+
if wait:
3867+
start_t = time.time()
3868+
while True:
3869+
if wt is not None and wt >= 0 and (time.time() - start_t) >= wt:
3870+
_log("UDP raw: wait_timeout reached; no receiver READY")
3871+
try:
3872+
sock.close()
3873+
except Exception:
3874+
pass
3875+
return False
3876+
3877+
# announce
3878+
if handshake:
3879+
try:
3880+
sock.sendto(b"HELLO " + tok + b"\n", addr)
3881+
except Exception:
3882+
pass
3883+
3884+
if raw_meta and total_len is not None:
3885+
try:
3886+
sock.sendto(b"META " + str(total_len).encode("ascii") + b"\n", addr)
3887+
except Exception:
3888+
pass
3889+
3890+
if raw_sha and expected_hex:
3891+
try:
3892+
sock.sendto(b"HASH " + raw_hash.encode("ascii") + b" " + expected_hex.encode("ascii") + b"\n", addr)
3893+
except Exception:
3894+
pass
3895+
3896+
# wait briefly for READY
3897+
try:
3898+
sock.settimeout(hello_iv)
3899+
except Exception:
3900+
pass
3901+
3902+
try:
3903+
pkt, _a = sock.recvfrom(1024)
3904+
if pkt.startswith(b"READY"):
3905+
# READY or READY <token>
3906+
if b" " in pkt:
3907+
rt = pkt.split(None, 1)[1].strip()
3908+
if rt and rt != tok:
3909+
continue
3910+
_log("UDP raw: received READY from receiver")
3911+
break
3912+
except socket.timeout:
3913+
continue
3914+
except Exception:
3915+
continue
3916+
else:
3917+
# if not waiting, still send META/HASH once up front
3918+
if handshake:
3919+
try:
3920+
sock.sendto(b"HELLO " + tok + b"\n", addr)
3921+
except Exception:
3922+
pass
3923+
if raw_meta and total_len is not None:
3924+
try:
3925+
sock.sendto(b"META " + str(total_len).encode("ascii") + b"\n", addr)
3926+
except Exception:
3927+
pass
3928+
if raw_sha and expected_hex:
3929+
try:
3930+
sock.sendto(b"HASH " + raw_hash.encode("ascii") + b" " + expected_hex.encode("ascii") + b"\n", addr)
3931+
except Exception:
3932+
pass
3933+
3934+
# ---- send data ----
3935+
if raw_ack:
3936+
# sliding window retransmit
3937+
try:
3938+
ack_to = float(kwargs.get("raw_ack_timeout", 0.5) or 0.5)
3939+
except Exception:
3940+
ack_to = 0.5
3941+
try:
3942+
retries_max = int(kwargs.get("raw_ack_retries", 40) or 40)
3943+
except Exception:
3944+
retries_max = 40
3945+
try:
3946+
win = int(kwargs.get("raw_ack_window", 1) or 1)
3947+
except Exception:
3948+
win = 1
3949+
if win < 1:
3950+
win = 1
3951+
3952+
try:
3953+
sock.settimeout(ack_to)
3954+
except Exception:
3955+
pass
3956+
3957+
def _make_pkt(seq, data):
3958+
return b"PKT " + str(seq).encode("ascii") + b" " + _to_bytes(data)
3959+
3960+
base_seq = 0
3961+
next_seq = 0
3962+
pkts = {}
3963+
eof = False
3964+
timeout_tries = 0
3965+
3966+
while True:
3967+
# fill window
3968+
while (not eof) and next_seq < base_seq + win:
3969+
data = fileobj.read(chunk)
3970+
if not data:
3971+
eof = True
3972+
break
3973+
pkt = _make_pkt(next_seq, data)
3974+
pkts[next_seq] = pkt
3975+
try:
3976+
sock.sendto(pkt, addr)
3977+
except Exception:
3978+
pass
3979+
next_seq += 1
3980+
3981+
if eof and base_seq == next_seq:
3982+
break
3983+
3984+
try:
3985+
apkt, _a = sock.recvfrom(1024)
3986+
if apkt.startswith(b"ACK "):
3987+
try:
3988+
aseq = int(apkt.split()[1])
3989+
except Exception:
3990+
aseq = -1
3991+
new_base = aseq + 1
3992+
if new_base > base_seq:
3993+
for s in list(pkts.keys()):
3994+
if s < new_base:
3995+
pkts.pop(s, None)
3996+
base_seq = new_base
3997+
timeout_tries = 0
3998+
except socket.timeout:
3999+
timeout_tries += 1
4000+
if retries_max >= 0 and timeout_tries >= retries_max:
4001+
_log("UDP raw: too many ACK timeouts, giving up")
4002+
return False
4003+
# retransmit all in-flight
4004+
for s in range(base_seq, next_seq):
4005+
pkt = pkts.get(s)
4006+
if pkt is None:
4007+
continue
4008+
try:
4009+
sock.sendto(pkt, addr)
4010+
except Exception:
4011+
pass
4012+
except Exception:
4013+
# treat as timeout-ish
4014+
timeout_tries += 1
4015+
4016+
else:
4017+
# legacy raw: just send datagrams
4018+
while True:
4019+
data = fileobj.read(chunk)
4020+
if not data:
4021+
break
4022+
try:
4023+
sock.sendto(_to_bytes(data), addr)
4024+
except Exception:
4025+
pass
4026+
4027+
# ---- finish ----
4028+
try:
4029+
sock.sendto(b"DONE", addr)
4030+
except Exception:
4031+
pass
4032+
4033+
return True
4034+
4035+
finally:
4036+
try:
4037+
sock.close()
4038+
except Exception:
4039+
pass
4040+
37804041
def _udp_raw_recv(fileobj, host, port, **kwargs):
37814042
logger = _logger_from_kwargs(kwargs)
37824043
addr = (host or "", int(port))

0 commit comments

Comments
 (0)