ClientConnection.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. ClientConnection::ClientConnection()
  10. : ports_count_(0), control_device_(nullptr), callback_registered_(FALSE) {
  11. KeInitializeSpinLock(&ports_lock_);
  12. RtlZeroMemory(ports_table_, sizeof(ports_table_));
  13. }
  14. ClientConnection::~ClientConnection() {
  15. Cleanup();
  16. }
  17. ClientConnection& GetClientConnection() {
  18. static ClientConnection instance;
  19. return instance;
  20. }
  21. NTSTATUS ClientConnection::Initialize(WDFDRIVER driver) {
  22. UNREFERENCED_PARAMETER(driver);
  23. // 控制设备创建详见 QueueCallback.cpp / DriverEntry.cpp
  24. return STATUS_SUCCESS;
  25. }
  26. void ClientConnection::Cleanup() {
  27. // 释放所有端口的环形缓冲
  28. KIRQL old_irql;
  29. KeAcquireSpinLock(&ports_lock_, &old_irql);
  30. for (ULONG i = 0; i < ports_count_; ++i) {
  31. PDEVICE_CONTEXT ctx = ports_table_[i].Context;
  32. if (ctx && ctx->RingBuffer) {
  33. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  34. ring->Cleanup();
  35. ExFreePoolWithTag(ring, 'RBCK');
  36. ctx->RingBuffer = nullptr;
  37. }
  38. }
  39. ports_count_ = 0;
  40. KeReleaseSpinLock(&ports_lock_, old_irql);
  41. }
  42. void ClientConnection::RegisterFilterDevice(ULONG com_number, WDFDEVICE device) {
  43. KIRQL old_irql;
  44. KeAcquireSpinLock(&ports_lock_, &old_irql);
  45. if (ports_count_ < 256) {
  46. PDEVICE_CONTEXT ctx = DeviceGetContext(device);
  47. ports_table_[ports_count_].ComNumber = com_number;
  48. ports_table_[ports_count_].Context = ctx;
  49. ports_count_++;
  50. ctx->ComNumber = com_number;
  51. ctx->MonitoringEnabled = FALSE;
  52. ctx->WdfDevice = device;
  53. }
  54. KeReleaseSpinLock(&ports_lock_, old_irql);
  55. }
  56. void ClientConnection::UnregisterFilterDevice(ULONG com_number) {
  57. KIRQL old_irql;
  58. KeAcquireSpinLock(&ports_lock_, &old_irql);
  59. for (ULONG i = 0; i < ports_count_; ++i) {
  60. if (ports_table_[i].ComNumber == com_number) {
  61. // 移动最后一个元素到当前位置
  62. PDEVICE_CONTEXT ctx = ports_table_[i].Context;
  63. if (ctx && ctx->RingBuffer) {
  64. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  65. ring->Cleanup();
  66. ExFreePoolWithTag(ring, 'RBCK');
  67. ctx->RingBuffer = nullptr;
  68. }
  69. ports_table_[i] = ports_table_[ports_count_ - 1];
  70. ports_count_--;
  71. break;
  72. }
  73. }
  74. KeReleaseSpinLock(&ports_lock_, old_irql);
  75. }
  76. PDEVICE_CONTEXT ClientConnection::FindPortContext(ULONG com_number) {
  77. PDEVICE_CONTEXT result = nullptr;
  78. KIRQL old_irql;
  79. KeAcquireSpinLock(&ports_lock_, &old_irql);
  80. for (ULONG i = 0; i < ports_count_; ++i) {
  81. if (ports_table_[i].ComNumber == com_number) {
  82. result = ports_table_[i].Context;
  83. break;
  84. }
  85. }
  86. KeReleaseSpinLock(&ports_lock_, old_irql);
  87. return result;
  88. }
  89. NTSTATUS ClientConnection::HandleRegisterCallback() {
  90. callback_registered_ = TRUE;
  91. return STATUS_SUCCESS;
  92. }
  93. NTSTATUS ClientConnection::HandleAttachPort(ULONG com_number) {
  94. PDEVICE_CONTEXT ctx = FindPortContext(com_number);
  95. if (!ctx) {
  96. return STATUS_DEVICE_DOES_NOT_EXIST;
  97. }
  98. // 如果未分配环形缓冲,先分配
  99. if (!ctx->RingBuffer) {
  100. EventRingBuffer* ring = (EventRingBuffer*)ExAllocatePool2(
  101. POOL_FLAG_NON_PAGED, sizeof(EventRingBuffer), 'RBCK');
  102. if (!ring) {
  103. return STATUS_INSUFFICIENT_RESOURCES;
  104. }
  105. // placement new 等价:手动调用构造
  106. RtlZeroMemory(ring, sizeof(EventRingBuffer));
  107. NTSTATUS status = ring->Initialize();
  108. if (!NT_SUCCESS(status)) {
  109. ring->Cleanup();
  110. ExFreePoolWithTag(ring, 'RBCK');
  111. return status;
  112. }
  113. ctx->RingBuffer = ring;
  114. }
  115. // 推入 OP_OPEN 事件(序列号由全局计数器递增)
  116. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  117. static LONG seq = 0;
  118. LONG cur = InterlockedIncrement(&seq);
  119. ring->Push((ULONG)cur, 0.0, com_number, COMMKIT_OP_OPEN, 0, nullptr);
  120. ctx->MonitoringEnabled = TRUE;
  121. return STATUS_SUCCESS;
  122. }
  123. NTSTATUS ClientConnection::HandleDetachPort(ULONG com_number) {
  124. PDEVICE_CONTEXT ctx = FindPortContext(com_number);
  125. if (!ctx) {
  126. return STATUS_DEVICE_DOES_NOT_EXIST;
  127. }
  128. ctx->MonitoringEnabled = FALSE;
  129. // 推入 OP_CLOSE 事件
  130. if (ctx->RingBuffer) {
  131. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  132. static LONG seq = 0;
  133. LONG cur = InterlockedIncrement(&seq);
  134. ring->Push((ULONG)cur, 0.0, com_number, COMMKIT_OP_CLOSE, 0, nullptr);
  135. }
  136. return STATUS_SUCCESS;
  137. }
  138. NTSTATUS ClientConnection::HandleWritePort(ULONG com_number, PVOID data, ULONG len) {
  139. UNREFERENCED_PARAMETER(data);
  140. UNREFERENCED_PARAMETER(len);
  141. // 简化实现:直接调用下层串口的 Write IRP
  142. // 完整实现需要查找端口上下文,构造 IRP 发送给下层设备
  143. PDEVICE_CONTEXT ctx = FindPortContext(com_number);
  144. if (!ctx) {
  145. return STATUS_DEVICE_DOES_NOT_EXIST;
  146. }
  147. // 注:完整的写数据流通过过滤驱动 IRP_MJ_WRITE 派遣完成
  148. // 这里仅返回成功;实际数据发送由用户态通过 CreateFile(COMx) 直接写入
  149. return STATUS_SUCCESS;
  150. }
  151. NTSTATUS ClientConnection::HandleReadPort(ULONG com_number, PVOID data, ULONG len) {
  152. UNREFERENCED_PARAMETER(data);
  153. UNREFERENCED_PARAMETER(len);
  154. PDEVICE_CONTEXT ctx = FindPortContext(com_number);
  155. if (!ctx) {
  156. return STATUS_DEVICE_DOES_NOT_EXIST;
  157. }
  158. return STATUS_SUCCESS;
  159. }
  160. NTSTATUS ClientConnection::HandleReadEvents(PVOID out_buf, ULONG out_size, PULONG returned) {
  161. *returned = 0;
  162. if (!callback_registered_) {
  163. return STATUS_DEVICE_NOT_READY;
  164. }
  165. PCOMMKIT_EVENT events = (PCOMMKIT_EVENT)out_buf;
  166. ULONG max_count = out_size / sizeof(COMMKIT_EVENT);
  167. if (max_count == 0) {
  168. return STATUS_BUFFER_TOO_SMALL;
  169. }
  170. ULONG total_popped = 0;
  171. KIRQL old_irql;
  172. KeAcquireSpinLock(&ports_lock_, &old_irql);
  173. for (ULONG i = 0; i < ports_count_ && total_popped < max_count; ++i) {
  174. PDEVICE_CONTEXT ctx = ports_table_[i].Context;
  175. if (!ctx || !ctx->RingBuffer || !ctx->MonitoringEnabled) {
  176. continue;
  177. }
  178. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  179. LONG popped = ring->PopBatch(events + total_popped, max_count - total_popped);
  180. total_popped += (ULONG)popped;
  181. }
  182. KeReleaseSpinLock(&ports_lock_, old_irql);
  183. *returned = total_popped * sizeof(COMMKIT_EVENT);
  184. return STATUS_SUCCESS;
  185. }
  186. NTSTATUS ClientConnection::HandleFreeAll() {
  187. KIRQL old_irql;
  188. KeAcquireSpinLock(&ports_lock_, &old_irql);
  189. for (ULONG i = 0; i < ports_count_; ++i) {
  190. PDEVICE_CONTEXT ctx = ports_table_[i].Context;
  191. if (ctx) {
  192. ctx->MonitoringEnabled = FALSE;
  193. if (ctx->RingBuffer) {
  194. ((EventRingBuffer*)ctx->RingBuffer)->Clear();
  195. }
  196. }
  197. }
  198. KeReleaseSpinLock(&ports_lock_, old_irql);
  199. callback_registered_ = FALSE;
  200. return STATUS_SUCCESS;
  201. }
  202. } // namespace commkit_driver