In the Data case the client pointer was looked up under clients_mutex
but used (pushBuffer) after the unlock; a user-initiated delete() of
the same client raced with the read thread and hit freed memory.
In the Disconnect case the client was stopped/closed and appended to
removed_clients_ (without the lock, unlike every other site) after
the unlock, with the same UAF window and a race on the vector itself.
Do both uses while holding clients_mutex: a concurrent delete() is
serialized with this block by clientDeleted() (the deleted() event),
so the client cannot be freed while it is in use. Setting
is_connected=false first also stops pushBuffer from buffering into a
dying client.
piMini(max_size, buff.size()) implicitly narrows size_t to int,
which is UB for large buffers. Replace with explicit piMin<ssize_t>
matching the correct pattern used in picloudclient.cpp.
in almost all methods removed timeouts in milliseconds, replaced to PISystemTime
PITimer rewrite, remove internal impl, now only thread implementation, API similar to PIThread
PITimer API no longer pass void*
PIPeer, PIConnection improved stability on reinit and exit
PISystemTime new methods
pisd now exit without hanging
pipacketextractor Header mode now more flexible
fix splitTime mode
more refactoring
add virtual override to functions
remove piforeach
replace 0 to nullptr
iterate over pimap via iterators
replace CONNECTU to CONNECT# with compile time check
PIIODevice small refactoring
new PIIODevice virtual methods: threadedReadTerminated() and threadedWriteTerminated()
PIIODevice::stop now accept bool "hard" instead of "wait"
PIStreamPacker new features: packet size crypt and aggressive optimization