Skip to content

Commit 0f6a1ad

Browse files
committed
(feat) introduce PT_ControlFrame and relevant helpers
this helps avoid repeated code where struct offset calculations were occurring.
1 parent 97f6955 commit 0f6a1ad

File tree

11 files changed

+455
-362
lines changed

11 files changed

+455
-362
lines changed

pipetap-dll/include/inject/control_server.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <unordered_map>
1010
#include <vector>
1111

12+
#include "pipetap/controlpipe.h"
13+
1214
namespace pipetap::inject {
1315

1416
class ControlServer {
@@ -60,9 +62,7 @@ namespace pipetap::inject {
6062

6163
void handle_inbound_commands(HANDLE h);
6264

63-
void send_control_message(uint16_t type,
64-
const void* meta, uint32_t meta_len,
65-
const void* payload, uint32_t payload_len);
65+
void send_control_message(const PT_ControlFrame& frame);
6666

6767
HANDLE create_events_pipe_instance(); // outbound only (we write)
6868
HANDLE create_commands_pipe_instance(); // inbound only (we read)

pipetap-dll/inject/control_server.cpp

Lines changed: 63 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ namespace pipetap::inject {
213213
strncpy_s(hello.proc_name, sizeof(hello.proc_name), name.c_str(), _TRUNCATE);
214214
log::printf("SendHello: pid=%lu exe=%s", (unsigned long)hello.pid, hello.proc_name);
215215

216-
send_control_message(PT_HELLO, &hello, (uint32_t)sizeof(hello), nullptr, 0);
216+
send_control_message(PT_ControlFrame::FromStruct(PT_HELLO, hello));
217217
}
218218

219219
void ControlServer::send_error(uint32_t code, const char* what)
@@ -224,7 +224,7 @@ namespace pipetap::inject {
224224
e.code = code;
225225
strncpy_s(e.what, sizeof(e.what), (what ? what : "err"), _TRUNCATE);
226226

227-
send_control_message(PT_ERROR, &e, (uint32_t)sizeof(e), nullptr, 0);
227+
send_control_message(PT_ControlFrame::FromStruct(PT_ERROR, e));
228228
}
229229

230230
void ControlServer::send_pipe_io(uint16_t message_type, HANDLE pipe,
@@ -233,18 +233,12 @@ namespace pipetap::inject {
233233
const char* apiName)
234234
{
235235
if (!connected_.load(std::memory_order_relaxed)) return;
236-
HANDLE hW = atomic_load_handle(ctrl_w_);
237-
if (ctrl_broken_.load(std::memory_order_acquire) || !hW || hW == INVALID_HANDLE_VALUE) {
238-
connected_.store(false, std::memory_order_release);
239-
return;
240-
}
241236

242237
uint8_t is_msg = 0;
243238
uint32_t outHint = 0, inHint = 0;
244239
query_pipe_hints(pipe, is_msg, outHint, inHint);
245240

246241
static constexpr uint32_t kMaxSample = 24 * 1024;
247-
uint32_t sample = (total > kMaxSample) ? kMaxSample : total;
248242

249243
std::string pipeName = pipe_name_for_handle(pipe);
250244
if (pipeName.size() > 0xFFFE) pipeName.resize(0xFFFE);
@@ -259,51 +253,27 @@ namespace pipetap::inject {
259253
if (peerImg.size() > 0xFFFE) peerImg.resize(0xFFFE);
260254
}
261255

262-
// Build meta
263-
PT_PipeIo meta{};
264-
meta.pid = GetCurrentProcessId();
265-
meta.tid = GetCurrentThreadId();
266-
meta.dir = dir;
267-
meta.is_message_mode = is_msg;
268-
meta.total_size = total;
269-
meta.sample_size = sample;
270-
meta.out_buf_hint = outHint;
271-
meta.in_buf_hint = inHint;
272-
meta.op_id = op_id;
273-
meta.pipe_len = static_cast<uint16_t>(pipeName.size());
274-
meta.api_len = static_cast<uint16_t>(api.size());
275-
meta.peer_pid = peer.pid;
276-
meta.endpoint_role = peer.role; // 0=unknown, 1=server-end, 2=client-end
277-
meta.image_len = static_cast<uint16_t>(peerImg.size());
278-
279-
const uint32_t meta_len = (uint32_t)sizeof(meta);
280-
const uint32_t name_len = meta.pipe_len;
281-
const uint32_t api_len = meta.api_len;
282-
const uint32_t image_len = meta.image_len;
283-
const uint32_t payload_len = sample;
284-
285-
std::vector<::pipetap::ControlMessageFragment> fragments;
286-
fragments.reserve(1 + (name_len ? 1 : 0) + (api_len ? 1 : 0) + (image_len ? 1 : 0) + ((payload_len && buf) ? 1 : 0));
287-
fragments.push_back({ &meta, meta_len });
288-
if (name_len) fragments.push_back({ pipeName.data(), name_len });
289-
if (api_len) fragments.push_back({ api.data(), api_len });
290-
if (image_len) fragments.push_back({ peerImg.data(), image_len });
291-
if (payload_len && buf) fragments.push_back({ buf, payload_len });
292-
293-
auto msg = ::pipetap::BuildControlMessage(message_type, fragments);
294-
295-
AcquireSRWLockExclusive(&ctrl_lock_);
296-
{
297-
SuppressHooksGuard _guard;
298-
DWORD wrote = 0;
299-
BOOL ok = WriteFile(hW, msg.data(), (DWORD)msg.size(), &wrote, nullptr);
300-
if (!ok || wrote != msg.size()) {
301-
ctrl_broken_.store(true, std::memory_order_release);
302-
connected_.store(false, std::memory_order_release);
303-
(void)atomic_exchange_handle(ctrl_w_, INVALID_HANDLE_VALUE);
304-
}
305-
}
306-
ReleaseSRWLockExclusive(&ctrl_lock_);
256+
PT_PipeIoEnvelope env{};
257+
env.meta.pid = GetCurrentProcessId();
258+
env.meta.tid = GetCurrentThreadId();
259+
env.meta.dir = dir;
260+
env.meta.is_message_mode = is_msg;
261+
env.meta.total_size = total;
262+
env.meta.out_buf_hint = outHint;
263+
env.meta.in_buf_hint = inHint;
264+
env.meta.op_id = op_id;
265+
env.meta.peer_pid = peer.pid;
266+
env.meta.endpoint_role = peer.role; // 0=unknown, 1=server-end, 2=client-end
267+
268+
env.pipe_name = pipeName;
269+
env.api_name = api;
270+
env.peer_image = peerImg;
271+
env.payload = static_cast<const uint8_t*>(buf);
272+
env.payload_len = (buf && total) ? total : 0;
273+
env.max_sample = kMaxSample;
274+
275+
auto frame = PT_BuildPipeIoMessage(message_type, env);
276+
send_control_message(frame);
307277
}
308278

309279
void ControlServer::send_proxy_opened(uint64_t session_id,
@@ -319,7 +289,7 @@ namespace pipetap::inject {
319289
r.is_message_mode = is_message_mode;
320290
r.out_buf_hint = out_hint;
321291
r.in_buf_hint = in_hint;
322-
send_control_message(PT_EVT_PROXY_OPENED, &r, sizeof(r), nullptr, 0);
292+
send_control_message(PT_ControlFrame::FromStruct(PT_EVT_PROXY_OPENED, r));
323293
}
324294

325295
void ControlServer::send_proxy_closed(uint64_t session_id,
@@ -331,7 +301,7 @@ namespace pipetap::inject {
331301
ev.session_id = session_id;
332302
ev.reason = reason;
333303
ev.win32_error = win32_error;
334-
send_control_message(PT_EVT_PROXY_CLOSED, &ev, sizeof(ev), nullptr, 0);
304+
send_control_message(PT_ControlFrame::FromStruct(PT_EVT_PROXY_CLOSED, ev));
335305
}
336306

337307
BOOL ControlServer::wait_for_edit_and_maybe_replace(uint64_t op_id,
@@ -454,9 +424,7 @@ namespace pipetap::inject {
454424
1, 0, 256 * 1024, 0, nullptr);
455425
}
456426

457-
void ControlServer::send_control_message(uint16_t type,
458-
const void* meta, uint32_t meta_len,
459-
const void* payload, uint32_t payload_len)
427+
void ControlServer::send_control_message(const PT_ControlFrame& frame)
460428
{
461429
if (!connected_.load(std::memory_order_relaxed)) return;
462430

@@ -466,17 +434,12 @@ namespace pipetap::inject {
466434
return;
467435
}
468436

469-
std::vector<::pipetap::ControlMessageFragment> fragments;
470-
if (meta_len && meta) fragments.push_back({ meta, meta_len });
471-
if (payload_len && payload) fragments.push_back({ payload, payload_len });
472-
auto msg = ::pipetap::BuildControlMessage(type, fragments);
473-
474437
AcquireSRWLockExclusive(&ctrl_lock_);
475438
{
476439
SuppressHooksGuard _guard;
477440
DWORD wrote = 0;
478-
BOOL ok = WriteFile(hW, msg.data(), (DWORD)msg.size(), &wrote, nullptr);
479-
if (!ok || wrote != msg.size()) {
441+
bool ok = ::pipetap::WriteControlFrame(hW, frame, &wrote);
442+
if (!ok) {
480443
ctrl_broken_.store(true, std::memory_order_release);
481444
connected_.store(false, std::memory_order_release);
482445
(void)atomic_exchange_handle(ctrl_w_, INVALID_HANDLE_VALUE);
@@ -498,61 +461,50 @@ namespace pipetap::inject {
498461
}
499462
if (totalAvail < sizeof(PT_ControlMessageHeader)) { Sleep(1); continue; }
500463

501-
PT_ControlMessageHeader hdr{};
464+
PT_ControlFrame frame;
502465
{
503466
SuppressHooksGuard _guard;
504-
if (!::pipetap::PipeReadExact(h, &hdr, static_cast<DWORD>(sizeof(hdr)))) break;
505-
}
506-
507-
if (hdr.length > (512u * 1024u * 1024u)) break;
508-
509-
std::vector<uint8_t> val(hdr.length);
510-
if (hdr.length) {
511-
SuppressHooksGuard _guard;
512-
if (!::pipetap::PipeReadExact(h, val.data(), hdr.length)) break;
467+
if (!::pipetap::ReadControlFrame(h, frame)) break;
513468
}
514469

515470
ctrl_broken_.store(false, std::memory_order_release);
516471
connected_.store(true, std::memory_order_release);
517472

518-
switch (hdr.type) {
473+
switch (frame.header.type) {
519474
case PT_CMD_SET_EDIT:
520-
if (hdr.length >= sizeof(PT_EditFlags)) {
475+
{
521476
PT_EditFlags fl{};
522-
std::memcpy(&fl, val.data(), sizeof(fl));
523-
edit_req_.store(fl.edit_request ? 1u : 0u, std::memory_order_release);
524-
edit_resp_.store(fl.edit_response ? 1u : 0u, std::memory_order_release);
477+
if (frame.TryAs(fl)) {
478+
edit_req_.store(fl.edit_request ? 1u : 0u, std::memory_order_release);
479+
edit_resp_.store(fl.edit_response ? 1u : 0u, std::memory_order_release);
480+
}
525481
}
526482
break;
527483

528484
case PT_CMD_EDIT_REPLY:
529-
if (hdr.length >= sizeof(PT_EditReply)) {
485+
{
486+
PT_ControlFrame::Reader rd = frame.AsReader();
530487
PT_EditReply rep{};
531-
std::memcpy(&rep, val.data(), sizeof(rep));
532-
const uint8_t* bytes = nullptr; uint32_t bsz = 0;
533-
if (rep.action == 1) {
534-
size_t off = sizeof(PT_EditReply);
535-
if (hdr.length >= off + rep.new_size) {
536-
bytes = val.data() + off;
537-
bsz = rep.new_size;
538-
}
488+
if (!rd.Next(rep)) break;
489+
490+
const uint8_t* bytes = nullptr;
491+
uint32_t bsz = 0;
492+
if (rep.action == 1 && rep.new_size) {
493+
if (!rd.NextBytes(rep.new_size, bytes)) break;
494+
bsz = rep.new_size;
539495
}
540496
complete_pending(rep.op_id, rep.action, bytes, bsz);
541497
}
542498
break;
543499

544500
case PT_CMD_PROXY_OPEN:
545-
if (hdr.length >= sizeof(PT_ProxyOpen)) {
501+
{
502+
PT_ControlFrame::Reader rd = frame.AsReader();
546503
PT_ProxyOpen op{};
547-
std::memcpy(&op, val.data(), sizeof(op));
504+
if (!rd.Next(op)) break;
548505

549-
const char* name = nullptr;
550-
if (op.name_len) {
551-
size_t off = sizeof(PT_ProxyOpen);
552-
if (hdr.length >= off + op.name_len) {
553-
name = reinterpret_cast<const char*>(val.data() + off);
554-
}
555-
}
506+
const uint8_t* name = nullptr;
507+
if (op.name_len && !rd.NextBytes(op.name_len, name)) break;
556508

557509
uint32_t win32err = ERROR_INVALID_PARAMETER;
558510
bool ok = false;
@@ -564,7 +516,7 @@ namespace pipetap::inject {
564516
DWORD le = NamedPipeClient::instance().open_session(
565517
*this,
566518
op.session_id,
567-
std::string(name, name + op.name_len),
519+
std::string(reinterpret_cast<const char*>(name), reinterpret_cast<const char*>(name) + op.name_len),
568520
op.timeout_ms,
569521
op.wait_for_server != 0,
570522
op.set_message_readmode != 0,
@@ -588,16 +540,17 @@ namespace pipetap::inject {
588540
break;
589541

590542
case PT_CMD_PROXY_SEND:
591-
if (hdr.length >= sizeof(PT_ProxySend)) {
543+
{
544+
PT_ControlFrame::Reader rd = frame.AsReader();
592545
PT_ProxySend ps{};
593-
std::memcpy(&ps, val.data(), sizeof(ps));
546+
if (!rd.Next(ps)) break;
547+
594548
const uint8_t* data = nullptr;
595-
if (ps.data_size) {
596-
size_t off = sizeof(PT_ProxySend);
597-
if (hdr.length >= off + ps.data_size) data = val.data() + off;
549+
if (ps.data_size && !rd.NextBytes(ps.data_size, data)) {
550+
send_error(2001u, "proxy_send_bad_session");
551+
break;
598552
}
599-
600-
if (!data) {
553+
if (ps.data_size == 0 || !data) {
601554
send_error(2001u, "proxy_send_bad_session");
602555
break;
603556
}
@@ -615,11 +568,11 @@ namespace pipetap::inject {
615568
break;
616569

617570
case PT_CMD_PROXY_CLOSE:
618-
if (hdr.length >= sizeof(PT_ProxyClose)) {
571+
{
619572
PT_ProxyClose c{};
620-
std::memcpy(&c, val.data(), sizeof(c));
621-
622-
NamedPipeClient::instance().close_session(c.session_id, /*reason=*/0u, /*win32err=*/0u);
573+
if (frame.TryAs(c)) {
574+
NamedPipeClient::instance().close_session(c.session_id, /*reason=*/0u, /*win32err=*/0u);
575+
}
623576
}
624577
break;
625578

pipetap-dll/inject/namedpipe_client.cpp

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,24 @@
66

77
#include <unordered_map>
88
#include <atomic>
9-
#include <vector>
10-
#include <string>
11-
#include <memory>
12-
#include "pipetap/controlpipe.h"
13-
#include "pipetap/winpipe_helpers.h"
14-
#include "inject/hook_guards.h"
15-
#include "inject/pipe_utils.h"
16-
#include "inject/control_server.h"
17-
#include "inject/namedpipe_client.h"
9+
#include <vector>
10+
#include <string>
11+
#include <memory>
12+
#include "pipetap/controlpipe.h"
13+
#include "pipetap/winpipe_helpers.h"
14+
#include "inject/hook_guards.h"
15+
#include "inject/pipe_utils.h"
16+
#include "inject/control_server.h"
17+
#include "inject/namedpipe_client.h"
1818

1919
namespace pipetap::inject {
2020

2121
static inline HANDLE atomic_load_handle(const HANDLE& h) {
2222
return (HANDLE)InterlockedCompareExchangePointer((PVOID*)&h, nullptr, nullptr);
2323
}
24-
static inline HANDLE atomic_exchange_handle(HANDLE& h, HANDLE hNew) {
25-
return (HANDLE)InterlockedExchangePointer((PVOID*)&h, hNew);
26-
}
24+
static inline HANDLE atomic_exchange_handle(HANDLE& h, HANDLE hNew) {
25+
return (HANDLE)InterlockedExchangePointer((PVOID*)&h, hNew);
26+
}
2727

2828
static std::atomic<uint64_t> g_proxyNextOpId{ 1 };
2929
static inline uint64_t NewProxyOpId() { return g_proxyNextOpId.fetch_add(1, std::memory_order_relaxed); }
@@ -157,15 +157,15 @@ namespace pipetap::inject {
157157
}
158158
if (totalAvail == 0) { Sleep(1); continue; }
159159

160-
buf.resize(totalAvail);
161-
{
162-
SuppressHooksGuard g;
163-
if (!::pipetap::PipeReadExact(h, buf.data(), totalAvail)) {
164-
DWORD le = GetLastError();
165-
self->notify_closed((le == ERROR_BROKEN_PIPE) ? 1u : 2u, le);
166-
break;
167-
}
168-
}
160+
buf.resize(totalAvail);
161+
{
162+
SuppressHooksGuard g;
163+
if (!::pipetap::PipeReadExact(h, buf.data(), totalAvail)) {
164+
DWORD le = GetLastError();
165+
self->notify_closed((le == ERROR_BROKEN_PIPE) ? 1u : 2u, le);
166+
break;
167+
}
168+
}
169169

170170
self->owner->send_pipe_io(PT_PIPE_READ, h, buf.data(), (uint32_t)buf.size(),
171171
/*dir=*/0, NewProxyOpId(), "ProxyRead");
@@ -185,10 +185,10 @@ namespace pipetap::inject {
185185
break;
186186
}
187187
if (got == 0) { Sleep(1); continue; }
188-
buf.resize(got);
189-
190-
self->owner->send_pipe_io(PT_PIPE_READ, h, buf.data(), (uint32_t)buf.size(),
191-
/*dir=*/0, NewProxyOpId(), "ProxyRead");
188+
buf.resize(got);
189+
190+
self->owner->send_pipe_io(PT_PIPE_READ, h, buf.data(), (uint32_t)buf.size(),
191+
/*dir=*/0, NewProxyOpId(), "ProxyRead");
192192
}
193193
}
194194

0 commit comments

Comments
 (0)