/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 2005 INRIA * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Mathieu Lacage */ #include "utils.h" namespace yans { uint16_t utils_hton_16 (uint16_t v) { uint8_t array[2]; array[0] = (v >> 8) & 0xff; array[1] = (v >> 0) & 0xff; return *((uint16_t *)array); } uint32_t utils_hton_32 (uint32_t v) { uint8_t array[4]; array[0] = (v >> 24) & 0xff; array[1] = (v >> 16) & 0xff; array[2] = (v >> 8) & 0xff; array[3] = (v >> 0) & 0xff; return *((uint32_t *)array); } uint16_t utils_ntoh_16 (uint16_t v) { uint16_t val; uint8_t *array; array = (uint8_t *)&v; val = (array[0] << 8) | (array[1] << 0); return val; } uint32_t utils_ntoh_32 (uint32_t v) { uint32_t val = 0; uint8_t *array = (uint8_t *)&v; val |= array[0] << 24; val |= array[1] << 16; val |= array[2] << 8; val |= array[3] << 0; return val; } #define ASCII_DOT (0x2e) #define ASCII_ZERO (0x30) #define ASCII_A (0x41) #define ASCII_Z (0x5a) #define ASCII_a (0x61) #define ASCII_z (0x7a) #define ASCII_COLON (0x3a) uint32_t ascii_to_ipv4_host (char const *address) { uint32_t host = 0; while (true) { uint8_t byte = 0; while (*address != ASCII_DOT && *address != 0) { byte *= 10; byte += *address - ASCII_ZERO; address++; } host <<= 8; host |= byte; if (*address == 0) { break; } address++; } return host; } char ascii_to_low_case (char c) { if (c >= ASCII_a && c <= ASCII_z) { return c; } else if (c >= ASCII_A && c <= ASCII_Z) { return c + (ASCII_a - ASCII_A); } else { return c; } } void ascii_to_mac_network (char const *str, uint8_t address[6]) { uint8_t i = 0; while (*str != 0 && i < 6) { uint8_t byte = 0; while (*str != ASCII_COLON && *str != 0) { byte <<= 4; char low = ascii_to_low_case (*str); if (low >= ASCII_a) { byte |= low - ASCII_a + 10; } else { byte |= low - ASCII_ZERO; } str++; } address[i] = byte; str++; i++; } } uint16_t utils_checksum_calculate (uint16_t checksum, uint8_t *buffer, uint16_t size) { /* see RFC 1071 to understand this code. */ uint32_t sum = checksum; uint16_t *data = (uint16_t *) buffer; for (uint16_t i = 0; i < (size/2); i++) { sum += data[i]; } if ((size % 2) != 0) { uint8_t tmp_buf[2]; tmp_buf[0] = buffer[size-1]; tmp_buf[1] = 0; data = (uint16_t *)tmp_buf; sum += *data; } while (sum >> 16) { sum = (sum & 0xffff) + (sum >> 16); } return sum; } uint16_t utils_checksum_complete (uint16_t checksum) { return ~checksum; } }; // namespace yans #ifdef RUN_SELF_TESTS #include "yans/test.h" namespace yans { class UtilsTest : public Test { public: UtilsTest (); virtual bool run_tests (void); private: bool test_ipv4_ascii_to_host (char const *str, uint32_t expected); bool test_mac_ascii (char const *str, uint8_t expected[6]); bool test_hton_16 (uint16_t v, uint8_t expected[2]); }; bool UtilsTest::test_ipv4_ascii_to_host (char const *str, uint32_t expected) { if (ascii_to_ipv4_host (str) != expected) { failure () << "Utils ascii to host --" << " for: \"" << str << "\"" << " expected: " << expected << " got: " << ascii_to_ipv4_host (str) << std::endl; return false; } return true; } bool UtilsTest::test_mac_ascii (char const *str, uint8_t expected[6]) { uint8_t got[6]; ascii_to_mac_network (str, got); for (uint8_t i = 0; i < 6; i++) { if (got[i] != expected[i]) { failure () << "Utils ascii to mac --" << " for: \"" << str << "\"" << " expected: "; failure ().setf (std::ios::hex, std::ios::basefield); failure () << (uint32_t)expected[0] << ":" << (uint32_t)expected[1] << ":" << (uint32_t)expected[2] << ":" << (uint32_t)expected[3] << ":" << (uint32_t)expected[4] << ":" << (uint32_t)expected[5]; failure ().setf (std::ios::dec, std::ios::basefield); failure () << " got: "; failure ().setf (std::ios::hex, std::ios::basefield); failure () << (uint32_t)got[0] << ":" << (uint32_t)got[1] << ":" << (uint32_t)got[2] << ":" << (uint32_t)got[3] << ":" << (uint32_t)got[4] << ":" << (uint32_t)got[5]; failure ().setf (std::ios::dec, std::ios::basefield); failure () << std::endl; return false; } } return true; } bool UtilsTest::test_hton_16 (uint16_t v, uint8_t expected[2]) { uint16_t result = utils_hton_16 (v); uint8_t *got = (uint8_t *)&result; if (got[0] != expected[0] || got[1] != expected[1]) { failure () << "Utils hton 16 --" << " for: \"" << v << "\"" << " expected: "; failure ().setf (std::ios::hex, std::ios::basefield); failure () << (uint32_t)expected[0] << ":" << (uint32_t)expected[1]; failure () << " got: "; failure () << (uint32_t)got[0] << ":" << (uint32_t)got[1]; failure ().setf (std::ios::dec, std::ios::basefield); failure () << std::endl; return false; } return true; } #define TEST_IPV4_ASCII_TO_HOST(a,b) \ if (!test_ipv4_ascii_to_host (a,b)) { \ ok = false; \ } #define TEST_MAC_ASCII(ad, a, b, c, d, e, f) \ { \ uint8_t expected[6] = {a, b, c, d, e, f}; \ if (!test_mac_ascii (ad, expected)) { \ ok = false; \ } \ } #define TEST_HTON_16(v, a, b) \ { \ uint8_t expected[2] = {a, b}; \ if (!test_hton_16 (v, expected)) { \ ok = false; \ } \ } UtilsTest::UtilsTest () : Test ("Utils") {} bool UtilsTest::run_tests (void) { bool ok = true; TEST_IPV4_ASCII_TO_HOST ("255.255.255.255", 0xffffffff); TEST_IPV4_ASCII_TO_HOST ("255.255.255.0", 0xffffff00); TEST_IPV4_ASCII_TO_HOST ("255.255.255.00", 0xffffff00); TEST_IPV4_ASCII_TO_HOST ("255.255.255.000", 0xffffff00); TEST_IPV4_ASCII_TO_HOST ("255.255.255.0000", 0xffffff00); TEST_IPV4_ASCII_TO_HOST ("255.255.0.255", 0xffff00ff); TEST_IPV4_ASCII_TO_HOST ("192.168.0.1", 0xc0a80001); TEST_IPV4_ASCII_TO_HOST ("0.168.0.1", 0x00a80001); TEST_MAC_ASCII ("00:00:00:00:00:00", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); TEST_MAC_ASCII ("00:00:00:00:00:01", 0x00, 0x00, 0x00, 0x00, 0x00, 0x01); TEST_MAC_ASCII ("01:00:00:00:00:01", 0x01, 0x00, 0x00, 0x00, 0x00, 0x01); TEST_MAC_ASCII ("ff:00:00:ff:00:01", 0xff, 0x00, 0x00, 0xff, 0x00, 0x01); TEST_MAC_ASCII ("f0:00:00:00:5d:01", 0xf0, 0x00, 0x00, 0x00, 0x5d, 0x01); TEST_HTON_16 (0xf00f, 0xf0, 0x0f); return ok; } static UtilsTest g_utils_test; }; //namespace yans #endif /* RUN_SELF_TESTS */