| /** @file |
| WCCP Message parsing and generation. |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #include "WccpLocal.h" |
| #include <errno.h> |
| #include <openssl/md5.h> |
| #include "ts/TsException.h" |
| #include "tscore/ink_memory.h" |
| #include "tscore/ink_string.h" |
| |
| namespace wccp |
| { |
| // ------------------------------------------------------ |
| // ------------------------------------------------------ |
| ServiceGroup & |
| ServiceGroup::setSvcType(ServiceGroup::Type t) |
| { |
| if (STANDARD == t) { |
| // For standard service, everything past ID must be zero. |
| memset(&m_priority, 0, sizeof(*this) - (reinterpret_cast<char *>(&m_priority) - reinterpret_cast<char *>(this))); |
| } |
| m_svc_type = t; // store actual type. |
| return *this; |
| } |
| |
| bool |
| ServiceGroup::operator==(self const &that) const |
| { |
| if (m_svc_type == STANDARD) { |
| // If type are different, fail, else if both are STANDARD |
| // then we need only match on the ID. |
| return that.m_svc_type == STANDARD && m_svc_id == that.m_svc_id; |
| } else if (that.m_svc_type != DYNAMIC) { |
| return false; |
| } else { |
| // Both services are DYNAMIC, check the properties. |
| // Port check is technically too strict -- should ignore |
| // ports beyond the terminating null port. Oh well. |
| return m_svc_id == that.m_svc_id && m_protocol == that.m_protocol && m_flags == that.m_flags && m_priority == that.m_priority && |
| 0 == memcmp(m_ports, that.m_ports, sizeof(m_ports)); |
| } |
| } |
| // ------------------------------------------------------ |
| // ------------------------------------------------------ |
| CacheHashIdElt & |
| CacheHashIdElt::setBucket(int idx, bool state) |
| { |
| uint8_t &bucket = m_buckets[idx >> 3]; |
| uint8_t mask = 1 << (idx & 7); |
| if (state) |
| bucket |= mask; |
| else |
| bucket &= !mask; |
| return *this; |
| } |
| |
| CacheHashIdElt & |
| CacheHashIdElt::setBuckets(bool state) |
| { |
| memset(m_buckets, state ? 0xFF : 0, sizeof(m_buckets)); |
| return *this; |
| } |
| |
| size_t |
| CacheIdBox::getSize() const |
| { |
| return m_size; |
| } |
| |
| CacheIdBox & |
| CacheIdBox::require(size_t n) |
| { |
| if (m_cap < n) { |
| if (m_base && m_cap) |
| ats_free(m_base); |
| m_base = static_cast<CacheIdElt *>(ats_malloc(n)); |
| m_cap = n; |
| } |
| memset(m_base, 0, m_cap); |
| m_size = 0; |
| return *this; |
| } |
| |
| CacheIdBox & |
| CacheIdBox::initDefaultHash(uint32_t addr) |
| { |
| this->require(sizeof(CacheHashIdElt)); |
| m_size = sizeof(CacheHashIdElt); |
| m_base->initHashRev().setUnassigned(true).setMask(false).setAddr(addr); |
| m_tail = static_cast<CacheHashIdElt *>(m_base)->getTailPtr(); |
| m_tail->m_weight = htons(0); |
| m_tail->m_status = htons(0); |
| return *this; |
| } |
| |
| CacheIdBox & |
| CacheIdBox::initDefaultMask(uint32_t addr) |
| { |
| // Base element plus set with 1 value plus tail. |
| this->require(sizeof(CacheMaskIdElt) + MaskValueSetElt::calcSize(1) + sizeof(CacheIdElt::Tail)); |
| CacheMaskIdElt *mid = static_cast<CacheMaskIdElt *>(m_base); |
| mid->initHashRev().setUnassigned(true).setMask(true).setAddr(addr); |
| mid->m_assign.init(0, 0, 0, 0)->addValue(addr, 0, 0, 0, 0); |
| m_size = mid->getSize(); |
| m_tail = mid->getTailPtr(); |
| m_tail->m_weight = htons(0); |
| m_tail->m_status = htons(0); |
| return *this; |
| } |
| |
| CacheIdBox & |
| CacheIdBox::fill(self const &src) |
| { |
| size_t n = src.getSize(); |
| this->require(src.getSize()); |
| memcpy(m_base, src.m_base, n); |
| m_size = src.m_size; |
| // If tail is set in src, use the same offset here. |
| if (src.m_tail) |
| m_tail = reinterpret_cast<CacheIdElt::Tail *>(reinterpret_cast<char *>(m_base) + |
| (reinterpret_cast<char *>(src.m_tail) - reinterpret_cast<char *>(src.m_base))); |
| else |
| m_tail = 0; |
| return *this; |
| } |
| |
| CacheIdBox & |
| CacheIdBox::fill(void *base, self const &src) |
| { |
| m_size = src.getSize(); |
| m_cap = 0; |
| m_base = static_cast<CacheIdElt *>(base); |
| memcpy(m_base, src.m_base, m_size); |
| return *this; |
| } |
| |
| int |
| CacheIdBox::parse(MsgBuffer base) |
| { |
| int zret = PARSE_SUCCESS; |
| CacheIdElt *ptr = reinterpret_cast<CacheIdElt *>(base.getTail()); |
| size_t n = base.getSpace(); |
| m_cap = 0; |
| if (ptr->isMask()) { |
| CacheMaskIdElt *mptr = static_cast<CacheMaskIdElt *>(ptr); |
| size_t size = sizeof(CacheMaskIdElt); |
| // Sanity check - verify enough room for empty elements. |
| if (n < size || n < size + MaskValueSetElt::calcSize(0) * mptr->getCount()) { |
| zret = PARSE_BUFFER_TOO_SMALL; |
| } else { |
| m_size = mptr->getSize(); |
| if (n < m_size) { |
| zret = PARSE_BUFFER_TOO_SMALL; |
| logf(LVL_DEBUG, "I_SEE_YOU Cache Mask ID too small: %lu < %lu", n, m_size); |
| } else { |
| m_tail = mptr->getTailPtr(); |
| } |
| } |
| } else { |
| if (n < sizeof(CacheHashIdElt)) { |
| zret = PARSE_BUFFER_TOO_SMALL; |
| logf(LVL_DEBUG, "I_SEE_YOU Cache Hash ID too small: %lu < %lu", n, sizeof(CacheHashIdElt)); |
| } else { |
| m_size = sizeof(CacheHashIdElt); |
| m_tail = static_cast<CacheHashIdElt *>(m_base)->getTailPtr(); |
| } |
| } |
| if (PARSE_SUCCESS == zret) |
| m_base = ptr; |
| return zret; |
| } |
| // ------------------------------------------------------ |
| inline CapabilityElt::Type |
| CapabilityElt::getCapType() const |
| { |
| return static_cast<Type>(ntohs(m_cap_type)); |
| } |
| |
| inline CapabilityElt & |
| CapabilityElt::setCapType(Type cap) |
| { |
| m_cap_type = static_cast<Type>(htons(cap)); |
| return *this; |
| } |
| |
| inline uint32_t |
| CapabilityElt::getCapData() const |
| { |
| return ntohl(m_cap_data); |
| } |
| |
| inline CapabilityElt & |
| CapabilityElt::setCapData(uint32_t data) |
| { |
| m_cap_data = htonl(data); |
| return *this; |
| } |
| |
| CapabilityElt::CapabilityElt() {} |
| |
| CapabilityElt::CapabilityElt(Type cap, uint32_t data) |
| { |
| this->setCapType(cap); |
| this->setCapData(data); |
| m_cap_length = htons(sizeof(uint32_t)); |
| } |
| // ------------------------------------------------------ |
| inline uint32_t |
| ValueElt::getf_src_addr() const |
| { |
| return ntohl(m_src_addr); |
| } |
| |
| inline ValueElt & |
| ValueElt::setf_src_addr(uint32_t addr) |
| { |
| m_src_addr = htonl(addr); |
| return *this; |
| } |
| |
| inline uint32_t |
| ValueElt::getDstAddr() const |
| { |
| return ntohl(m_dst_addr); |
| } |
| |
| inline ValueElt & |
| ValueElt::setf_dst_addr(uint32_t addr) |
| { |
| m_dst_addr = htonl(addr); |
| return *this; |
| } |
| |
| inline uint16_t |
| ValueElt::getf_src_port() const |
| { |
| return ntohs(m_src_port); |
| } |
| |
| inline ValueElt & |
| ValueElt::setf_src_port(uint16_t port) |
| { |
| m_src_port = htons(port); |
| return *this; |
| } |
| |
| inline uint16_t |
| ValueElt::getDstPort() const |
| { |
| return ntohs(m_dst_port); |
| } |
| |
| inline ValueElt & |
| ValueElt::setf_dst_port(uint16_t port) |
| { |
| m_dst_port = htons(port); |
| return *this; |
| } |
| |
| inline uint32_t |
| ValueElt::getCacheAddr() const |
| { |
| return ntohl(m_cache_addr); |
| } |
| |
| inline ValueElt & |
| ValueElt::setCacheAddr(uint32_t addr) |
| { |
| m_cache_addr = htonl(addr); |
| return *this; |
| } |
| // ------------------------------------------------------ |
| MaskValueSetElt & |
| MaskValueSetElt::addValue(uint32_t cacheAddr, uint32_t srcAddr, uint32_t dstAddr, uint16_t srcPort, uint16_t dstPort) |
| { |
| uint32_t idx = ntohl(m_count); |
| new (this->values() + idx) ValueElt(cacheAddr, srcAddr, dstAddr, srcPort, dstPort); |
| m_count = htonl(idx + 1); |
| return *this; |
| } |
| |
| size_t |
| MaskAssignElt::getVarSize() const |
| { |
| size_t zret = 0; |
| int n = this->getCount(); |
| |
| MaskValueSetElt const *set = reinterpret_cast<MaskValueSetElt const *>(this + 1); |
| while (n--) { |
| size_t k = set->getSize(); |
| zret += k; |
| set = reinterpret_cast<MaskValueSetElt const *>(reinterpret_cast<char const *>(set) + k); |
| } |
| return zret; |
| } |
| |
| HashAssignElt & |
| HashAssignElt::round_robin_assign() |
| { |
| uint32_t v_caches = this->getCount(); |
| Bucket *buckets = this->getBucketBase(); |
| if (1 == v_caches) |
| memset(buckets, 0, sizeof(Bucket) * N_BUCKETS); |
| else { // Assign round robin. |
| size_t x = 0; |
| for (Bucket *spot = buckets, *limit = spot + N_BUCKETS; spot < limit; ++spot) { |
| spot->m_idx = x; |
| spot->m_alt = 0; |
| x = (x + 1) % v_caches; |
| } |
| } |
| return *this; |
| } |
| |
| RouterAssignListElt & |
| RouterAssignListElt::updateRouterId(uint32_t addr, uint32_t rcvid, uint32_t cno) |
| { |
| uint32_t n = this->getCount(); |
| RouterAssignElt *elt = access_array<RouterAssignElt>(this + 1); |
| for (uint32_t i = 0; i < n; ++i, ++elt) { |
| if (addr == elt->getAddr()) { |
| elt->setChangeNumber(cno).setRecvId(rcvid); |
| break; |
| } |
| } |
| return *this; |
| } |
| // ------------------------------------------------------ |
| message_type_t |
| MsgHeaderComp::getType() |
| { |
| return static_cast<message_type_t>(get_field(&raw_t::m_type, m_base)); |
| } |
| |
| uint16_t |
| MsgHeaderComp::getVersion() |
| { |
| return get_field(&raw_t::m_version, m_base); |
| } |
| |
| uint16_t |
| MsgHeaderComp::getLength() |
| { |
| return get_field(&raw_t::m_length, m_base); |
| } |
| |
| MsgHeaderComp & |
| MsgHeaderComp::setType(message_type_t type) |
| { |
| set_field(&raw_t::m_type, m_base, type); |
| return *this; |
| } |
| |
| MsgHeaderComp & |
| MsgHeaderComp::setVersion(uint16_t version) |
| { |
| set_field(&raw_t::m_version, m_base, version); |
| return *this; |
| } |
| |
| MsgHeaderComp & |
| MsgHeaderComp::setLength(uint16_t length) |
| { |
| set_field(&raw_t::m_length, m_base, length); |
| return *this; |
| } |
| |
| size_t |
| MsgHeaderComp::calcSize() |
| { |
| return sizeof(raw_t); |
| } |
| |
| MsgHeaderComp & |
| MsgHeaderComp::fill(MsgBuffer &buffer, message_type_t t) |
| { |
| size_t comp_size = this->calcSize(); |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| m_base = buffer.getTail(); |
| buffer.use(comp_size); |
| this->setType(t).setVersion(VERSION).setLength(0); |
| return *this; |
| } |
| |
| int |
| MsgHeaderComp::parse(MsgBuffer &base) |
| { |
| int zret = PARSE_SUCCESS; |
| size_t comp_size = this->calcSize(); |
| if (base.getSpace() < comp_size) { |
| zret = PARSE_BUFFER_TOO_SMALL; |
| } else { |
| m_base = base.getTail(); |
| // Length field puts end of message past end of buffer. |
| if (this->getLength() + comp_size > base.getSpace()) { |
| zret = PARSE_MSG_TOO_BIG; |
| } else if (INVALID_MSG_TYPE == this->toMsgType(get_field(&raw_t::m_type, m_base))) { |
| zret = PARSE_COMP_TYPE_INVALID; |
| } else { |
| base.use(comp_size); |
| } |
| } |
| return zret; |
| } |
| // ------------------------------------------------------ |
| SecurityComp::Key SecurityComp::m_default_key; |
| SecurityComp::Option SecurityComp::m_default_opt = SECURITY_NONE; |
| |
| SecurityComp::Option |
| SecurityComp::getOption() const |
| { |
| return static_cast<Option>(get_field(&RawNone::m_option, m_base)); |
| } |
| |
| SecurityComp & |
| SecurityComp::setOption(Option opt) |
| { |
| set_field(&RawNone::m_option, m_base, static_cast<uint32_t>(opt)); |
| return *this; |
| } |
| |
| SecurityComp & |
| SecurityComp::setKey(char const *key) |
| { |
| m_local_key = true; |
| ink_strlcpy(m_key, key, KEY_SIZE); |
| return *this; |
| } |
| |
| void |
| SecurityComp::setDefaultKey(char const *key) |
| { |
| ink_strlcpy(m_default_key, key, KEY_SIZE); |
| } |
| |
| SecurityComp & |
| SecurityComp::fill(MsgBuffer &buffer, Option opt) |
| { |
| size_t comp_size = this->calcSize(opt); |
| |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| |
| this->setType(COMP_TYPE).setLength(comp_size - sizeof(super::raw_t)).setOption(opt); |
| |
| if (SECURITY_NONE != opt) { |
| RawMD5::HashData &data = access_field(&RawMD5::m_data, m_base); |
| memset(data, 0, sizeof(data)); |
| } |
| |
| buffer.use(comp_size); |
| return *this; |
| } |
| |
| SecurityComp & |
| SecurityComp::secure(MsgBuffer const &msg) |
| { |
| if (SECURITY_MD5 == this->getOption()) { |
| MD5_CTX ctx; |
| char const *key = m_local_key ? m_key : m_default_key; |
| MD5_Init(&ctx); |
| MD5_Update(&ctx, key, KEY_SIZE); |
| MD5_Update(&ctx, msg.getBase(), msg.getCount()); |
| MD5_Final(access_field(&RawMD5::m_data, m_base), &ctx); |
| } |
| return *this; |
| } |
| |
| bool |
| SecurityComp::validate(MsgBuffer const &msg) const |
| { |
| bool zret = true; |
| if (SECURITY_MD5 == this->getOption()) { |
| RawMD5::HashData save; |
| RawMD5::HashData &org = const_cast<RawMD5::HashData &>(access_field(&RawMD5::m_data, m_base)); |
| MD5_CTX ctx; |
| char const *key = m_local_key ? m_key : m_default_key; |
| // save the original hash aside. |
| memcpy(save, org, sizeof(save)); |
| // zero out the component hash area to compute the hash. |
| memset(org, 0, sizeof(org)); |
| // Compute hash in to hash area. |
| MD5_Init(&ctx); |
| MD5_Update(&ctx, key, KEY_SIZE); |
| MD5_Update(&ctx, msg.getBase(), msg.getCount()); |
| MD5_Final(org, &ctx); |
| // check hash. |
| zret = 0 == memcmp(org, save, sizeof(save)); |
| // restore original data. |
| memcpy(org, save, sizeof(save)); |
| } |
| return zret; |
| } |
| |
| int |
| SecurityComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < sizeof(raw_t)) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| Option opt = this->getOption(); |
| if (SECURITY_NONE != opt && SECURITY_MD5 != opt) |
| zret = PARSE_COMP_INVALID; |
| else { |
| size_t comp_size = this->calcSize(opt); |
| if (this->getLength() != comp_size - sizeof(super::raw_t)) |
| zret = PARSE_COMP_WRONG_SIZE; |
| else |
| buffer.use(comp_size); |
| } |
| } |
| } |
| return zret; |
| } |
| // ------------------------------------------------------ |
| |
| ServiceComp & |
| ServiceComp::setPort(int idx, uint16_t port) |
| { |
| this->access()->setPort(idx, port); |
| m_port_count = std::max(m_port_count, idx); |
| return *this; |
| } |
| |
| ServiceComp & |
| ServiceComp::addPort(uint16_t port) |
| { |
| if (m_port_count < static_cast<int>(ServiceGroup::N_PORTS)) |
| this->access()->setPort(m_port_count++, port); |
| return *this; |
| } |
| |
| ServiceComp & |
| ServiceComp::clearPorts() |
| { |
| this->access()->clearPorts(); |
| m_port_count = 0; |
| return *this; |
| } |
| |
| ServiceComp & |
| ServiceComp::fill(MsgBuffer &buffer, ServiceGroup const &svc) |
| { |
| size_t comp_size = this->calcSize(); |
| |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| |
| this->setType(COMP_TYPE).setLength(comp_size - sizeof(super::raw_t)); |
| |
| // Cast buffer to our serialized type, then cast to ServiceGroup |
| // to get offset of that part of the serialization storage. |
| memcpy( |
| // This generates a gcc warning, but the next line doesn't. Yay. |
| // static_cast<ServiceGroup*>(reinterpret_cast<raw_t*>(m_base)), |
| &static_cast<ServiceGroup &>(*reinterpret_cast<raw_t *>(m_base)), &svc, sizeof(svc)); |
| buffer.use(comp_size); |
| return *this; |
| } |
| |
| int |
| ServiceComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| size_t comp_size = this->calcSize(); |
| if (buffer.getSpace() < comp_size) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| ServiceGroup::Type svc = this->getSvcType(); |
| if (ServiceGroup::DYNAMIC != svc && ServiceGroup::STANDARD != svc) |
| zret = PARSE_COMP_INVALID; |
| else if (this->getLength() != comp_size - sizeof(super::raw_t)) |
| zret = PARSE_COMP_WRONG_SIZE; |
| else |
| buffer.use(comp_size); |
| } |
| } |
| return zret; |
| } |
| // ------------------------------------------------------ |
| RouterIdElt & |
| RouterIdComp::idElt() |
| { |
| return access_field(&raw_t::m_id, m_base); |
| } |
| |
| RouterIdElt const & |
| RouterIdComp::idElt() const |
| { |
| return access_field(&raw_t::m_id, m_base); |
| } |
| |
| RouterIdComp & |
| RouterIdComp::setIdElt(uint32_t addr, uint32_t recv_id) |
| { |
| this->idElt().setAddr(addr).setRecvId(recv_id); |
| return *this; |
| } |
| |
| uint32_t |
| RouterIdComp::getAddr() const |
| { |
| return this->idElt().getAddr(); |
| } |
| |
| RouterIdComp & |
| RouterIdComp::setAddr(uint32_t addr) |
| { |
| this->idElt().setAddr(addr); |
| return *this; |
| } |
| |
| uint32_t |
| RouterIdComp::getRecvId() const |
| { |
| return this->idElt().getRecvId(); |
| } |
| inline RouterIdComp & |
| RouterIdComp::setRecvId(uint32_t id) |
| { |
| this->idElt().setRecvId(id); |
| return *this; |
| } |
| |
| uint32_t |
| RouterIdComp::getToAddr() const |
| { |
| return access_field(&raw_t::m_to_addr, m_base); |
| } |
| |
| RouterIdComp & |
| RouterIdComp::setToAddr(uint32_t addr) |
| { |
| access_field(&raw_t::m_to_addr, m_base) = addr; |
| return *this; |
| } |
| |
| uint32_t |
| RouterIdComp::getFromCount() const |
| { |
| return get_field(&raw_t::m_from_count, m_base); |
| } |
| |
| uint32_t |
| RouterIdComp::getFromAddr(int idx) const |
| { |
| return access_array<uint32_t>(m_base + sizeof(raw_t))[idx]; |
| } |
| |
| RouterIdComp & |
| RouterIdComp::setFromAddr(int idx, uint32_t addr) |
| { |
| access_array<uint32_t>(m_base + sizeof(raw_t))[idx] = addr; |
| return *this; |
| } |
| |
| int |
| RouterIdComp::findFromAddr(uint32_t addr) |
| { |
| int n = this->getFromCount(); |
| uint32_t *addrs = access_array<uint32_t>(m_base + sizeof(raw_t)) + n; |
| while (n-- != 0 && *--addrs != addr) |
| ; |
| return n; |
| } |
| |
| RouterIdComp & |
| RouterIdComp::fill(MsgBuffer &buffer, size_t n_caches) |
| { |
| size_t comp_size = this->calcSize(n_caches); |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| |
| this->setType(COMP_TYPE); |
| set_field(&raw_t::m_from_count, m_base, n_caches); |
| this->setLength(comp_size - sizeof(super::raw_t)); |
| buffer.use(comp_size); |
| |
| return *this; |
| } |
| |
| RouterIdComp & |
| RouterIdComp::fillSingleton(MsgBuffer &buffer, uint32_t addr, uint32_t recv_count, uint32_t to_addr, uint32_t from_addr) |
| { |
| size_t comp_size = this->calcSize(1); |
| |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| |
| this->setType(COMP_TYPE).setIdElt(addr, recv_count).setToAddr(to_addr).setFromAddr(0, from_addr); |
| |
| set_field(&raw_t::m_from_count, m_base, 1); |
| |
| this->setLength(comp_size - sizeof(super::raw_t)); |
| buffer.use(comp_size); |
| |
| return *this; |
| } |
| |
| int |
| RouterIdComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < sizeof(raw_t)) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| size_t comp_size = this->calcSize(this->getFromCount()); |
| if (this->getLength() != comp_size - sizeof(super::raw_t)) |
| zret = PARSE_COMP_WRONG_SIZE; |
| else |
| buffer.use(comp_size); |
| } |
| } |
| return zret; |
| } |
| // ------------------------------------------------------ |
| AssignmentKeyElt & |
| RouterViewComp::keyElt() |
| { |
| return access_field(&raw_t::m_key, m_base); |
| } |
| |
| AssignmentKeyElt const & |
| RouterViewComp::keyElt() const |
| { |
| return access_field(&raw_t::m_key, m_base); |
| } |
| |
| uint32_t |
| RouterViewComp::getChangeNumber() const |
| { |
| return get_field(&raw_t::m_change_number, m_base); |
| } |
| |
| RouterViewComp & |
| RouterViewComp::setChangeNumber(uint32_t n) |
| { |
| set_field(&raw_t::m_change_number, m_base, n); |
| return *this; |
| } |
| |
| // This is untainted because an overall size check is done when the packet is read. If any of the |
| // counts are bogus, that size check will fail. |
| // coverity[ -tainted_data_return] |
| uint32_t |
| RouterViewComp::getCacheCount() const |
| { |
| return ntohl(*m_cache_count); |
| } |
| |
| // This is untainted because an overall size check is done when the packet is read. If any of the |
| // counts are bogus, that size check will fail. |
| // coverity[ -tainted_data_return] |
| uint32_t |
| RouterViewComp::getRouterCount() const |
| { |
| return get_field(&raw_t::m_router_count, m_base); |
| } |
| |
| CacheIdBox & |
| RouterViewComp::cacheId(int idx) |
| { |
| return m_cache_ids[idx]; |
| } |
| |
| uint32_t |
| RouterViewComp::getRouterAddr(int idx) const |
| { |
| return access_array<uint32_t>(m_base + sizeof(raw_t))[idx]; |
| } |
| |
| RouterViewComp & |
| RouterViewComp::setRouterAddr(int idx, uint32_t addr) |
| { |
| access_array<uint32_t>(m_base + sizeof(raw_t))[idx] = addr; |
| return *this; |
| } |
| |
| uint32_t * |
| RouterViewComp::calc_cache_count_ptr() |
| { |
| return reinterpret_cast<uint32_t *>(m_base + sizeof(raw_t) + this->getRouterCount() * sizeof(uint32_t)); |
| } |
| |
| RouterViewComp & |
| RouterViewComp::fill(MsgBuffer &buffer, int n_routers, int n_caches) |
| { |
| // TBD: This isn't right since the upgrade to mask support |
| // because the size isn't a static function of the router and |
| // cache count anymore. |
| size_t comp_size = sizeof(raw_t); |
| |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| |
| this->setType(COMP_TYPE); |
| |
| // No setf for this field, hand pack it. |
| set_field(&raw_t::m_router_count, m_base, n_routers); |
| // Set the pointer to the count of caches. |
| m_cache_count = this->calc_cache_count_ptr(); |
| // No setf, go direct. |
| *m_cache_count = htonl(n_caches); |
| |
| this->setLength(comp_size - HEADER_SIZE); |
| buffer.use(comp_size); |
| |
| return *this; |
| } |
| |
| int |
| RouterViewComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < sizeof(raw_t)) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| uint32_t ncaches; // # of caches. |
| if (this->getRouterCount() > MAX_ROUTERS) |
| zret = PARSE_MSG_INVALID; |
| // check if cache count is past end of buffer |
| else if (static_cast<void *>(m_cache_count = this->calc_cache_count_ptr()) >= |
| static_cast<void *>(buffer.getBase() + buffer.getSize())) |
| zret = PARSE_COMP_WRONG_SIZE, log(LVL_DEBUG, "I_SEE_YOU: cache counter past end of buffer"); |
| else if ((ncaches = this->getCacheCount()) > MAX_CACHES) |
| zret = PARSE_MSG_INVALID; |
| else { |
| size_t comp_size = reinterpret_cast<char *>(m_cache_count + 1) - m_base; |
| // Walk the cache ID elements. |
| MsgBuffer spot(buffer); |
| CacheIdBox *box = m_cache_ids; |
| uint32_t idx = 0; |
| spot.use(comp_size); |
| while (idx < ncaches && PARSE_SUCCESS == (zret = box->parse(spot))) { |
| size_t k = box->getSize(); |
| spot.use(k); |
| comp_size += k; |
| ++box; |
| ++idx; |
| } |
| if (PARSE_SUCCESS == zret) |
| buffer.use(comp_size); |
| } |
| } |
| } |
| return zret; |
| } |
| // ------------------------------------------------------ |
| CacheIdComp & |
| CacheIdComp::fill(MsgBuffer &base, CacheIdBox const &src) |
| { |
| size_t comp_size = src.getSize() + HEADER_SIZE; |
| |
| if (base.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = base.getTail(); |
| this->setType(COMP_TYPE).setLength(comp_size - HEADER_SIZE); |
| m_box.fill(&(access_field(&raw_t::m_id, m_base)), src); |
| base.use(comp_size); |
| return *this; |
| } |
| |
| int |
| CacheIdComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < sizeof(raw_t)) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| MsgBuffer tmp(buffer); |
| tmp.use(reinterpret_cast<char *>(&(access_field(&raw_t::m_id, m_base))) - m_base); |
| zret = m_box.parse(tmp); |
| if (PARSE_SUCCESS == zret) { |
| size_t comp_size = HEADER_SIZE + m_box.getSize(); |
| if (this->getLength() != comp_size - HEADER_SIZE) |
| zret = PARSE_COMP_WRONG_SIZE; |
| else |
| buffer.use(comp_size); |
| } |
| } |
| } |
| return zret; |
| } |
| // ------------------------------------------------------ |
| uint32_t |
| CacheViewComp::getChangeNumber() const |
| { |
| return get_field(&raw_t::m_change_number, m_base); |
| } |
| |
| CacheViewComp & |
| CacheViewComp::setChangeNumber(uint32_t n) |
| { |
| set_field(&raw_t::m_change_number, m_base, n); |
| return *this; |
| } |
| |
| uint32_t |
| CacheViewComp::getRouterCount() const |
| { |
| return get_field(&raw_t::m_router_count, m_base); |
| } |
| |
| uint32_t |
| CacheViewComp::getCacheCount() const |
| { |
| return ntohl(*m_cache_count); |
| } |
| |
| uint32_t |
| CacheViewComp::getCacheAddr(int idx) const |
| { |
| return ntohl(m_cache_count[idx + 1]); |
| } |
| |
| CacheViewComp & |
| CacheViewComp::setCacheAddr(int idx, uint32_t addr) |
| { |
| m_cache_count[idx + 1] = addr; |
| return *this; |
| } |
| |
| RouterIdElt * |
| CacheViewComp::atf_router_array() |
| { |
| return reinterpret_cast<RouterIdElt *>(m_base + sizeof(raw_t)); |
| } |
| |
| RouterIdElt & |
| CacheViewComp::routerElt(int idx) |
| { |
| return this->atf_router_array()[idx]; |
| } |
| |
| RouterIdElt * |
| CacheViewComp::findf_router_elt(uint32_t addr) |
| { |
| for (RouterIdElt *rtr = this->atf_router_array(), *limit = rtr + this->getRouterCount(); rtr < limit; ++rtr) { |
| if (rtr->getAddr() == addr) |
| return rtr; |
| } |
| return 0; |
| } |
| |
| size_t |
| CacheViewComp::calcSize(int n_routers, int n_caches) |
| { |
| return sizeof(raw_t) + n_routers * sizeof(RouterIdElt) + sizeof(uint32_t) + n_caches * sizeof(uint32_t); |
| } |
| |
| CacheViewComp & |
| CacheViewComp::fill(MsgBuffer &buffer, detail::cache::GroupData const &group) |
| { |
| int i; |
| size_t n_routers = group.m_routers.size(); |
| size_t n_caches = group.m_caches.size(); |
| size_t comp_size = this->calcSize(n_routers, n_caches); |
| |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| |
| this->setType(COMP_TYPE).setChangeNumber(group.m_generation); |
| |
| set_field(&raw_t::m_router_count, m_base, n_routers); |
| // Set the pointer to the count of caches. |
| m_cache_count = reinterpret_cast<uint32_t *>(m_base + sizeof(raw_t) + n_routers * sizeof(RouterIdElt)); |
| *m_cache_count = htonl(n_caches); // set the actual count. |
| |
| // Fill routers. |
| i = 0; |
| for (detail::cache::RouterBag::const_iterator spot = group.m_routers.begin(), limit = group.m_routers.end(); spot != limit; |
| ++spot, ++i) { |
| this->routerElt(i).setAddr(spot->m_addr).setRecvId(spot->m_recv.m_sn); |
| } |
| |
| // fill caches. |
| i = 0; |
| for (detail::cache::CacheBag::const_iterator spot = group.m_caches.begin(), limit = group.m_caches.end(); spot != limit; |
| ++spot, ++i) { |
| this->setCacheAddr(i, spot->idAddr()); |
| } |
| |
| this->setLength(comp_size - sizeof(super::raw_t)); |
| buffer.use(comp_size); |
| return *this; |
| } |
| |
| int |
| CacheViewComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < sizeof(raw_t)) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| m_cache_count = reinterpret_cast<uint32_t *>(m_base + sizeof(raw_t) + this->getRouterCount() * sizeof(RouterIdElt)); |
| size_t comp_size = this->calcSize(this->getRouterCount(), this->getCacheCount()); |
| if (this->getLength() != comp_size - sizeof(super::raw_t)) |
| zret = PARSE_COMP_WRONG_SIZE; |
| else |
| buffer.use(comp_size); |
| } |
| } |
| return zret; |
| } |
| // ------------------------------------------------------ |
| AssignmentKeyElt & |
| AssignInfoComp::keyElt() |
| { |
| return access_field(&raw_t::m_key, m_base); |
| } |
| |
| AssignmentKeyElt const & |
| AssignInfoComp::keyElt() const |
| { |
| return access_field(&raw_t::m_key, m_base); |
| } |
| |
| uint32_t |
| AssignInfoComp::getKeyChangeNumber() const |
| { |
| return access_field(&raw_t::m_key, m_base).getChangeNumber(); |
| } |
| |
| AssignInfoComp & |
| AssignInfoComp::setKeyChangeNumber(uint32_t n) |
| { |
| access_field(&raw_t::m_key, m_base).setChangeNumber(n); |
| return *this; |
| } |
| |
| uint32_t |
| AssignInfoComp::getKeyAddr() const |
| { |
| return access_field(&raw_t::m_key, m_base).getAddr(); |
| } |
| |
| AssignInfoComp & |
| AssignInfoComp::setKeyAddr(uint32_t addr) |
| { |
| access_field(&raw_t::m_key, m_base).setAddr(addr); |
| return *this; |
| } |
| |
| uint32_t |
| AssignInfoComp::getRouterCount() const |
| { |
| return access_field(&raw_t::m_routers, m_base).getCount(); |
| } |
| |
| RouterAssignElt & |
| AssignInfoComp::routerElt(int idx) |
| { |
| return access_field(&raw_t::m_routers, m_base).elt(idx); |
| } |
| |
| uint32_t |
| AssignInfoComp::getCacheCount() const |
| { |
| return ntohl(*m_cache_count); |
| } |
| |
| uint32_t |
| AssignInfoComp::getCacheAddr(int idx) const |
| { |
| return m_cache_count[idx + 1]; |
| } |
| |
| AssignInfoComp & |
| AssignInfoComp::setCacheAddr(int idx, uint32_t addr) |
| { |
| m_cache_count[idx + 1] = addr; |
| return *this; |
| } |
| |
| size_t |
| AssignInfoComp::calcSize(int n_routers, int n_caches) |
| { |
| return sizeof(raw_t) + RouterAssignListElt::calcVarSize(n_routers) + HashAssignElt::calcSize(n_caches); |
| } |
| |
| uint32_t * |
| AssignInfoComp::calcCacheCountPtr() |
| { |
| return reinterpret_cast<uint32_t *>(m_base + sizeof(raw_t) + access_field(&raw_t::m_routers, m_base).getVarSize()); |
| } |
| |
| AssignInfoComp::Bucket * |
| AssignInfoComp::calcBucketPtr() |
| { |
| return reinterpret_cast<Bucket *>(reinterpret_cast<char *>(m_cache_count) + sizeof(uint32_t) * (1 + this->getCacheCount())); |
| } |
| |
| AssignInfoComp & |
| AssignInfoComp::fill(MsgBuffer &buffer, detail::Assignment const &assign) |
| { |
| RouterAssignListElt const &ralist = assign.getRouterList(); |
| HashAssignElt const &ha = assign.getHash(); |
| size_t n_routers = ralist.getCount(); |
| size_t n_caches = ha.getCount(); |
| size_t comp_size = this->calcSize(n_routers, n_caches); |
| |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| |
| this->setType(COMP_TYPE); |
| this->keyElt() = assign.getKey(); |
| memcpy(&(access_field(&raw_t::m_routers, m_base)), &ralist, ralist.getSize()); |
| // Set the pointer to the count of caches and write the count. |
| m_cache_count = this->calcCacheCountPtr(); |
| memcpy(m_cache_count, &ha, ha.getSize()); |
| |
| this->setLength(comp_size - HEADER_SIZE); |
| buffer.use(comp_size); |
| |
| return *this; |
| } |
| |
| int |
| AssignInfoComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < HEADER_SIZE) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| int n_routers = this->getRouterCount(); |
| int n_caches; |
| m_cache_count = this->calcCacheCountPtr(); |
| n_caches = this->getCacheCount(); |
| m_buckets = this->calcBucketPtr(); |
| size_t comp_size = this->calcSize(n_routers, n_caches); |
| if (this->getLength() != comp_size - HEADER_SIZE) |
| zret = PARSE_COMP_WRONG_SIZE; |
| else |
| buffer.use(comp_size); |
| } |
| } |
| if (PARSE_SUCCESS != zret) |
| m_base = 0; |
| return zret; |
| } |
| |
| AssignmentKeyElt & |
| AltAssignComp::keyElt() |
| { |
| return access_field(&raw_t::m_key, m_base); |
| } |
| |
| AssignmentKeyElt const & |
| AltAssignComp::keyElt() const |
| { |
| return access_field(&raw_t::m_key, m_base); |
| } |
| |
| void * |
| AltAssignComp::calcVarPtr() |
| { |
| return reinterpret_cast<void *>(m_base + sizeof(raw_t) + access_field(&raw_t::m_routers, m_base).getVarSize()); |
| } |
| |
| uint32_t |
| AltAssignComp::getRouterCount() const |
| { |
| return access_field(&raw_t::m_routers, m_base).getCount(); |
| } |
| |
| uint32_t |
| AltHashAssignComp::getCacheCount() const |
| { |
| return ntohl(*m_cache_count); |
| } |
| |
| size_t |
| AltHashAssignComp::calcSize(int n_routers, int n_caches) |
| { |
| return sizeof(raw_t) + RouterAssignListElt::calcVarSize(n_routers) + HashAssignElt::calcSize(n_caches); |
| } |
| |
| AltHashAssignComp & |
| AltHashAssignComp::fill(MsgBuffer &buffer, detail::Assignment const &assign) |
| { |
| RouterAssignListElt const &ralist = assign.getRouterList(); |
| HashAssignElt const &ha = assign.getHash(); |
| size_t n_routers = ralist.getCount(); |
| size_t n_caches = ha.getCount(); |
| size_t comp_size = this->calcSize(n_routers, n_caches); |
| |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| |
| this->setType(COMP_TYPE) |
| .setLength(comp_size - HEADER_SIZE) |
| .setAssignType(ALT_HASH_ASSIGNMENT) |
| .setAssignLength(comp_size - HEADER_SIZE - sizeof(local_header_t)); |
| this->keyElt() = assign.getKey(); |
| memcpy(&(access_field(&raw_t::m_routers, m_base)), &ralist, ralist.getSize()); |
| // Set the pointer to the count of caches and write the count. |
| m_cache_count = static_cast<uint32_t *>(this->calcVarPtr()); |
| memcpy(m_cache_count, &ha, ha.getSize()); |
| |
| buffer.use(comp_size); |
| |
| return *this; |
| } |
| |
| int |
| AltHashAssignComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < sizeof(raw_t)) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| int n_routers = this->getRouterCount(); |
| int n_caches; |
| m_cache_count = static_cast<uint32_t *>(this->calcVarPtr()); |
| n_caches = this->getCacheCount(); |
| size_t comp_size = this->calcSize(n_routers, n_caches); |
| if (this->getLength() != comp_size - HEADER_SIZE) |
| zret = PARSE_COMP_WRONG_SIZE; |
| else |
| buffer.use(comp_size); |
| } |
| } |
| if (PARSE_SUCCESS != zret) |
| m_base = 0; |
| return zret; |
| } |
| |
| AltMaskAssignComp & |
| AltMaskAssignComp::fill(MsgBuffer &buffer, detail::Assignment const &assign) |
| { |
| RouterAssignListElt const &ralist = assign.getRouterList(); |
| MaskAssignElt const &ma = assign.getMask(); |
| size_t comp_size = sizeof(raw_t) + ralist.getVarSize() + ma.getSize(); |
| |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| |
| this->setType(COMP_TYPE) |
| .setLength(comp_size - HEADER_SIZE) |
| .setAssignType(ALT_MASK_ASSIGNMENT) |
| .setAssignLength(comp_size - HEADER_SIZE - sizeof(local_header_t)); |
| this->keyElt() = assign.getKey(); |
| |
| memcpy(&(access_field(&raw_t::m_routers, m_base)), &ralist, ralist.getSize()); |
| m_mask_elt = static_cast<MaskAssignElt *>(this->calcVarPtr()); |
| memcpy(m_mask_elt, &ma, ma.getSize()); |
| |
| buffer.use(comp_size); |
| |
| return *this; |
| } |
| |
| int |
| AltMaskAssignComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < sizeof(raw_t)) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| RouterAssignListElt *ralist = &(access_field(&raw_t::m_routers, m_base)); |
| m_mask_elt = static_cast<MaskAssignElt *>(this->calcVarPtr()); |
| size_t comp_size = sizeof(raw_t) + ralist->getVarSize() + m_mask_elt->getSize(); |
| if (this->getLength() != comp_size - HEADER_SIZE) |
| zret = PARSE_COMP_WRONG_SIZE; |
| else |
| buffer.use(comp_size); |
| } |
| } |
| if (PARSE_SUCCESS != zret) |
| m_base = 0; |
| return zret; |
| } |
| |
| // ------------------------------------------------------ |
| CmdComp::cmd_t |
| CmdComp::getCmd() const |
| { |
| return static_cast<cmd_t>(get_field(&raw_t::m_cmd, m_base)); |
| } |
| |
| CmdComp & |
| CmdComp::setCmd(cmd_t cmd) |
| { |
| set_field(&raw_t::m_cmd, m_base, cmd); |
| return *this; |
| } |
| |
| uint32_t |
| CmdComp::getCmdData() const |
| { |
| return get_field(&raw_t::m_cmd_data, m_base); |
| } |
| |
| CmdComp & |
| CmdComp::setCmdData(uint32_t data) |
| { |
| set_field(&raw_t::m_cmd_data, m_base, data); |
| return *this; |
| } |
| |
| inline size_t |
| CmdComp::calcSize() |
| { |
| return sizeof(raw_t); |
| } |
| |
| CmdComp & |
| CmdComp::fill(MsgBuffer &buffer, cmd_t cmd, uint32_t data) |
| { |
| size_t comp_size = this->calcSize(); |
| |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| |
| this->setType(COMP_TYPE).setCmd(cmd).setCmdData(data).setLength(sizeof(raw_t) - sizeof(super::raw_t)); |
| // Command length is always the same. |
| set_field(&raw_t::m_length, m_base, sizeof(uint32_t)); |
| // reinterpret_cast<raw_t*>(m_base)->m_length = htons(sizeof(uint32_t)); |
| return *this; |
| } |
| |
| int |
| CmdComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < sizeof(raw_t)) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| if (this->getLength() + sizeof(super::raw_t) != this->calcSize()) |
| zret = PARSE_COMP_WRONG_SIZE; |
| } |
| } |
| return zret; |
| } |
| // ------------------------------------------------------ |
| CapabilityElt & |
| CapComp::elt(int idx) |
| { |
| return access_array<CapabilityElt>(m_base + sizeof(super::raw_t))[idx]; |
| } |
| |
| CapabilityElt const & |
| CapComp::elt(int idx) const |
| { |
| return access_array<CapabilityElt>(m_base + sizeof(super::raw_t))[idx]; |
| } |
| |
| void |
| CapComp::cache() const |
| { |
| uint32_t x; // scratch for bounds checking. |
| // Reset all values. |
| m_packet_forward = ServiceGroup::NO_PACKET_STYLE; |
| m_packet_return = ServiceGroup::NO_PACKET_STYLE; |
| m_cache_assign = ServiceGroup::NO_CACHE_ASSIGN_STYLE; |
| if (!m_base) |
| return; // No data, everything is default. |
| // Load from data. |
| for (uint32_t i = 0, n = this->getEltCount(); i < n; ++i) { |
| CapabilityElt const &elt = this->elt(i); |
| switch (elt.getCapType()) { |
| case CapabilityElt::PACKET_FORWARD_METHOD: |
| x = elt.getCapData(); |
| if (0 < x && x < 4) |
| m_packet_forward = static_cast<ServiceGroup::PacketStyle>(x); |
| break; |
| case CapabilityElt::PACKET_RETURN_METHOD: |
| x = elt.getCapData(); |
| if (0 < x && x < 4) |
| m_packet_return = static_cast<ServiceGroup::PacketStyle>(x); |
| break; |
| case CapabilityElt::CACHE_ASSIGNMENT_METHOD: |
| x = elt.getCapData(); |
| if (0 < x && x < 4) |
| m_cache_assign = static_cast<ServiceGroup::CacheAssignmentStyle>(x); |
| break; |
| default: |
| logf(LVL_INFO, "Invalid capability type %d in packet.", elt.getCapType()); |
| break; |
| } |
| } |
| m_cached = true; |
| } |
| |
| CapComp & |
| CapComp::fill(MsgBuffer &buffer, int n) |
| { |
| size_t comp_size = this->calcSize(n); |
| m_cached = false; |
| |
| if (buffer.getSpace() < comp_size) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| this->setType(COMP_TYPE).setLength(comp_size - sizeof(super::raw_t)); |
| m_count = n; |
| buffer.use(comp_size); |
| |
| return *this; |
| } |
| |
| int |
| CapComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| m_cached = false; |
| if (buffer.getSpace() < sizeof(raw_t)) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| // No explicit count, compute it from length. |
| m_count = this->getLength() / sizeof(CapabilityElt); |
| buffer.use(this->getLength() + sizeof(super::raw_t)); |
| } |
| } |
| return zret; |
| } |
| // ------------------------------------------------------ |
| int |
| QueryComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < sizeof(raw_t)) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) |
| buffer.use(this->calcSize()); |
| } |
| return zret; |
| } |
| // ------------------------------------------------------ |
| uint32_t |
| AssignMapComp::getCount() const |
| { |
| return access_field(&raw_t::m_assign, m_base).getCount(); |
| } |
| |
| AssignMapComp & |
| AssignMapComp::fill(MsgBuffer &buffer, detail::Assignment const &assign) |
| { |
| size_t comp_size = sizeof(raw_t); |
| MaskAssignElt const &ma = assign.getMask(); |
| size_t ma_size = ma.getSize(); // Not constant time. |
| |
| // Can't be precise, but we need at least one mask/value set with |
| // at least one value. If we don't have that it's a clear fail. |
| if (buffer.getSpace() < comp_size + sizeof(MaskValueSetElt::calcSize(1))) |
| throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); |
| |
| m_base = buffer.getTail(); |
| memcpy(&(access_field(&raw_t::m_assign, m_base)), &ma, ma_size); |
| comp_size += ma_size - sizeof(ma); |
| |
| this->setType(COMP_TYPE).setLength(comp_size - HEADER_SIZE); |
| buffer.use(comp_size); |
| |
| return *this; |
| } |
| |
| int |
| AssignMapComp::parse(MsgBuffer &buffer) |
| { |
| int zret = PARSE_SUCCESS; |
| if (buffer.getSpace() < HEADER_SIZE) |
| zret = PARSE_BUFFER_TOO_SMALL; |
| else { |
| m_base = buffer.getTail(); |
| zret = this->checkHeader(buffer, COMP_TYPE); |
| if (PARSE_SUCCESS == zret) { |
| // TBD - Actually check the mask/value set data !! |
| buffer.use(this->getLength() + HEADER_SIZE); |
| } |
| } |
| if (PARSE_SUCCESS != zret) |
| m_base = 0; |
| return zret; |
| } |
| // ------------------------------------------------------ |
| detail::Assignment::Assignment() : m_key(0, 0), m_active(false), m_router_list(0), m_hash_assign(0), m_mask_assign(0) {} |
| |
| bool |
| detail::Assignment::fill(cache::GroupData &group, uint32_t addr) |
| { |
| // Compute the last packet received times for the routers. For each |
| // cache, compute how many routers mentioned it in their last |
| // packet. Prepare an assignment from those caches. If there are no |
| // such caches, fail the assignment. Any cache that wasn't |
| // mentioned by at least one router are purged. |
| |
| size_t n_routers = group.m_routers.size(); // routers in group |
| size_t n_caches = group.m_caches.size(); // caches in group |
| |
| // We need both routers and caches to do something useful. |
| if (!(n_routers && n_caches)) |
| return false; |
| |
| // Iteration vars. |
| size_t cdx, rdx; |
| cache::RouterBag::iterator rspot, rbegin = group.m_routers.begin(), rend = group.m_routers.end(); |
| cache::CacheBag::iterator cspot, cbegin = group.m_caches.begin(), cend = group.m_caches.end(); |
| |
| size_t nr[n_caches]; // validity check counts. |
| memset(nr, 0, sizeof(nr)); // Set counts to zero. |
| |
| // Guess at size of serialization buffer. For the router list and |
| // the hash assignment, we can compute reasonable upper bounds and so |
| // we don't have to do space checks when those get filled out. |
| // The mask assignment is more difficult. We just guess generously and |
| // try to recover if we go over. |
| size_t size = RouterAssignListElt::calcSize(n_routers) + HashAssignElt::calcSize(n_caches) + 4096; |
| |
| if (m_buffer.getSize() < size) { |
| ats_free(m_buffer.getBase()); |
| m_buffer.set(ats_malloc(size), size); |
| } |
| m_buffer.reset(); |
| |
| // Set assignment key |
| m_key.setAddr(addr).setChangeNumber(group.m_generation); |
| |
| m_router_list = reinterpret_cast<RouterAssignListElt *>(m_buffer.getBase()); |
| new (m_router_list) RouterAssignListElt(n_routers); |
| |
| // For each router, update the assignment and run over the caches |
| // and bump the nr count if that cache was included in the most |
| // recent packet. Note that the router data gets updated from |
| // ISeeYou message processing as well, this is more of an initial |
| // setup. |
| for (rdx = 0, rspot = rbegin; rspot != rend; ++rspot, ++rdx) { |
| // Update router assignment. |
| m_router_list->elt(rdx).setChangeNumber(rspot->m_generation).setAddr(rspot->m_addr).setRecvId(rspot->m_recv.m_sn); |
| // Check cache validity. |
| for (cdx = 0, cspot = cbegin; cspot != cend; ++cspot, ++cdx) { |
| if (cspot->m_src[rdx].m_time == rspot->m_recv.m_time) |
| ++(nr[cdx]); |
| } |
| } |
| |
| size_t k = m_router_list->getSize(); |
| m_buffer.use(k); |
| m_hash_assign = reinterpret_cast<HashAssignElt *>(m_buffer.getTail()); |
| |
| // If the nr value is 0, then the cache was not included in any |
| // last packet, so it should be discarded. A cache is valid if |
| // nr is n_routers, indicating that every router mentioned it. |
| int v_caches = 0; // valid caches |
| for (cdx = 0, cspot = cbegin; cspot != cend; ++cspot, ++cdx) |
| if (nr[cdx] == n_routers) { |
| m_hash_assign->setAddr(cdx, cspot->idAddr()); |
| ++v_caches; |
| } |
| |
| if (!v_caches) { // no valid caches. |
| log(LVL_INFO, "Attempted to generate cache assignment but no valid caches were found."); |
| return false; |
| } |
| // Just sets the cache count. |
| new (m_hash_assign) HashAssignElt(v_caches); |
| m_hash_assign->round_robin_assign(); |
| m_buffer.use(m_hash_assign->getSize()); |
| |
| m_mask_assign = reinterpret_cast<MaskAssignElt *>(m_buffer.getTail()); |
| new (m_mask_assign) MaskAssignElt; |
| |
| // For now, hardwire everything to first cache. |
| // We have plenty of space, but will need to check if we do something |
| // more complex here. |
| m_mask_assign->init(0, 0, 0, 0)->addValue(m_hash_assign->getAddr(0), 0, 0, 0, 0); |
| |
| logf(LVL_INFO, "Generated assignment for group %d with %d routers, %d valid caches.", group.m_svc.getSvcId(), n_routers, |
| v_caches); |
| |
| return true; |
| } |
| // ------------------------------------------------------ |
| void |
| BaseMsg::setBuffer(MsgBuffer const &buffer) |
| { |
| m_buffer = buffer; |
| } |
| |
| void |
| BaseMsg::finalize() |
| { |
| m_header.setLength(m_buffer.getCount() - m_header.calcSize()); |
| m_security.secure(m_buffer); |
| } |
| |
| bool |
| BaseMsg::validateSecurity() const |
| { |
| return m_security.validate(m_buffer); |
| } |
| // ------------------------------------------------------ |
| void |
| HereIAmMsg::fill(detail::cache::GroupData const &group, CacheIdBox const &cache_id, SecurityOption sec_opt) |
| { |
| m_header.fill(m_buffer, HERE_I_AM); |
| m_security.fill(m_buffer, sec_opt); |
| m_service.fill(m_buffer, group.m_svc); |
| m_cache_id.fill(m_buffer, cache_id); |
| m_cache_view.fill(m_buffer, group); |
| } |
| |
| void |
| HereIAmMsg::fill_caps(detail::cache::RouterData const &router) |
| { |
| if (router.m_send_caps) { |
| m_capabilities.fill(m_buffer, 3); |
| m_capabilities.elt(0) = CapabilityElt(CapabilityElt::PACKET_FORWARD_METHOD, router.m_packet_forward); |
| m_capabilities.elt(1) = CapabilityElt(CapabilityElt::CACHE_ASSIGNMENT_METHOD, router.m_cache_assign); |
| m_capabilities.elt(2) = CapabilityElt(CapabilityElt::PACKET_RETURN_METHOD, router.m_packet_return); |
| } |
| } |
| |
| int |
| HereIAmMsg::parse(ts::Buffer const &buffer) |
| { |
| int zret; |
| this->setBuffer(buffer); |
| if (!m_buffer.getBase()) |
| return -EINVAL; |
| zret = m_header.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| if (HERE_I_AM != m_header.getType()) |
| return PARSE_MSG_WRONG_TYPE; |
| |
| // Time to look for components. |
| zret = m_security.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| |
| zret = m_service.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| |
| zret = m_cache_id.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| |
| zret = m_cache_view.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| |
| // These are optional so failures can be ignored. |
| if (m_buffer.getSpace()) |
| m_capabilities.parse(m_buffer); |
| if (m_buffer.getSpace()) |
| m_command.parse(m_buffer); |
| |
| return m_buffer.getSpace() ? PARSE_DATA_OVERRUN : PARSE_SUCCESS; |
| } |
| // ------------------------------------------------------ |
| void |
| RedirectAssignMsg::fill(detail::cache::GroupData const &group, SecurityOption sec_opt) |
| { |
| m_header.fill(m_buffer, REDIRECT_ASSIGN); |
| m_security.fill(m_buffer, sec_opt); |
| m_service.fill(m_buffer, group.m_svc); |
| switch (group.m_cache_assign) { |
| case ServiceGroup::HASH_ONLY: |
| m_hash_assign.fill(m_buffer, group.m_assign_info); |
| break; |
| case ServiceGroup::MASK_ONLY: |
| m_alt_mask_assign.fill(m_buffer, group.m_assign_info); |
| break; |
| default: |
| logf(LVL_WARN, "Bad assignment type [%d] for REDIRECT_ASSIGN", group.m_cache_assign); |
| break; |
| } |
| } |
| // ------------------------------------------------------ |
| void |
| ISeeYouMsg::fill(detail::router::GroupData const &group, SecurityOption sec_opt, detail::Assignment & /* assign ATS_UNUSED */, |
| size_t to_caches, size_t n_routers, size_t n_caches, bool /* send_capabilities ATS_UNUSED */ |
| ) |
| { |
| m_header.fill(m_buffer, I_SEE_YOU); |
| m_security.fill(m_buffer, sec_opt); |
| m_service.fill(m_buffer, group.m_svc); |
| m_router_id.fill(m_buffer, to_caches); |
| m_router_view.fill(m_buffer, n_routers, n_caches); |
| } |
| |
| int |
| ISeeYouMsg::parse(ts::Buffer const &buffer) |
| { |
| int zret; |
| this->setBuffer(buffer); |
| if (!m_buffer.getBase()) |
| return -EINVAL; |
| zret = m_header.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| if (I_SEE_YOU != m_header.getType()) |
| return PARSE_MSG_WRONG_TYPE; |
| |
| // Time to look for components. |
| zret = m_security.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| |
| zret = m_service.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| |
| zret = m_router_id.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) { |
| logf(LVL_DEBUG, "I_SEE_YOU: Invalid %d router id", zret); |
| return zret; |
| } |
| |
| zret = m_router_view.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) { |
| logf(LVL_DEBUG, "I_SEE_YOU: Invalid %d router view", zret); |
| return zret; |
| } |
| |
| // Optional components. |
| |
| // Test for alternates here |
| // At most one of the assignments but never both. |
| // Can be omitted. |
| m_assignment.parse(m_buffer); |
| m_map.parse(m_buffer); |
| |
| // Optional components. |
| m_capabilities.parse(m_buffer); |
| m_command.parse(m_buffer); |
| |
| if (m_buffer.getSpace()) { |
| zret = PARSE_DATA_OVERRUN; |
| logf(LVL_DEBUG, "I_SEE_YOU: Data overrun %lu", m_buffer.getSpace()); |
| } |
| |
| return zret; |
| } |
| // ------------------------------------------------------ |
| int |
| RemovalQueryMsg::parse(ts::Buffer const &buffer) |
| { |
| int zret; |
| this->setBuffer(buffer); |
| if (!m_buffer.getBase()) |
| return -EINVAL; |
| zret = m_header.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| if (REMOVAL_QUERY != m_header.getType()) |
| return PARSE_MSG_WRONG_TYPE; |
| |
| // Get the components. |
| zret = m_security.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| |
| zret = m_service.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| |
| zret = m_query.parse(m_buffer); |
| if (PARSE_SUCCESS != zret) |
| return zret; |
| |
| return m_buffer.getSpace() ? PARSE_DATA_OVERRUN : PARSE_SUCCESS; |
| } |
| // ------------------------------------------------------ |
| } // namespace wccp |