1 #include "endian.hpp" 2 #include "slp.hpp" 3 #include "slp_meta.hpp" 4 5 #include <string.h> 6 7 #include <algorithm> 8 #include <string> 9 10 namespace slp 11 { 12 13 namespace parser 14 { 15 16 namespace internal 17 { 18 19 std::tuple<int, Message> parseHeader(const buffer& buff) 20 { 21 /* 0 1 2 3 22 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 23 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 24 | Version | Function-ID | Length | 25 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 26 | Length, contd.|O|F|R| reserved |Next Ext Offset| 27 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28 | Next Extension Offset, contd.| XID | 29 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 30 | Language Tag Length | Language Tag \ 31 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 32 33 Message req{}; 34 int rc = slp::SUCCESS; 35 36 if (buff.size() < slp::header::MIN_LEN) 37 { 38 std::cerr << "Invalid msg size: " << buff.size() << std::endl; 39 rc = static_cast<int>(slp::Error::PARSE_ERROR); 40 } 41 else 42 { 43 std::copy_n(buff.data(), slp::header::SIZE_VERSION, 44 &req.header.version); 45 46 std::copy_n(buff.data() + slp::header::OFFSET_FUNCTION, 47 slp::header::SIZE_VERSION, &req.header.functionID); 48 49 std::copy_n(buff.data() + slp::header::OFFSET_LENGTH, 50 slp::header::SIZE_LENGTH, req.header.length.data()); 51 52 std::copy_n(buff.data() + slp::header::OFFSET_FLAGS, 53 slp::header::SIZE_FLAGS, (uint8_t*)&req.header.flags); 54 55 req.header.flags = endian::from_network(req.header.flags); 56 std::copy_n(buff.data() + slp::header::OFFSET_EXT, 57 slp::header::SIZE_EXT, req.header.extOffset.data()); 58 59 std::copy_n(buff.data() + slp::header::OFFSET_XID, 60 slp::header::SIZE_XID, (uint8_t*)&req.header.xid); 61 62 req.header.xid = endian::from_network(req.header.xid); 63 64 uint16_t langtagLen; 65 66 std::copy_n(buff.data() + slp::header::OFFSET_LANG_LEN, 67 slp::header::SIZE_LANG, (uint8_t*)&langtagLen); 68 69 langtagLen = endian::from_network(langtagLen); 70 71 // Enforce language tag size limits 72 if ((slp::header::OFFSET_LANG + langtagLen) > buff.size()) 73 { 74 std::cerr << "Invalid Language Tag Length: " << langtagLen 75 << std::endl; 76 rc = static_cast<int>(slp::Error::PARSE_ERROR); 77 } 78 else 79 { 80 req.header.langtag.insert( 81 0, (const char*)buff.data() + slp::header::OFFSET_LANG, 82 langtagLen); 83 84 /* check for the validity of the function */ 85 if (req.header.functionID < 86 static_cast<uint8_t>(slp::FunctionType::SRVRQST) || 87 req.header.functionID > 88 static_cast<uint8_t>(slp::FunctionType::SAADV)) 89 { 90 std::cerr << "Invalid function ID: " << req.header.functionID 91 << std::endl; 92 rc = static_cast<int>(slp::Error::PARSE_ERROR); 93 } 94 } 95 } 96 97 return std::make_tuple(rc, std::move(req)); 98 } 99 100 int parseSrvTypeRqst(const buffer& buff, Message& req) 101 { 102 /* 0 1 2 3 103 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 104 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 105 | length of PRList | <PRList> String \ 106 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 107 | length of Naming Authority | <Naming Authority String> \ 108 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 109 | length of <scope-list> | <scope-list> String \ 110 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 111 112 /* Enforce SLPv2 service type request size limits. */ 113 if (buff.size() < slp::request::MIN_SRVTYPE_LEN) 114 { 115 return (int)slp::Error::PARSE_ERROR; 116 } 117 118 /* Parse the PRList. */ 119 uint16_t prListLen; 120 std::copy_n(buff.data() + slp::request::OFFSET_PR_LEN, 121 slp::request::SIZE_PRLIST, (uint8_t*)&prListLen); 122 123 prListLen = endian::from_network(prListLen); 124 125 req.body.srvtyperqst.prList.insert( 126 0, (const char*)buff.data() + slp::request::OFFSET_PR, prListLen); 127 128 uint8_t pos = slp::request::OFFSET_PR + prListLen; 129 130 /* Parse the Naming Authority. */ 131 uint16_t namingAuthLen; 132 std::copy_n(buff.data() + pos, slp::request::SIZE_NAMING, 133 (uint8_t*)&namingAuthLen); 134 135 pos += slp::request::SIZE_NAMING; 136 137 namingAuthLen = endian::from_network(namingAuthLen); 138 139 if (namingAuthLen == 0 || namingAuthLen == 0xffff) 140 { 141 req.body.srvtyperqst.namingAuth = ""; 142 } 143 else 144 { 145 req.body.srvtyperqst.namingAuth.insert( 146 0, (const char*)buff.data() + pos, namingAuthLen); 147 } 148 149 pos += namingAuthLen; 150 151 /* Parse the <scope-list>. */ 152 uint16_t scopeListLen; 153 std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE, 154 (uint8_t*)&scopeListLen); 155 156 pos += slp::request::SIZE_SCOPE; 157 158 scopeListLen = endian::from_network(scopeListLen); 159 160 req.body.srvtyperqst.scopeList.insert(0, (const char*)buff.data() + pos, 161 scopeListLen); 162 163 return slp::SUCCESS; 164 } 165 166 int parseSrvRqst(const buffer& buff, Message& req) 167 { 168 /* 0 1 2 3 169 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 170 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 171 | length of <PRList> | <PRList> String \ 172 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 173 | length of <service-type> | <service-type> String \ 174 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 175 | length of <scope-list> | <scope-list> String \ 176 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 177 | length of predicate string | Service Request <predicate> \ 178 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 179 | length of <SLP SPI> string | <SLP SPI> String \ 180 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 181 182 /* Enforce v2 service request size limits. */ 183 if (buff.size() < slp::request::MIN_SRV_LEN) 184 { 185 return (int)slp::Error::PARSE_ERROR; 186 } 187 188 /* 1) Parse the PRList. */ 189 uint16_t prListLen; 190 std::copy_n(buff.data() + slp::request::OFFSET_PR_LEN, 191 slp::request::SIZE_PRLIST, (uint8_t*)&prListLen); 192 193 auto pos = slp::request::OFFSET_PR_LEN + slp::request::SIZE_PRLIST; 194 195 prListLen = endian::from_network(prListLen); 196 197 req.body.srvrqst.prList.insert(0, (const char*)buff.data() + pos, 198 prListLen); 199 200 pos += prListLen; 201 202 /* 2) Parse the <service-type> string. */ 203 uint16_t srvTypeLen; 204 std::copy_n(buff.data() + pos, slp::request::SIZE_SERVICE_TYPE, 205 (uint8_t*)&srvTypeLen); 206 207 srvTypeLen = endian::from_network(srvTypeLen); 208 209 pos += slp::request::SIZE_SERVICE_TYPE; 210 211 req.body.srvrqst.srvType.insert(0, (const char*)buff.data() + pos, 212 srvTypeLen); 213 214 pos += srvTypeLen; 215 216 /* 3) Parse the <scope-list> string. */ 217 uint16_t scopeListLen; 218 std::copy_n(buff.data() + pos, slp::request::SIZE_SCOPE, 219 (uint8_t*)&scopeListLen); 220 221 scopeListLen = endian::from_network(scopeListLen); 222 223 pos += slp::request::SIZE_SCOPE; 224 225 req.body.srvrqst.scopeList.insert(0, (const char*)buff.data() + pos, 226 scopeListLen); 227 228 pos += scopeListLen; 229 230 /* 4) Parse the <predicate> string. */ 231 uint16_t predicateLen; 232 std::copy_n(buff.data() + pos, slp::request::SIZE_PREDICATE, 233 (uint8_t*)&predicateLen); 234 235 predicateLen = endian::from_network(predicateLen); 236 pos += slp::request::SIZE_PREDICATE; 237 238 req.body.srvrqst.predicate.insert(0, (const char*)buff.data() + pos, 239 predicateLen); 240 241 pos += predicateLen; 242 243 /* 5) Parse the <SLP SPI> string. */ 244 uint16_t spistrLen; 245 std::copy_n(buff.data() + pos, slp::request::SIZE_SLPI, 246 (uint8_t*)&spistrLen); 247 248 spistrLen = endian::from_network(spistrLen); 249 pos += slp::request::SIZE_SLPI; 250 251 req.body.srvrqst.spistr.insert(0, (const char*)buff.data() + pos, 252 spistrLen); 253 254 return slp::SUCCESS; 255 } 256 } // namespace internal 257 258 std::tuple<int, Message> parseBuffer(const buffer& buff) 259 { 260 Message req; 261 int rc = slp::SUCCESS; 262 /* parse the header first */ 263 std::tie(rc, req) = internal::parseHeader(buff); 264 if (!rc) 265 { 266 /* switch on the function id to parse the body */ 267 switch (req.header.functionID) 268 { 269 case (uint8_t)slp::FunctionType::SRVTYPERQST: 270 rc = internal::parseSrvTypeRqst(buff, req); 271 break; 272 case (uint8_t)slp::FunctionType::SRVRQST: 273 rc = internal::parseSrvRqst(buff, req); 274 break; 275 default: 276 rc = (int)slp::Error::MSG_NOT_SUPPORTED; 277 } 278 } 279 return std::make_tuple(rc, std::move(req)); 280 } 281 } // namespace parser 282 } // namespace slp 283