ClientConnection.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // ClientConnection.cpp - 用户态连接管理实现
  2. #include <ntddk.h>
  3. #include <wdf.h>
  4. #include "ClientConnection.h"
  5. #include "EventRingBuffer.h"
  6. #include "../common/CommKitIoctl.h"
  7. #include "../common/CommKitEvents.h"
  8. namespace commkit_driver {
  9. // 全局实例
  10. ClientConnection g_ClientConnection;
  11. void ClientConnection::Initialize() {
  12. ports_count_ = 0;
  13. control_device_ = nullptr;
  14. callback_registered_ = FALSE;
  15. KeInitializeSpinLock(&ports_lock_);
  16. RtlZeroMemory(ports_table_, sizeof(ports_table_));
  17. }
  18. void ClientConnection::Cleanup() {
  19. // 释放所有端口的环形缓冲
  20. KIRQL old_irql;
  21. KeAcquireSpinLock(&ports_lock_, &old_irql);
  22. for (ULONG i = 0; i < ports_count_; ++i) {
  23. PDEVICE_CONTEXT ctx = ports_table_[i].Context;
  24. if (ctx && ctx->RingBuffer) {
  25. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  26. ring->Cleanup();
  27. ExFreePoolWithTag(ring, 'RBCK');
  28. ctx->RingBuffer = nullptr;
  29. }
  30. }
  31. ports_count_ = 0;
  32. KeReleaseSpinLock(&ports_lock_, old_irql);
  33. }
  34. void ClientConnection::RegisterFilterDevice(WDFDEVICE device) {
  35. KIRQL old_irql;
  36. KeAcquireSpinLock(&ports_lock_, &old_irql);
  37. if (ports_count_ < 256) {
  38. PDEVICE_CONTEXT ctx = DeviceGetContext(device);
  39. ports_table_[ports_count_].ComNumber = 0; // 延迟到 UpdatePortComNumber
  40. ports_table_[ports_count_].Context = ctx;
  41. ports_count_++;
  42. ctx->ComNumber = 0;
  43. ctx->MonitoringEnabled = FALSE;
  44. ctx->WdfDevice = device;
  45. }
  46. KeReleaseSpinLock(&ports_lock_, old_irql);
  47. }
  48. void ClientConnection::UpdatePortComNumber(WDFDEVICE device, ULONG com_number) {
  49. KIRQL old_irql;
  50. KeAcquireSpinLock(&ports_lock_, &old_irql);
  51. for (ULONG i = 0; i < ports_count_; ++i) {
  52. if (ports_table_[i].Context &&
  53. ports_table_[i].Context->WdfDevice == device) {
  54. ports_table_[i].ComNumber = com_number;
  55. ports_table_[i].Context->ComNumber = com_number;
  56. break;
  57. }
  58. }
  59. KeReleaseSpinLock(&ports_lock_, old_irql);
  60. }
  61. void ClientConnection::UnregisterFilterDevice(ULONG com_number) {
  62. KIRQL old_irql;
  63. KeAcquireSpinLock(&ports_lock_, &old_irql);
  64. for (ULONG i = 0; i < ports_count_; ++i) {
  65. if (ports_table_[i].ComNumber == com_number) {
  66. // 移动最后一个元素到当前位置
  67. PDEVICE_CONTEXT ctx = ports_table_[i].Context;
  68. if (ctx && ctx->RingBuffer) {
  69. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  70. ring->Cleanup();
  71. ExFreePoolWithTag(ring, 'RBCK');
  72. ctx->RingBuffer = nullptr;
  73. }
  74. ports_table_[i] = ports_table_[ports_count_ - 1];
  75. ports_count_--;
  76. break;
  77. }
  78. }
  79. KeReleaseSpinLock(&ports_lock_, old_irql);
  80. }
  81. PDEVICE_CONTEXT ClientConnection::FindPortContext(ULONG com_number) {
  82. PDEVICE_CONTEXT result = nullptr;
  83. KIRQL old_irql;
  84. KeAcquireSpinLock(&ports_lock_, &old_irql);
  85. for (ULONG i = 0; i < ports_count_; ++i) {
  86. if (ports_table_[i].ComNumber == com_number) {
  87. result = ports_table_[i].Context;
  88. break;
  89. }
  90. }
  91. KeReleaseSpinLock(&ports_lock_, old_irql);
  92. return result;
  93. }
  94. NTSTATUS ClientConnection::HandleRegisterCallback() {
  95. callback_registered_ = TRUE;
  96. return STATUS_SUCCESS;
  97. }
  98. NTSTATUS ClientConnection::HandleAttachPort(ULONG com_number) {
  99. PDEVICE_CONTEXT ctx = FindPortContext(com_number);
  100. if (!ctx) {
  101. return STATUS_DEVICE_DOES_NOT_EXIST;
  102. }
  103. // 如果未分配环形缓冲,先分配
  104. if (!ctx->RingBuffer) {
  105. EventRingBuffer* ring = (EventRingBuffer*)ExAllocatePool2(
  106. POOL_FLAG_NON_PAGED, sizeof(EventRingBuffer), 'RBCK');
  107. if (!ring) {
  108. return STATUS_INSUFFICIENT_RESOURCES;
  109. }
  110. // placement new 等价:手动调用构造
  111. RtlZeroMemory(ring, sizeof(EventRingBuffer));
  112. NTSTATUS status = ring->Initialize();
  113. if (!NT_SUCCESS(status)) {
  114. ring->Cleanup();
  115. ExFreePoolWithTag(ring, 'RBCK');
  116. return status;
  117. }
  118. ctx->RingBuffer = ring;
  119. }
  120. // 推入 OP_OPEN 事件(序列号由全局计数器递增)
  121. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  122. static LONG seq = 0;
  123. LONG cur = InterlockedIncrement(&seq);
  124. UINT64 timestamp = KeQueryInterruptTime(); // 100ns 单位
  125. ring->Push((ULONG)cur, timestamp, com_number, COMMKIT_OP_OPEN, 0, nullptr);
  126. ctx->MonitoringEnabled = TRUE;
  127. return STATUS_SUCCESS;
  128. }
  129. NTSTATUS ClientConnection::HandleDetachPort(ULONG com_number) {
  130. PDEVICE_CONTEXT ctx = FindPortContext(com_number);
  131. if (!ctx) {
  132. return STATUS_DEVICE_DOES_NOT_EXIST;
  133. }
  134. ctx->MonitoringEnabled = FALSE;
  135. // 推入 OP_CLOSE 事件
  136. if (ctx->RingBuffer) {
  137. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  138. static LONG seq2 = 0;
  139. LONG cur = InterlockedIncrement(&seq2);
  140. UINT64 timestamp = KeQueryInterruptTime();
  141. ring->Push((ULONG)cur, timestamp, com_number, COMMKIT_OP_CLOSE, 0, nullptr);
  142. }
  143. return STATUS_SUCCESS;
  144. }
  145. NTSTATUS ClientConnection::HandleWritePort(ULONG com_number, PVOID data, ULONG len) {
  146. PDEVICE_CONTEXT ctx = FindPortContext(com_number);
  147. if (!ctx || !ctx->LowerDevice) {
  148. return STATUS_DEVICE_DOES_NOT_EXIST;
  149. }
  150. // 构造同步写 IRP 发送给下层串口设备
  151. KEVENT event;
  152. KeInitializeEvent(&event, NotificationEvent, FALSE);
  153. IO_STATUS_BLOCK io_status = {};
  154. PIRP irp = IoBuildSynchronousFsdRequest(
  155. IRP_MJ_WRITE, ctx->LowerDevice, data, len, nullptr, &event, &io_status);
  156. if (!irp) {
  157. return STATUS_INSUFFICIENT_RESOURCES;
  158. }
  159. NTSTATUS status = IoCallDriver(ctx->LowerDevice, irp);
  160. if (status == STATUS_PENDING) {
  161. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, nullptr);
  162. status = io_status.Status;
  163. }
  164. return status;
  165. }
  166. NTSTATUS ClientConnection::HandleReadPort(ULONG com_number, PVOID data, ULONG len) {
  167. PDEVICE_CONTEXT ctx = FindPortContext(com_number);
  168. if (!ctx || !ctx->LowerDevice) {
  169. return STATUS_DEVICE_DOES_NOT_EXIST;
  170. }
  171. // 构造同步读 IRP 发送给下层串口设备
  172. KEVENT event;
  173. KeInitializeEvent(&event, NotificationEvent, FALSE);
  174. IO_STATUS_BLOCK io_status = {};
  175. PIRP irp = IoBuildSynchronousFsdRequest(
  176. IRP_MJ_READ, ctx->LowerDevice, data, len, nullptr, &event, &io_status);
  177. if (!irp) {
  178. return STATUS_INSUFFICIENT_RESOURCES;
  179. }
  180. NTSTATUS status = IoCallDriver(ctx->LowerDevice, irp);
  181. if (status == STATUS_PENDING) {
  182. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, nullptr);
  183. status = io_status.Status;
  184. }
  185. return status;
  186. }
  187. NTSTATUS ClientConnection::HandleReadEvents(PVOID out_buf, ULONG out_size, PULONG returned) {
  188. *returned = 0;
  189. if (!callback_registered_) {
  190. return STATUS_DEVICE_NOT_READY;
  191. }
  192. PCOMMKIT_EVENT events = (PCOMMKIT_EVENT)out_buf;
  193. ULONG max_count = out_size / sizeof(COMMKIT_EVENT);
  194. if (max_count == 0) {
  195. return STATUS_BUFFER_TOO_SMALL;
  196. }
  197. ULONG total_popped = 0;
  198. KIRQL old_irql;
  199. KeAcquireSpinLock(&ports_lock_, &old_irql);
  200. for (ULONG i = 0; i < ports_count_ && total_popped < max_count; ++i) {
  201. PDEVICE_CONTEXT ctx = ports_table_[i].Context;
  202. if (!ctx || !ctx->RingBuffer || !ctx->MonitoringEnabled) {
  203. continue;
  204. }
  205. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  206. LONG popped = ring->PopBatch(events + total_popped, max_count - total_popped);
  207. total_popped += (ULONG)popped;
  208. }
  209. KeReleaseSpinLock(&ports_lock_, old_irql);
  210. *returned = total_popped * sizeof(COMMKIT_EVENT);
  211. return STATUS_SUCCESS;
  212. }
  213. NTSTATUS ClientConnection::HandleFreeAll() {
  214. KIRQL old_irql;
  215. KeAcquireSpinLock(&ports_lock_, &old_irql);
  216. for (ULONG i = 0; i < ports_count_; ++i) {
  217. PDEVICE_CONTEXT ctx = ports_table_[i].Context;
  218. if (ctx) {
  219. ctx->MonitoringEnabled = FALSE;
  220. if (ctx->RingBuffer) {
  221. ((EventRingBuffer*)ctx->RingBuffer)->Clear();
  222. }
  223. }
  224. }
  225. KeReleaseSpinLock(&ports_lock_, old_irql);
  226. callback_registered_ = FALSE;
  227. return STATUS_SUCCESS;
  228. }
  229. } // namespace commkit_driver