| 82 | } |
| 83 | |
| 84 | std::shared_ptr<HostFile> |
| 85 | ParseHostFile(swoc::file::path const &path, ts_seconds interval) |
| 86 | { |
| 87 | std::shared_ptr<HostFile> hf; |
| 88 | |
| 89 | static DbgCtl dbg_ctl{"hostdb"}; |
| 90 | Dbg_bw(dbg_ctl, R"(Loading host file "{}")", path.view()); |
| 91 | |
| 92 | if (!path.empty()) { |
| 93 | std::error_code ec; |
| 94 | std::string content = swoc::file::load(path, ec); |
| 95 | if (!ec) { |
| 96 | HostAddrMap addr_map; |
| 97 | AddrHostMap host_map; |
| 98 | swoc::TextView text{content}; |
| 99 | while (text) { |
| 100 | auto line = text.take_prefix_at('\n').ltrim_if(&isspace); |
| 101 | if (line.empty() || '#' == *line) { |
| 102 | continue; |
| 103 | } |
| 104 | ParseHostLine(line, addr_map, host_map); |
| 105 | } |
| 106 | // @a map should be loaded with all of the data, create the records. |
| 107 | hf = std::make_shared<HostFile>(interval); |
| 108 | // Common loading function for creating a record from the address vector. |
| 109 | auto loader = [](swoc::TextView key, std::vector<IpAddr> const &v) -> HostDBRecord::Handle { |
| 110 | HostDBRecord::Handle record{HostDBRecord::alloc(key, v.size())}; |
| 111 | record->af_family = v.front().family(); // @a v is presumed family homogeneous |
| 112 | auto rr_info = record->rr_info(); |
| 113 | auto spot = v.begin(); |
| 114 | for (auto &item : rr_info) { |
| 115 | item.assign(*spot++); |
| 116 | } |
| 117 | return record; |
| 118 | }; |
| 119 | // Walk the temporary map and create the corresponding records for the persistent map. |
| 120 | for (auto const &[key, value] : addr_map) { |
| 121 | // Bit of subtlety to be able to search records with a view and not a string - the key |
| 122 | // must point at stable memory for the name, which is available in the record itself. |
| 123 | // Therefore the lookup for adding the record must be done using a view based in the record. |
| 124 | // It doesn't matter if it's the IPv4 or IPv6 record that's used, both are stable and equal |
| 125 | // to each other. |
| 126 | // IPv4 |
| 127 | if (auto const &v = std::get<IPV4_IDX>(value); v.size() > 0) { |
| 128 | auto r = loader(key, v); |
| 129 | hf->forward[r->name_view()].record_4 = r; |
| 130 | } |
| 131 | // IPv6 |
| 132 | if (auto const &v = std::get<IPV6_IDX>(value); v.size() > 0) { |
| 133 | auto r = loader(key, v); |
| 134 | hf->forward[r->name_view()].record_6 = r; |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | // Walk the temporary reverse map and create the reverse index. |
| 139 | for (auto const &[ip, host] : host_map) { |
| 140 | auto lup = hf->forward.find(host); |
| 141 | if (lup != hf->forward.end()) { |