1 | // |
2 | // DialogSocket.cpp |
3 | // |
4 | // Library: Net |
5 | // Package: Sockets |
6 | // Module: DialogSocket |
7 | // |
8 | // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Net/DialogSocket.h" |
16 | #include "Poco/Exception.h" |
17 | #include "Poco/Ascii.h" |
18 | #include <cstring> |
19 | |
20 | |
21 | namespace Poco { |
22 | namespace Net { |
23 | |
24 | |
25 | DialogSocket::DialogSocket(): |
26 | _pBuffer(0), |
27 | _pNext(0), |
28 | _pEnd(0) |
29 | { |
30 | allocBuffer(); |
31 | } |
32 | |
33 | |
34 | DialogSocket::DialogSocket(const SocketAddress& address): |
35 | StreamSocket(address), |
36 | _pBuffer(0), |
37 | _pNext(0), |
38 | _pEnd(0) |
39 | { |
40 | allocBuffer(); |
41 | } |
42 | |
43 | |
44 | DialogSocket::DialogSocket(const Socket& socket): |
45 | StreamSocket(socket), |
46 | _pBuffer(0), |
47 | _pNext(0), |
48 | _pEnd(0) |
49 | { |
50 | allocBuffer(); |
51 | } |
52 | |
53 | |
54 | DialogSocket::DialogSocket(const DialogSocket& socket): |
55 | StreamSocket(socket), |
56 | _pBuffer(0), |
57 | _pNext(0), |
58 | _pEnd(0) |
59 | { |
60 | allocBuffer(); |
61 | } |
62 | |
63 | |
64 | DialogSocket::~DialogSocket() |
65 | { |
66 | delete [] _pBuffer; |
67 | } |
68 | |
69 | |
70 | DialogSocket& DialogSocket::operator = (const Socket& socket) |
71 | { |
72 | StreamSocket::operator = (socket); |
73 | _pNext = _pBuffer; |
74 | _pEnd = _pBuffer; |
75 | return *this; |
76 | } |
77 | |
78 | |
79 | DialogSocket& DialogSocket::operator = (const DialogSocket& socket) |
80 | { |
81 | StreamSocket::operator = (socket); |
82 | _pNext = _pBuffer; |
83 | _pEnd = _pBuffer; |
84 | return *this; |
85 | } |
86 | |
87 | |
88 | void DialogSocket::sendByte(unsigned char ch) |
89 | { |
90 | sendBytes(&ch, 1); |
91 | } |
92 | |
93 | |
94 | void DialogSocket::sendString(const char* str) |
95 | { |
96 | sendBytes(str, (int) std::strlen(str)); |
97 | } |
98 | |
99 | |
100 | void DialogSocket::sendString(const std::string& str) |
101 | { |
102 | sendBytes(str.data(), (int) str.length()); |
103 | } |
104 | |
105 | |
106 | void DialogSocket::sendMessage(const std::string& message) |
107 | { |
108 | std::string line; |
109 | line.reserve(message.length() + 2); |
110 | line.append(message); |
111 | line.append("\r\n" ); |
112 | sendString(line); |
113 | } |
114 | |
115 | |
116 | void DialogSocket::sendMessage(const std::string& message, const std::string& arg) |
117 | { |
118 | std::string line; |
119 | line.reserve(message.length() + arg.length() + 3); |
120 | line.append(message); |
121 | if (!arg.empty()) |
122 | { |
123 | line.append(" " ); |
124 | line.append(arg); |
125 | } |
126 | line.append("\r\n" ); |
127 | sendString(line); |
128 | } |
129 | |
130 | |
131 | void DialogSocket::sendMessage(const std::string& message, const std::string& arg1, const std::string& arg2) |
132 | { |
133 | std::string line; |
134 | line.reserve(message.length() + arg1.length() +arg2.length() + 4); |
135 | line.append(message); |
136 | line.append(" " ); |
137 | line.append(arg1); |
138 | if (!arg2.empty()) |
139 | { |
140 | line.append(" " ); |
141 | line.append(arg2); |
142 | } |
143 | line.append("\r\n" ); |
144 | sendString(line); |
145 | } |
146 | |
147 | |
148 | bool DialogSocket::receiveMessage(std::string& message) |
149 | { |
150 | message.clear(); |
151 | return receiveLine(message, MAX_LINE_LENGTH); |
152 | } |
153 | |
154 | |
155 | int DialogSocket::receiveStatusMessage(std::string& message) |
156 | { |
157 | message.clear(); |
158 | int status = receiveStatusLine(message, MAX_LINE_LENGTH); |
159 | if (status < 0) |
160 | { |
161 | while (status <= 0) |
162 | { |
163 | message += '\n'; |
164 | status = receiveStatusLine(message, MAX_LINE_LENGTH); |
165 | } |
166 | } |
167 | return status; |
168 | } |
169 | |
170 | |
171 | int DialogSocket::get() |
172 | { |
173 | refill(); |
174 | if (_pNext != _pEnd) |
175 | return std::char_traits<char>::to_int_type(*_pNext++); |
176 | else |
177 | return EOF_CHAR; |
178 | } |
179 | |
180 | |
181 | int DialogSocket::peek() |
182 | { |
183 | refill(); |
184 | if (_pNext != _pEnd) |
185 | return std::char_traits<char>::to_int_type(*_pNext); |
186 | else |
187 | return EOF_CHAR; |
188 | } |
189 | |
190 | |
191 | void DialogSocket::synch() |
192 | { |
193 | sendUrgent(TELNET_DM); |
194 | } |
195 | |
196 | |
197 | void DialogSocket::sendTelnetCommand(unsigned char command) |
198 | { |
199 | unsigned char buffer[2]; |
200 | buffer[0] = TELNET_IAC; |
201 | buffer[1] = command; |
202 | sendBytes(buffer, 2); |
203 | } |
204 | |
205 | |
206 | void DialogSocket::sendTelnetCommand(unsigned char command, unsigned char arg) |
207 | { |
208 | unsigned char buffer[3]; |
209 | buffer[0] = TELNET_IAC; |
210 | buffer[1] = command; |
211 | buffer[2] = arg; |
212 | sendBytes(buffer, 3); |
213 | } |
214 | |
215 | |
216 | void DialogSocket::refill() |
217 | { |
218 | if (_pNext == _pEnd) |
219 | { |
220 | int n = receiveBytes(_pBuffer, RECEIVE_BUFFER_SIZE); |
221 | if (n > 0) |
222 | { |
223 | _pNext = _pBuffer; |
224 | _pEnd = _pBuffer + n; |
225 | } |
226 | } |
227 | } |
228 | |
229 | |
230 | void DialogSocket::allocBuffer() |
231 | { |
232 | _pBuffer = new char [RECEIVE_BUFFER_SIZE]; |
233 | _pNext = _pBuffer; |
234 | _pEnd = _pBuffer; |
235 | } |
236 | |
237 | |
238 | bool DialogSocket::receiveLine(std::string& line, std::size_t lineLengthLimit) |
239 | { |
240 | // An old wisdom goes: be strict in what you emit |
241 | // and generous in what you accept. |
242 | int ch = get(); |
243 | while (ch != EOF_CHAR && ch != '\r' && ch != '\n') |
244 | { |
245 | if (lineLengthLimit == 0 || line.size() < lineLengthLimit) |
246 | line += (char) ch; |
247 | else |
248 | throw Poco::IOException("Line too long" ); |
249 | ch = get(); |
250 | } |
251 | if (ch == '\r' && peek() == '\n') |
252 | get(); |
253 | else if (ch == EOF_CHAR) |
254 | return false; |
255 | return true; |
256 | } |
257 | |
258 | |
259 | int DialogSocket::receiveStatusLine(std::string& line, std::size_t lineLengthLimit) |
260 | { |
261 | int status = 0; |
262 | int ch = get(); |
263 | if (ch != EOF_CHAR) line += (char) ch; |
264 | int n = 0; |
265 | while (Poco::Ascii::isDigit(ch) && n < 3) |
266 | { |
267 | status *= 10; |
268 | status += ch - '0'; |
269 | ++n; |
270 | ch = get(); |
271 | if (ch != EOF_CHAR) line += (char) ch; |
272 | } |
273 | if (n == 3) |
274 | { |
275 | if (ch == '-') |
276 | status = -status; |
277 | } |
278 | else status = 0; |
279 | if (ch != EOF_CHAR) receiveLine(line, lineLengthLimit); |
280 | return status; |
281 | } |
282 | |
283 | |
284 | int DialogSocket::receiveRawBytes(void* buffer, int length) |
285 | { |
286 | refill(); |
287 | int n = static_cast<int>(_pEnd - _pNext); |
288 | if (n > length) n = length; |
289 | std::memcpy(buffer, _pNext, n); |
290 | _pNext += n; |
291 | return n; |
292 | } |
293 | |
294 | |
295 | } } // namespace Poco::Net |
296 | |