master
hxx 108 lines 3.31 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2 // SPDX-License-Identifier: MIT
3 #pragma once
4
5 #include <poll.h>
6 #include <signal.h>
7 #include <sys/signalfd.h>
8 #include "lxwil.h"
9 #include "Forwarder.h"
10 #include "Packet.h"
11 #include "Syscall.h"
12
13 #include <stdio.h>
14
15 #define _countof(a) (sizeof(a) / sizeof(*(a)))
16
17 template <typename ProcessingFunction, typename ExceptionHandler>
18 Forwarder<ProcessingFunction, ExceptionHandler>::Forwarder(int SourceFd, int DestinationFd, ProcessingFunction Handler, ExceptionHandler exceptionHandler)
19 {
20 // Create a pipe to signal the thread to stop.
21 int pipes[2];
22 Syscall(pipe2, pipes, 0);
23 TerminateFd = pipes[1];
24
25 Worker = std::thread([=]() {
26 try
27 {
28 wil::unique_fd terminate = pipes[0];
29 auto wait_for_fd = [&terminate](int fd, int event) -> bool {
30 struct pollfd poll_fds[2];
31 poll_fds[0] = {.fd = fd, .events = event, .revents = 0};
32 poll_fds[1] = {.fd = terminate.get(), .events = POLLIN, .revents = 0};
33 for (;;)
34 {
35 const int return_value = poll(poll_fds, _countof(poll_fds), -1);
36 if (return_value < 0)
37 {
38 if (errno == EINTR)
39 {
40 continue;
41 }
42
43 throw std::runtime_error(std::string("poll returned ") + std::string(strerror(errno)));
44 }
45 else if (return_value == 0)
46 {
47 continue;
48 }
49 else if (poll_fds[1].revents)
50 {
51 return false;
52 }
53 else if (poll_fds[0].revents & event)
54 {
55 return true;
56 }
57 }
58 };
59
60 Packet packet;
61 for (;;)
62 {
63 packet.reset();
64
65 // Grow the packet to provide space.
66 packet.adjust_tail(Packet::InitialPacketSize);
67 if (!wait_for_fd(SourceFd, POLLIN))
68 {
69 break;
70 }
71
72 int bytes_read = Syscall(read, SourceFd, packet.data(), packet.data_end() - packet.data());
73
74 // Shrink packet to size of data read.
75 packet.adjust_tail(bytes_read - (packet.data_end() - packet.data()));
76
77 // If the handler returns true, write the packet to the destination fd.
78 if (Handler(packet))
79 {
80 if (!wait_for_fd(DestinationFd, POLLOUT))
81 {
82 break;
83 }
84
85 Syscall(write, DestinationFd, packet.data(), packet.data_end() - packet.data());
86 }
87 }
88 }
89 catch (std::exception& e)
90 {
91 if (!exceptionHandler(e))
92 {
93 throw;
94 }
95 }
96 });
97 }
98
99 template <typename ProcessingFunction, typename ExceptionHandler>
100 Forwarder<ProcessingFunction, ExceptionHandler>::~Forwarder()
101 {
102 // Close the write end of the pipe to signal the thread to stop.
103 close(TerminateFd);
104 if (Worker.joinable())
105 {
106 Worker.join();
107 }
108 }