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
21namespace Poco {
22namespace Net {
23
24
25DialogSocket::DialogSocket():
26 _pBuffer(0),
27 _pNext(0),
28 _pEnd(0)
29{
30 allocBuffer();
31}
32
33
34DialogSocket::DialogSocket(const SocketAddress& address):
35 StreamSocket(address),
36 _pBuffer(0),
37 _pNext(0),
38 _pEnd(0)
39{
40 allocBuffer();
41}
42
43
44DialogSocket::DialogSocket(const Socket& socket):
45 StreamSocket(socket),
46 _pBuffer(0),
47 _pNext(0),
48 _pEnd(0)
49{
50 allocBuffer();
51}
52
53
54DialogSocket::DialogSocket(const DialogSocket& socket):
55 StreamSocket(socket),
56 _pBuffer(0),
57 _pNext(0),
58 _pEnd(0)
59{
60 allocBuffer();
61}
62
63
64DialogSocket::~DialogSocket()
65{
66 delete [] _pBuffer;
67}
68
69
70DialogSocket& DialogSocket::operator = (const Socket& socket)
71{
72 StreamSocket::operator = (socket);
73 _pNext = _pBuffer;
74 _pEnd = _pBuffer;
75 return *this;
76}
77
78
79DialogSocket& DialogSocket::operator = (const DialogSocket& socket)
80{
81 StreamSocket::operator = (socket);
82 _pNext = _pBuffer;
83 _pEnd = _pBuffer;
84 return *this;
85}
86
87
88void DialogSocket::sendByte(unsigned char ch)
89{
90 sendBytes(&ch, 1);
91}
92
93
94void DialogSocket::sendString(const char* str)
95{
96 sendBytes(str, (int) std::strlen(str));
97}
98
99
100void DialogSocket::sendString(const std::string& str)
101{
102 sendBytes(str.data(), (int) str.length());
103}
104
105
106void 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
116void 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
131void 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
148bool DialogSocket::receiveMessage(std::string& message)
149{
150 message.clear();
151 return receiveLine(message, MAX_LINE_LENGTH);
152}
153
154
155int 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
171int 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
181int 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
191void DialogSocket::synch()
192{
193 sendUrgent(TELNET_DM);
194}
195
196
197void 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
206void 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
216void 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
230void DialogSocket::allocBuffer()
231{
232 _pBuffer = new char [RECEIVE_BUFFER_SIZE];
233 _pNext = _pBuffer;
234 _pEnd = _pBuffer;
235}
236
237
238bool 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
259int 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
284int 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