00001 #include "artdaq/DAQdata/PortManager.hh"
00002 #define TRACE_NAME "PortManager"
00003 #include "artdaq/DAQdata/Globals.hh"
00004 #include "artdaq/DAQdata/TCPConnect.hh"
00005 #include <sstream>
00006
00007 artdaq::PortManager::PortManager()
00008 : base_configured_(false)
00009 , multicasts_configured_(false)
00010 , routing_tokens_configured_(false)
00011 , routing_acks_configured_(false)
00012 , xmlrpc_configured_(false)
00013 , tcpsocket_configured_(false)
00014 , request_port_configured_(false)
00015 , request_pattern_configured_(false)
00016 , routing_table_port_configured_(false)
00017 , routing_table_pattern_configured_(false)
00018 , multicast_transfer_port_configued_(false)
00019 , multicast_transfer_pattern_configured_(false)
00020 , base_port_(DEFAULT_BASE)
00021 , ports_per_partition_(DEFAULT_PORTS_PER_PARTITION)
00022 , multicast_interface_address_()
00023 , multicast_group_offset_(DEFAULT_MULTICAST_GROUP_OFFSET)
00024 , routing_token_offset_(DEFAULT_ROUTING_TOKEN_OFFSET)
00025 , routing_ack_offset_(DEFAULT_ROUTING_TABLE_ACK_OFFSET)
00026 , xmlrpc_offset_(DEFAULT_XMLRPC_OFFSET)
00027 , tcp_socket_offset_(DEFAULT_TCPSOCKET_OFFSET)
00028 , request_message_port_(DEFAULT_REQUEST_PORT)
00029 , routing_table_port_(DEFAULT_ROUTING_TABLE_PORT)
00030 , multicast_transfer_offset_(1024)
00031 , request_message_group_pattern_("227.128.PPP.SSS")
00032 , routing_table_group_pattern_("227.129.PPP.SSS")
00033 , multicast_transfer_group_pattern_("227.130.14.PPP")
00034 {
00035 }
00036
00037 void artdaq::PortManager::UpdateConfiguration(fhicl::ParameterSet const& ps)
00038 {
00039 if (ps.has_key("artdaq_base_port"))
00040 {
00041 auto newVal = ps.get<int>("artdaq_base_port");
00042 if (base_port_ != DEFAULT_BASE && base_port_ != newVal)
00043 {
00044 TLOG(TLVL_WARNING) << "Base port has changed! This may lead to misconfiguration and non-functional systems!";
00045 }
00046 base_port_ = newVal;
00047 }
00048 if (ps.has_key("ports_per_partition"))
00049 {
00050 auto newVal = ps.get<int>("ports_per_partition");
00051 if (ports_per_partition_ != DEFAULT_PORTS_PER_PARTITION && ports_per_partition_ != newVal)
00052 {
00053 TLOG(TLVL_WARNING) << "Ports per Partition has changed! This may lead to misconfiguration and non-functional systems!";
00054 }
00055 ports_per_partition_ = newVal;
00056 }
00057
00058 auto bp = getenv("ARTDAQ_BASE_PORT");
00059 if (bp != nullptr)
00060 {
00061 try
00062 {
00063 auto bp_s = std::string(bp);
00064 auto bp_tmp = std::stoi(bp_s, 0, 0);
00065 if (bp_tmp < 1024 || bp_tmp > 32000)
00066 {
00067 TLOG(TLVL_ERROR) << "Base port specified in ARTDAQ_BASE_PORT is invalid! Ignoring...";
00068 }
00069 else
00070 {
00071 base_port_ = bp_tmp;
00072 }
00073 }
00074 catch (std::invalid_argument) {}
00075 catch (std::out_of_range) {}
00076 }
00077
00078 auto ppp = getenv("ARTDAQ_PORTS_PER_PARTITION");
00079 if (ppp != nullptr)
00080 {
00081 try
00082 {
00083 auto ppp_s = std::string(ppp);
00084 auto ppp_tmp = std::stoi(ppp_s, 0, 0);
00085 if (ppp_tmp < 0 || ppp_tmp > 32000)
00086 {
00087 TLOG(TLVL_ERROR) << "Ports per partition specified in ARTDAQ_PORTS_PER_PARTITION is invalid! Ignoring...";
00088 }
00089 else
00090 {
00091 ports_per_partition_ = ppp_tmp;
00092 }
00093 }
00094 catch (std::invalid_argument) {}
00095 catch (std::out_of_range) {}
00096 }
00097
00098 if (!base_configured_ && (base_port_ != DEFAULT_BASE || ports_per_partition_ != DEFAULT_PORTS_PER_PARTITION))
00099 {
00100 base_configured_ = true;
00101 auto max_partitions = (65535 - base_port_) / ports_per_partition_;
00102 TLOG(TLVL_INFO) << "Based on configuration, there can be " << max_partitions << " partitions of " << ports_per_partition_ << " ports each, starting at port " << base_port_;
00103 if (GetPartitionNumber() > max_partitions)
00104 {
00105 TLOG(TLVL_ERROR) << "Currently-configured partition number is greater than the allowed number! The system WILL NOT WORK!";
00106 exit(22);
00107 }
00108 }
00109
00110 in_addr tmp_addr;
00111 bool multicast_configured = false;
00112 if (ps.has_key("multicast_output_interface"))
00113 {
00114 multicast_configured = GetIPOfInterface(ps.get<std::string>("multicast_output_interface"), tmp_addr) == 0;
00115 }
00116 else if (ps.has_key("multicast_output_network"))
00117 {
00118 multicast_configured = GetInterfaceForNetwork(ps.get<std::string>("multicast_output_network").c_str(), tmp_addr) == 0;
00119 }
00120 if (multicast_configured && multicasts_configured_ && tmp_addr.s_addr != multicast_interface_address_.s_addr)
00121 {
00122 TLOG(TLVL_WARNING) << "Multicast output address has changed! This may lead to misconfiguration and non-functional systems!";
00123 }
00124 else if (multicast_configured)
00125 {
00126 multicasts_configured_ = true;
00127 multicast_interface_address_ = tmp_addr;
00128 }
00129
00130 if (ps.has_key("multicast_group_offset"))
00131 {
00132 auto newVal = ps.get<int>("multicast_group_offset");
00133 if (multicast_group_offset_ != DEFAULT_MULTICAST_GROUP_OFFSET && multicast_group_offset_ != newVal)
00134 {
00135 TLOG(TLVL_WARNING) << "Multicast group offset (added to last part of group IP address) has changed! This may lead to misconfiguration and non-functional systems!";
00136 }
00137 multicast_group_offset_ = newVal;
00138 }
00139
00140 if (ps.has_key("routing_token_port_offset"))
00141 {
00142 auto newVal = ps.get<int>("routing_token_port_offset");
00143 if (routing_tokens_configured_ && newVal != routing_token_offset_)
00144 {
00145 TLOG(TLVL_WARNING) << "Routing Token Port Offset has changed! This may lead to misconfiguration and non-functional systems!";
00146 }
00147
00148 routing_tokens_configured_ = true;
00149 routing_token_offset_ = newVal;
00150 }
00151
00152 if (ps.has_key("routing_table_ack_port_offset"))
00153 {
00154 auto newVal = ps.get<int>("routing_table_ack_port_offset");
00155 if (routing_acks_configured_ && newVal != routing_ack_offset_)
00156 {
00157 TLOG(TLVL_WARNING) << "Routing Table Acknowledgement Port Offset has changed! This may lead to misconfiguration and non-functional systems!";
00158 }
00159
00160 routing_acks_configured_ = true;
00161 routing_ack_offset_ = newVal;
00162 }
00163
00164 if (ps.has_key("xmlrpc_port_offset"))
00165 {
00166
00167 auto newVal = ps.get<int>("xmlrpc_port_offset");
00168 if (xmlrpc_configured_ && newVal != xmlrpc_offset_)
00169 {
00170 TLOG(TLVL_WARNING) << "XMLRPC Port Offset has changed! This may lead to misconfiguration and non-functional systems!";
00171 }
00172
00173 xmlrpc_configured_ = true;
00174 xmlrpc_offset_ = newVal;
00175 }
00176
00177 if (ps.has_key("tcp_socket_port_offset"))
00178 {
00179 auto newVal = ps.get<int>("tcp_socket_port_offset");
00180 if (tcpsocket_configured_ && newVal != tcp_socket_offset_)
00181 {
00182 TLOG(TLVL_WARNING) << "TCPSocketTransfer Port Offset has changed! This may lead to misconfiguration and non-functional systems!";
00183 }
00184
00185 tcpsocket_configured_ = true;
00186 tcp_socket_offset_ = newVal;
00187 }
00188
00189 if (ps.has_key("request_port"))
00190 {
00191 auto newVal = ps.get<int>("request_port");
00192 if (request_port_configured_ && newVal != request_message_port_)
00193 {
00194 TLOG(TLVL_WARNING) << "Request Message Port has changed! This may lead to misconfiguration and non-functional systems!";
00195 }
00196
00197 request_port_configured_ = true;
00198 request_message_port_ = newVal;
00199
00200 }
00201
00202 if (ps.has_key("request_pattern"))
00203 {
00204 auto newVal = ps.get<std::string>("request_pattern");
00205 if (request_pattern_configured_ && newVal != request_message_group_pattern_)
00206 {
00207 TLOG(TLVL_WARNING) << "Request Message Multicast Group Pattern has changed! This may lead to misconfiguration and non-functional systems!";
00208 }
00209
00210 request_pattern_configured_ = true;
00211 request_message_group_pattern_ = newVal;
00212
00213 }
00214
00215 if (ps.has_key("routing_table_port"))
00216 {
00217 auto newVal = ps.get<int>("routing_table_port");
00218 if (routing_table_port_configured_ && newVal != routing_table_port_)
00219 {
00220 TLOG(TLVL_WARNING) << "Routing Table Port has changed! This may lead to misconfiguration and non-functional systems!";
00221 }
00222
00223 routing_table_port_configured_ = true;
00224 routing_table_port_ = newVal;
00225
00226 }
00227
00228 if (ps.has_key("routing_table_pattern"))
00229 {
00230 auto newVal = ps.get<std::string>("routing_table_pattern");
00231 if (routing_table_pattern_configured_ && newVal != routing_table_group_pattern_)
00232 {
00233 TLOG(TLVL_WARNING) << "Routing Table Multicast Group Pattern has changed! This may lead to misconfiguration and non-functional systems!";
00234 }
00235
00236 routing_table_pattern_configured_ = true;
00237 routing_table_group_pattern_ = newVal;
00238
00239 }
00240
00241 if (ps.has_key("multicast_transfer_port_offset"))
00242 {
00243 auto newVal = ps.get<int>("multicast_transfer_port_offset");
00244 if (multicast_transfer_port_configued_ && newVal != multicast_transfer_offset_)
00245 {
00246 TLOG(TLVL_WARNING) << "Multicast Transfer Port Offset has changed! This may lead to misconfiguration and non-functional systems!";
00247 }
00248
00249 multicast_transfer_port_configued_ = true;
00250 multicast_transfer_offset_ = newVal;
00251
00252 }
00253
00254 if (ps.has_key("multicast_transfer_pattern"))
00255 {
00256 auto newVal = ps.get<std::string>("multicast_transfer_pattern");
00257 if (multicast_transfer_pattern_configured_ && newVal != multicast_transfer_group_pattern_)
00258 {
00259 TLOG(TLVL_WARNING) << "Multicast Transfer Multicast Group Pattern has changed! This may lead to misconfiguration and non-functional systems!";
00260 }
00261
00262 multicast_transfer_pattern_configured_ = true;
00263 multicast_transfer_group_pattern_ = newVal;
00264
00265 }
00266 }
00267
00268 int artdaq::PortManager::GetRoutingTokenPort(int subsystemID)
00269 {
00270 if (!routing_tokens_configured_)
00271 {
00272 TLOG(TLVL_INFO) << "Using default port range for Routing Tokens";
00273 routing_tokens_configured_ = true;
00274 }
00275
00276 return base_port_ + routing_token_offset_ + (GetPartitionNumber() * ports_per_partition_) + subsystemID;
00277 }
00278
00279 int artdaq::PortManager::GetRoutingAckPort(int subsystemID)
00280 {
00281 if (!routing_acks_configured_)
00282 {
00283 TLOG(TLVL_INFO) << "Using default port range for Routing Table Acknowledgements";
00284 routing_acks_configured_ = true;
00285 }
00286 return base_port_ + routing_ack_offset_ + (GetPartitionNumber() * ports_per_partition_) + subsystemID;
00287 }
00288
00289 int artdaq::PortManager::GetXMLRPCPort(int rank)
00290 {
00291 if (!xmlrpc_configured_)
00292 {
00293 TLOG(TLVL_INFO) << "Using default port range for XMLRPC";
00294 xmlrpc_configured_ = true;
00295 }
00296 return base_port_ + xmlrpc_offset_ + rank + (GetPartitionNumber() * ports_per_partition_);
00297 }
00298
00299 int artdaq::PortManager::GetTCPSocketTransferPort(int rank)
00300 {
00301 if (!tcpsocket_configured_)
00302 {
00303 TLOG(TLVL_INFO) << "Using default port range for TCPSocket Transfer";
00304 tcpsocket_configured_ = true;
00305 }
00306 return base_port_ + tcp_socket_offset_ + (GetPartitionNumber() * ports_per_partition_) + rank;
00307 }
00308
00309 int artdaq::PortManager::GetRequestMessagePort()
00310 {
00311 if (!request_port_configured_)
00312 {
00313 TLOG(TLVL_INFO) << "Using default port for Request Messages";
00314 request_port_configured_ = true;
00315 }
00316 return request_message_port_;
00317
00318 }
00319
00320 std::string artdaq::PortManager::GetRequestMessageGroupAddress(int subsystemID)
00321 {
00322 if (!request_pattern_configured_)
00323 {
00324 TLOG(TLVL_INFO) << "Using default address for Request Messages";
00325 request_pattern_configured_ = true;
00326 }
00327
00328 return parse_pattern_(request_message_group_pattern_, subsystemID);
00329 }
00330
00331 int artdaq::PortManager::GetRoutingTablePort()
00332 {
00333 if (!routing_table_port_configured_)
00334 {
00335 TLOG(TLVL_INFO) << "Using default port for Routing Tables";
00336 routing_table_port_configured_ = true;
00337 }
00338
00339 return routing_table_port_;
00340 }
00341
00342 std::string artdaq::PortManager::GetRoutingTableGroupAddress(int subsystemID)
00343 {
00344 if (!routing_table_pattern_configured_)
00345 {
00346 TLOG(TLVL_INFO) << "Using default address for Routing Tables";
00347 routing_table_pattern_configured_ = true;
00348 }
00349
00350 return parse_pattern_(routing_table_group_pattern_, subsystemID);
00351 }
00352
00353 int artdaq::PortManager::GetMulticastTransferPort(int rank)
00354 {
00355 if (!multicast_transfer_port_configued_)
00356 {
00357 TLOG(TLVL_INFO) << "Using default port for Multicast Transfer";
00358 multicast_transfer_port_configued_ = true;
00359 }
00360
00361 return multicast_transfer_offset_ + rank;
00362 }
00363
00364 std::string artdaq::PortManager::GetMulticastTransferGroupAddress()
00365 {
00366 if (!multicast_transfer_pattern_configured_)
00367 {
00368 TLOG(TLVL_INFO) << "Using default address for Multicast Transfer";
00369 multicast_transfer_pattern_configured_ = true;
00370 }
00371
00372 return parse_pattern_(multicast_transfer_group_pattern_);
00373 }
00374
00375 in_addr artdaq::PortManager::GetMulticastOutputAddress(std::string interface_name, std::string interface_address)
00376 {
00377 if (!multicasts_configured_)
00378 {
00379 if (interface_name == "" && interface_address == "") TLOG(TLVL_INFO) << "Using default multicast output address (autodetected private interface)";
00380 if (interface_name != "")
00381 {
00382 GetIPOfInterface(interface_name, multicast_interface_address_);
00383 }
00384 else if (interface_address != "")
00385 {
00386 GetInterfaceForNetwork(interface_address.c_str(), multicast_interface_address_);
00387 }
00388 else
00389 {
00390 AutodetectPrivateInterface(multicast_interface_address_);
00391 }
00392 multicasts_configured_ = true;
00393 }
00394 return multicast_interface_address_;
00395 }
00396
00397 std::string artdaq::PortManager::parse_pattern_(std::string pattern, int subsystemID, int rank)
00398 {
00399 std::istringstream f(pattern);
00400 std::vector<int> address(4);
00401 std::string s;
00402
00403 while (getline(f, s, '.'))
00404 {
00405 if (s == "PPP") {
00406 address.push_back(GetPartitionNumber());
00407 }
00408 else if (s == "SSS") {
00409 address.push_back(subsystemID);
00410 }
00411 else if (s == "RRR") {
00412 address.push_back(rank);
00413 }
00414 else
00415 {
00416 address.push_back(stoi(s));
00417 }
00418 }
00419
00420 if (address.size() != 4)
00421 {
00422 TLOG(TLVL_ERROR) << "Invalid address pattern!";
00423 while (address.size() < 4) { address.push_back(0); }
00424 }
00425 address[3] += multicast_group_offset_;
00426
00427 return std::to_string(address[0]) + "." + std::to_string(address[1]) + "." + std::to_string(address[2]) + "." + std::to_string(address[3]);
00428 }