Telnet++ 4.0.0.9
A C++ library for interacting with Telnet streams
Loading...
Searching...
No Matches
parser.hpp
1#pragma once
2
3#include "telnetpp/command.hpp"
4#include "telnetpp/core.hpp"
5#include "telnetpp/negotiation.hpp"
6#include "telnetpp/subnegotiation.hpp"
7
8#include <algorithm>
9
10namespace telnetpp {
11
12class parser final
13{
14public:
15 template <typename Continuation>
16 constexpr void operator()(telnetpp::bytes data, Continuation &&c)
17 {
18 std::ranges::for_each(
19 data, [&](telnetpp::byte by) { parse_byte(by, c); });
20
21 emit_plain_data(c);
22 }
23
24private:
25 enum class parsing_state : std::uint8_t
26 {
27 state_idle,
28 state_iac,
29 state_negotiation,
30 state_subnegotiation,
31 state_subnegotiation_content,
32 state_subnegotiation_content_iac
33 };
34
35 parsing_state state_{parsing_state::state_idle};
36
37 telnetpp::byte_storage plain_data_;
38 telnetpp::byte_storage subnegotiation_content_;
39 telnetpp::negotiation_type negotiation_type_;
40 telnetpp::option_type subnegotiation_option_;
41
42 template <typename Continuation>
43 constexpr void parse_byte(telnetpp::byte by, Continuation &&c)
44 {
45 switch (state_)
46 {
47 case parsing_state::state_idle:
48 parse_idle(by, c);
49 break;
50
51 case parsing_state::state_iac:
52 parse_iac(by, c);
53 break;
54
55 case parsing_state::state_negotiation:
56 parse_negotiation(by, c);
57 break;
58
59 case parsing_state::state_subnegotiation:
60 parse_subnegotiation(by, c);
61 break;
62
63 case parsing_state::state_subnegotiation_content:
64 parse_subnegotiation_content(by, c);
65 break;
66
67 case parsing_state::state_subnegotiation_content_iac:
68 parse_subnegotiation_content_iac(by, c);
69 break;
70
71 default:
72 break;
73 }
74 }
75
76 template <typename Continuation>
77 constexpr void parse_idle(telnetpp::byte by, Continuation &&c)
78 {
79 switch (by)
80 {
81 case telnetpp::iac:
82 state_ = parsing_state::state_iac;
83 break;
84
85 default:
86 plain_data_.push_back(by);
87 break;
88 }
89 }
90
91 template <typename Continuation>
92 constexpr void parse_iac(telnetpp::byte by, Continuation &&c)
93 {
94 switch (by)
95 {
96 case telnetpp::iac:
97 plain_data_.push_back(by);
98 state_ = parsing_state::state_idle;
99 break;
100
101 case telnetpp::will: // fall-through
102 case telnetpp::wont: // fall-through
103 case telnetpp::do_: // fall-through
104 case telnetpp::dont:
105 emit_plain_data(c);
106 negotiation_type_ = by;
107 state_ = parsing_state::state_negotiation;
108 break;
109
110 case telnetpp::sb:
111 emit_plain_data(c);
112 state_ = parsing_state::state_subnegotiation;
113 break;
114
115 default:
116 emit_plain_data(c);
117 c(telnetpp::command{by});
118 state_ = parsing_state::state_idle;
119 break;
120 }
121 }
122
123 template <typename Continuation>
124 constexpr void parse_negotiation(telnetpp::byte by, Continuation &&c)
125 {
126 c(telnetpp::negotiation{negotiation_type_, by});
127 state_ = parsing_state::state_idle;
128 }
129
130 template <typename Continuation>
131 constexpr void parse_subnegotiation(telnetpp::byte by, Continuation &&c)
132 {
133 subnegotiation_option_ = by;
134 subnegotiation_content_.clear();
135 state_ = parsing_state::state_subnegotiation_content;
136 }
137
138 template <typename Continuation>
139 constexpr void parse_subnegotiation_content(
140 telnetpp::byte by, Continuation &&c)
141 {
142 switch (by)
143 {
144 case telnetpp::iac:
145 state_ = parsing_state::state_subnegotiation_content_iac;
146 break;
147
148 default:
149 subnegotiation_content_.push_back(by);
150 break;
151 }
152 }
153
154 template <typename Continuation>
155 constexpr void parse_subnegotiation_content_iac(
156 telnetpp::byte by, Continuation &&c)
157 {
158 switch (by)
159 {
160 case telnetpp::se:
162 subnegotiation_option_, subnegotiation_content_});
163 state_ = parsing_state::state_idle;
164 break;
165
166 default:
167 subnegotiation_content_.push_back(by);
168 state_ = parsing_state::state_subnegotiation_content;
169 break;
170 }
171 }
172
173 template <typename Continuation>
174 constexpr void emit_plain_data(Continuation &&c)
175 {
176 if (!plain_data_.empty())
177 {
178 c(plain_data_);
179 plain_data_.clear();
180 }
181 }
182};
183
184} // namespace telnetpp
A class that encapsulates the value of a Telnet command.
Definition command.hpp:13
A class that encapsulates a Telnet negotiation.
Definition negotiation.hpp:15
Definition parser.hpp:13
A class that encapsulates a Telnet subnegotiation.
Definition subnegotiation.hpp:14