]> granicus.if.org Git - icinga2/blob - lib/base/netstring.cpp
0bd110bacffd30a0fc22bea125d2025fa8fc72b5
[icinga2] / lib / base / netstring.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/)  *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "base/netstring.hpp"
21 #include "base/debug.hpp"
22 #include <sstream>
23
24 using namespace icinga;
25
26 /**
27  * Reads data from a stream in netstring format.
28  *
29  * @param stream The stream to read from.
30  * @param[out] str The String that has been read from the IOQueue.
31  * @returns true if a complete String was read from the IOQueue, false otherwise.
32  * @exception invalid_argument The input stream is invalid.
33  * @see https://github.com/PeterScott/netstring-c/blob/master/netstring.c
34  */
35 StreamReadStatus NetString::ReadStringFromStream(const Stream::Ptr& stream, String *str, StreamReadContext& context, bool may_wait)
36 {
37         if (context.Eof)
38                 return StatusEof;
39
40         if (context.MustRead) {
41                 if (!context.FillFromStream(stream, may_wait)) {
42                         context.Eof = true;
43                         return StatusEof;
44                 }
45
46                 context.MustRead = false;
47         }
48
49         size_t header_length = 0;
50
51         for (size_t i = 0; i < context.Size; i++) {
52                 if (context.Buffer[i] == ':') {
53                         header_length = i;
54
55                         /* make sure there's a header */
56                         if (header_length == 0)
57                                 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (no length specifier)"));
58
59                         break;
60                 } else if (i > 16)
61                         BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (missing :)"));
62         }
63
64         if (header_length == 0) {
65                 context.MustRead = true;
66                 return StatusNeedData;
67         }
68
69         /* no leading zeros allowed */
70         if (context.Buffer[0] == '0' && isdigit(context.Buffer[1]))
71                 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (leading zero)"));
72
73         size_t len, i;
74
75         len = 0;
76         for (i = 0; i < header_length && isdigit(context.Buffer[i]); i++) {
77                 /* length specifier must have at most 9 characters */
78                 if (i >= 9)
79                         BOOST_THROW_EXCEPTION(std::invalid_argument("Length specifier must not exceed 9 characters"));
80
81                 len = len * 10 + (context.Buffer[i] - '0');
82         }
83
84         /* read the whole message */
85         size_t data_length = len + 1;
86
87         char *data = context.Buffer + header_length + 1;
88
89         if (context.Size < header_length + 1 + data_length) {
90                 context.MustRead = true;
91                 return StatusNeedData;
92         }
93
94         if (data[len] != ',')
95                 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid NetString (missing ,)"));
96
97         *str = String(&data[0], &data[len]);
98
99         context.DropData(header_length + 1 + len + 1);
100
101         return StatusNewItem;
102 }
103
104 /**
105  * Writes data into a stream using the netstring format and returns bytes written.
106  *
107  * @param stream The stream.
108  * @param str The String that is to be written.
109  *
110  * @return The amount of bytes written.
111  */
112 size_t NetString::WriteStringToStream(const Stream::Ptr& stream, const String& str)
113 {
114         std::ostringstream msgbuf;
115         WriteStringToStream(msgbuf, str);
116
117         String msg = msgbuf.str();
118         stream->Write(msg.CStr(), msg.GetLength());
119         return msg.GetLength();
120 }
121
122 /**
123  * Writes data into a stream using the netstring format.
124  *
125  * @param stream The stream.
126  * @param str The String that is to be written.
127  */
128 void NetString::WriteStringToStream(std::ostream& stream, const String& str)
129 {
130         stream << str.GetLength() << ":" << str << ",";
131 }