token.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <eval/token.h>
  15. #include <eval/eval_log.h>
  16. #include <util/encode/hex.h>
  17. #include <boost/lexical_cast.hpp>
  18. #include <cstring>
  19. #include <string>
  20. using namespace isc::dhcp;
  21. using namespace std;
  22. void
  23. TokenString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
  24. // Literals only push, nothing to pop
  25. values.push(value_);
  26. }
  27. void
  28. TokenHexString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
  29. // Eliminate the empty string case first
  30. if (repr_.empty()) {
  31. values.push("");
  32. return;
  33. }
  34. // Transform string of hexadecimal digits into binary format
  35. std::vector<uint8_t> binary;
  36. try {
  37. // The decodeHex function expects that the string contains an
  38. // even number of digits. If we don't meet this requirement,
  39. // we have to insert a leading 0.
  40. if (repr_.length() % 2) {
  41. repr_ = repr_.insert(0, "0");
  42. }
  43. util::encode::decodeHex(repr_, binary);
  44. } catch (...) {
  45. values.push("");
  46. return;
  47. }
  48. // Convert to a string
  49. std::string chars(binary.size(), '\0');
  50. // Note that binary.size() cannot be 0
  51. std::memmove(&chars[0], &binary[0], binary.size());
  52. // Literals only push, nothing to pop
  53. values.push(chars);
  54. }
  55. void
  56. TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
  57. OptionPtr opt = pkt.getOption(option_code_);
  58. if (opt) {
  59. values.push(opt->toString());
  60. } else {
  61. // Option not found, push empty string
  62. values.push("");
  63. }
  64. }
  65. void
  66. TokenEqual::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
  67. if (values.size() < 2) {
  68. isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
  69. "2 values for == operator, got " << values.size());
  70. }
  71. string op1 = values.top();
  72. values.pop();
  73. string op2 = values.top();
  74. values.pop(); // Dammit, std::stack interface is awkward.
  75. if (op1 == op2)
  76. values.push("true");
  77. else
  78. values.push("false");
  79. }
  80. void
  81. TokenSubstring::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
  82. if (values.size() < 3) {
  83. isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
  84. "3 values for substring operator, got " << values.size());
  85. }
  86. string len_str = values.top();
  87. values.pop();
  88. string start_str = values.top();
  89. values.pop();
  90. string string_str = values.top();
  91. values.pop();
  92. // If we have no string to start with we push an empty string and leave
  93. if (string_str.empty()) {
  94. values.push("");
  95. return;
  96. }
  97. // Convert the starting position and length from strings to numbers
  98. // the length may also be "all" in which case simply make it the
  99. // length of the string.
  100. // If we have a problem push an empty string and leave
  101. int start_pos;
  102. int length;
  103. try {
  104. start_pos = boost::lexical_cast<int>(start_str);
  105. if (len_str == "all") {
  106. length = string_str.length();
  107. } else {
  108. length = boost::lexical_cast<int>(len_str);
  109. }
  110. } catch (const boost::bad_lexical_cast&) {
  111. LOG_DEBUG(eval_logger, EVAL_DBG_TRACE,
  112. EVAL_SUBSTRING_BAD_PARAM_CONVERSION)
  113. .arg(start_str)
  114. .arg(len_str);
  115. values.push("");
  116. return;
  117. }
  118. const int string_length = string_str.length();
  119. // If the starting postion is outside of the string push an
  120. // empty string and leave
  121. if ((start_pos < -string_length) || (start_pos >= string_length)) {
  122. values.push("");
  123. return;
  124. }
  125. // Adjust the values to be something for substr. We first figure out
  126. // the starting postion, then update it and the length to get the
  127. // characters before or after it depending on the sign of length
  128. if (start_pos < 0) {
  129. start_pos = string_length + start_pos;
  130. }
  131. if (length < 0) {
  132. length = -length;
  133. if (length <= start_pos){
  134. start_pos -= length;
  135. } else {
  136. length = start_pos;
  137. start_pos = 0;
  138. }
  139. }
  140. // and finally get the substring
  141. values.push(string_str.substr(start_pos, length));
  142. }