|
|
|
@ -54,7 +54,7 @@ namespace http {
@@ -54,7 +54,7 @@ namespace http {
|
|
|
|
|
" body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; }\r\n" |
|
|
|
|
" a, .slide label { text-decoration: none; color: #894C84; }\r\n" |
|
|
|
|
" a:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n" |
|
|
|
|
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none; color: initial;}\r\n" |
|
|
|
|
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none; color: initial; width: 1.5em;}\r\n" |
|
|
|
|
" .header { font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84; }\r\n" |
|
|
|
|
" .wrapper { margin: 0 auto; padding: 1em; max-width: 60em; }\r\n" |
|
|
|
|
" .left { float: left; position: absolute; }\r\n" |
|
|
|
@ -64,12 +64,13 @@ namespace http {
@@ -64,12 +64,13 @@ namespace http {
|
|
|
|
|
" .tunnel.failed { color: #D33F3F; }\r\n" |
|
|
|
|
" .tunnel.building { color: #434343; }\r\n" |
|
|
|
|
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" |
|
|
|
|
" table { width: 100%; border-collapse: collapse; text-align: center; }\r\n" |
|
|
|
|
" .slide p, .slide [type='checkbox'] { display: none; }\r\n" |
|
|
|
|
" .slide [type='checkbox']:checked ~ p { display: block; margin-top: 0; padding: 0; }\r\n" |
|
|
|
|
" table { display: table; border-collapse: collapse; text-align: center; }\r\n" |
|
|
|
|
" table.extaddr { text-align: left; }\r\n table.services { width: 100%; }" |
|
|
|
|
" .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n" |
|
|
|
|
" .slide div.content, .slide [type='checkbox'] { display: none; }\r\n" |
|
|
|
|
" .slide [type='checkbox']:checked ~ div.content { display: block; margin-top: 0; padding: 0; }\r\n" |
|
|
|
|
" .disabled:after { color: #D33F3F; content: \"Disabled\" }\r\n" |
|
|
|
|
" .enabled:after { color: #56B734; content: \"Enabled\" }\r\n" |
|
|
|
|
" .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n" |
|
|
|
|
"</style>\r\n"; |
|
|
|
|
|
|
|
|
|
const char HTTP_PAGE_TUNNELS[] = "tunnels"; |
|
|
|
@ -181,8 +182,10 @@ namespace http {
@@ -181,8 +182,10 @@ namespace http {
|
|
|
|
|
"<div class=left>\r\n" |
|
|
|
|
" <a href=\"" << webroot << "\">Main page</a><br>\r\n<br>\r\n" |
|
|
|
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_COMMANDS << "\">Router commands</a><br>\r\n" |
|
|
|
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">Local destinations</a><br>\r\n" |
|
|
|
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</a><br>\r\n" |
|
|
|
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">Local destinations</a><br>\r\n"; |
|
|
|
|
if (i2p::context.IsFloodfill ()) |
|
|
|
|
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</a><br>\r\n"; |
|
|
|
|
s << |
|
|
|
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">Tunnels</a><br>\r\n" |
|
|
|
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">Transit tunnels</a><br>\r\n" |
|
|
|
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">Transports</a><br>\r\n" |
|
|
|
@ -234,11 +237,8 @@ namespace http {
@@ -234,11 +237,8 @@ namespace http {
|
|
|
|
|
} |
|
|
|
|
s << "<br>\r\n"; |
|
|
|
|
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) |
|
|
|
|
if (auto remains = Daemon.gracefulShutdownInterval) { |
|
|
|
|
s << "<b>Stopping in:</b> "; |
|
|
|
|
s << remains << " seconds"; |
|
|
|
|
s << "<br>\r\n"; |
|
|
|
|
} |
|
|
|
|
if (auto remains = Daemon.gracefulShutdownInterval) |
|
|
|
|
s << "<b>Stopping in:</b> " << remains << " seconds<br>\r\n"; |
|
|
|
|
#endif |
|
|
|
|
auto family = i2p::context.GetFamily (); |
|
|
|
|
if (family.length () > 0) |
|
|
|
@ -256,45 +256,50 @@ namespace http {
@@ -256,45 +256,50 @@ namespace http {
|
|
|
|
|
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n"; |
|
|
|
|
s << "<div class='slide'>"; |
|
|
|
|
if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) { |
|
|
|
|
s << "<label for='slide-info'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide-info'/>\r\n<p class='content'>\r\n"; |
|
|
|
|
s << "<label for='slide-info'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide-info'/>\r\n<div class='content'>\r\n"; |
|
|
|
|
} |
|
|
|
|
if(includeHiddenContent) { |
|
|
|
|
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n"; |
|
|
|
|
if (!i2p::context.GetRouterInfo().GetProperty("family").empty()) |
|
|
|
|
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n"; |
|
|
|
|
s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n"; |
|
|
|
|
s << "<b>Our external address:</b>" << "<br>\r\n" ; |
|
|
|
|
s << "<b>Our external address:</b>" << "<br>\r\n<table class=\"extaddr\"><tbody>\r\n"; |
|
|
|
|
for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) |
|
|
|
|
{ |
|
|
|
|
s << "<tr>\r\n"; |
|
|
|
|
if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ()) |
|
|
|
|
{ |
|
|
|
|
s << "NTCP2"; |
|
|
|
|
s << "<td>NTCP2"; |
|
|
|
|
if (address->host.is_v6 ()) s << "v6"; |
|
|
|
|
s << " supported <br>\r\n"; |
|
|
|
|
s << "</td><td>supported</td>\r\n</tr>\r\n"; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
switch (address->transportStyle) |
|
|
|
|
{ |
|
|
|
|
case i2p::data::RouterInfo::eTransportNTCP: |
|
|
|
|
{ |
|
|
|
|
s << "NTCP"; |
|
|
|
|
s << "<td>NTCP"; |
|
|
|
|
if (address->IsPublishedNTCP2 ()) s << "2"; |
|
|
|
|
if (address->host.is_v6 ()) s << "v6"; |
|
|
|
|
s << " "; |
|
|
|
|
s << "</td>\r\n"; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case i2p::data::RouterInfo::eTransportSSU: |
|
|
|
|
{ |
|
|
|
|
s << "<td>SSU"; |
|
|
|
|
if (address->host.is_v6 ()) |
|
|
|
|
s << "SSUv6 "; |
|
|
|
|
else |
|
|
|
|
s << "SSU "; |
|
|
|
|
s << "v6"; |
|
|
|
|
s << "</td>\r\n"; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
s << "Unknown "; |
|
|
|
|
s << "<td>Unknown</td>\r\n"; |
|
|
|
|
} |
|
|
|
|
s << address->host.to_string() << ":" << address->port << "<br>\r\n"; |
|
|
|
|
s << "<td>" << address->host.to_string() << ":" << address->port << "</td>\r\n</tr>\r\n"; |
|
|
|
|
} |
|
|
|
|
s << "</tbody></table>\r\n"; |
|
|
|
|
} |
|
|
|
|
s << "</p>\r\n</div>\r\n"; |
|
|
|
|
s << "</table>\r\n</div>\r\n</div>\r\n"; |
|
|
|
|
if(outputFormat==OutputFormatEnum::forQtUi) { |
|
|
|
|
s << "<br>"; |
|
|
|
|
} |
|
|
|
@ -310,15 +315,15 @@ namespace http {
@@ -310,15 +315,15 @@ namespace http {
|
|
|
|
|
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n"; |
|
|
|
|
|
|
|
|
|
if(outputFormat==OutputFormatEnum::forWebConsole) { |
|
|
|
|
s << "<table><caption>Services</caption><tr><th>Service</th><th>State</th></tr>\r\n"; |
|
|
|
|
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol); |
|
|
|
|
s << "<table class=\"services\"><caption>Services</caption><tbody>\r\n"; |
|
|
|
|
s << "<tr><td>" << "HTTP Proxy" << "</td><td><div class='" << ((i2p::client::context.GetHttpProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n"; |
|
|
|
|
s << "<tr><td>" << "SOCKS Proxy" << "</td><td><div class='" << ((i2p::client::context.GetSocksProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n"; |
|
|
|
|
s << "<tr><td>" << "BOB" << "</td><td><div class='" << ((i2p::client::context.GetBOBCommandChannel ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n"; |
|
|
|
|
s << "<tr><td>" << "SAM" << "</td><td><div class='" << ((i2p::client::context.GetSAMBridge ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n"; |
|
|
|
|
s << "<tr><td>" << "I2CP" << "</td><td><div class='" << ((i2p::client::context.GetI2CPServer ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n"; |
|
|
|
|
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol); |
|
|
|
|
s << "<tr><td>" << "I2PControl" << "</td><td><div class='" << ((i2pcontrol) ? "enabled" : "disabled") << "'></div></td></tr>\r\n"; |
|
|
|
|
s << "</table>\r\n"; |
|
|
|
|
s << "</tbody></table>\r\n"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -358,19 +363,20 @@ namespace http {
@@ -358,19 +363,20 @@ namespace http {
|
|
|
|
|
if (dest->IsEncryptedLeaseSet ()) |
|
|
|
|
{ |
|
|
|
|
i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ()); |
|
|
|
|
s << "<div class='slide'><label for='slide-b33'><b>Encrypted B33 address:</b></label>\r\n<input type='checkbox' id='slide-b33'/>\r\n<p class='content'>\r\n"; |
|
|
|
|
s << "<div class='slide'><label for='slide-b33'><b>Encrypted B33 address:</b></label>\r\n<input type='checkbox' id='slide-b33'/>\r\n<div class='content'>\r\n"; |
|
|
|
|
s << blinded.ToB33 () << ".b32.i2p<br>\r\n"; |
|
|
|
|
s << "</p>\r\n</div>\r\n"; |
|
|
|
|
s << "</div>\r\n</div>\r\n"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(dest->GetNumRemoteLeaseSets()) |
|
|
|
|
{ |
|
|
|
|
s << "<div class='slide'><label for='slide-lease'><b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets () << "</i></label>\r\n<input type='checkbox' id='slide-lease'/>\r\n<p class='content'>\r\n"; |
|
|
|
|
s << "<div class='slide'><label for='slide-lease'><b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets () |
|
|
|
|
<< "</i></label>\r\n<input type='checkbox' id='slide-lease'/>\r\n<div class='content'>\r\n<table><thead><th>Address</th><th>Type</th><th>EncType</th></thead><tbody>"; |
|
|
|
|
for(auto& it: dest->GetLeaseSets ()) |
|
|
|
|
s << it.first.ToBase32 () << " " << (int)it.second->GetStoreType () << "<br>\r\n"; |
|
|
|
|
s << "</p>\r\n</div>\r\n"; |
|
|
|
|
s << "<tr><td>" << it.first.ToBase32 () << "</td><td>" << (int)it.second->GetStoreType () << "</td><td>" << (int)it.second->GetEncryptionType () <<"</td></tr>\r\n"; |
|
|
|
|
s << "</tbody></table>\r\n</div>\r\n</div>\r\n<br>\r\n"; |
|
|
|
|
} else |
|
|
|
|
s << "<b>LeaseSets:</b> <i>0</i><br>\r\n"; |
|
|
|
|
s << "<b>LeaseSets:</b> <i>0</i><br>\r\n<br>\r\n"; |
|
|
|
|
auto pool = dest->GetTunnelPool (); |
|
|
|
|
if (pool) |
|
|
|
|
{ |
|
|
|
@ -395,10 +401,11 @@ namespace http {
@@ -395,10 +401,11 @@ namespace http {
|
|
|
|
|
if (!dest->GetSessions ().empty ()) { |
|
|
|
|
std::stringstream tmp_s; uint32_t out_tags = 0; |
|
|
|
|
for (const auto& it: dest->GetSessions ()) { |
|
|
|
|
tmp_s << i2p::client::context.GetAddressBook ().ToAddress(it.first) << " " << it.second->GetNumOutgoingTags () << "<br>\r\n"; |
|
|
|
|
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.first) << "</td><td>" << it.second->GetNumOutgoingTags () << "</td></tr>\r\n"; |
|
|
|
|
out_tags = out_tags + it.second->GetNumOutgoingTags (); |
|
|
|
|
} |
|
|
|
|
s << "<div class='slide'><label for='slide-tags'>Outgoing: <i>" << out_tags << "</i></label>\r\n<input type='checkbox' id='slide-tags'/>\r\n<p class='content'>\r\n" << tmp_s.str () << "</p>\r\n</div>\r\n"; |
|
|
|
|
s << "<div class='slide'><label for='slide-tags'>Outgoing: <i>" << out_tags << "</i></label>\r\n<input type='checkbox' id='slide-tags'/>\r\n" |
|
|
|
|
<< "<div class='content'>\r\n<table><tbody><thead><th>Destination</th><th>Amount</th></thead>\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n"; |
|
|
|
|
} else |
|
|
|
|
s << "Outgoing: <i>0</i><br>\r\n"; |
|
|
|
|
s << "<br>\r\n"; |
|
|
|
@ -472,6 +479,8 @@ namespace http {
@@ -472,6 +479,8 @@ namespace http {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ShowLeasesSets(std::stringstream& s) |
|
|
|
|
{ |
|
|
|
|
if (i2p::data::netdb.GetNumLeaseSets ()) |
|
|
|
|
{ |
|
|
|
|
s << "<b>LeaseSets:</b><br>\r\n<br>\r\n"; |
|
|
|
|
int counter = 1; |
|
|
|
@ -494,7 +503,7 @@ namespace http {
@@ -494,7 +503,7 @@ namespace http {
|
|
|
|
|
if (!ls->IsValid()) |
|
|
|
|
s << "<div class='invalid'>!! Invalid !! </div>\r\n"; |
|
|
|
|
s << "<div class='slide'><label for='slide" << counter << "'>" << dest.ToBase32() << "</label>\r\n"; |
|
|
|
|
s << "<input type='checkbox' id='slide" << (counter++) << "'/>\r\n<p class='content'>\r\n"; |
|
|
|
|
s << "<input type='checkbox' id='slide" << (counter++) << "'/>\r\n<div class='content'>\r\n"; |
|
|
|
|
s << "<b>Store type:</b> " << (int)storeType << "<br>\r\n"; |
|
|
|
|
s << "<b>Expires:</b> " << ConvertTime(ls->GetExpirationTime()) << "<br>\r\n"; |
|
|
|
|
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET || storeType == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2) |
|
|
|
@ -509,11 +518,20 @@ namespace http {
@@ -509,11 +518,20 @@ namespace http {
|
|
|
|
|
s << "<b>EndDate:</b> " << ConvertTime(l->endDate) << "<br>\r\n"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
s << "</p>\r\n</div>\r\n</div>\r\n"; |
|
|
|
|
s << "</div>\r\n</div>\r\n</div>\r\n"; |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
// end for each lease set
|
|
|
|
|
} |
|
|
|
|
else if (!i2p::context.IsFloodfill ()) |
|
|
|
|
{ |
|
|
|
|
s << "<b>LeaseSets:</b> not floodfill.<br>\r\n"; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
s << "<b>LeaseSets:</b> 0<br>\r\n"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ShowTunnels (std::stringstream& s) |
|
|
|
|
{ |
|
|
|
@ -573,6 +591,8 @@ namespace http {
@@ -573,6 +591,8 @@ namespace http {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ShowTransitTunnels (std::stringstream& s) |
|
|
|
|
{ |
|
|
|
|
if(i2p::tunnel::tunnels.CountTransitTunnels()) |
|
|
|
|
{ |
|
|
|
|
s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n"; |
|
|
|
|
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) |
|
|
|
@ -586,6 +606,11 @@ namespace http {
@@ -586,6 +606,11 @@ namespace http {
|
|
|
|
|
s << " " << it->GetNumTransmittedBytes () << "<br>\r\n"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
s << "<b>Transit tunnels:</b> no transit tunnels currently built.<br>\r\n"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template<typename Sessions> |
|
|
|
|
static void ShowNTCPTransports (std::stringstream& s, const Sessions& sessions, const std::string name) |
|
|
|
@ -617,13 +642,15 @@ namespace http {
@@ -617,13 +642,15 @@ namespace http {
|
|
|
|
|
} |
|
|
|
|
if (!tmp_s.str ().empty ()) |
|
|
|
|
{ |
|
|
|
|
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "'><b>" << name << "</b> ( " << cnt << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "'/>\r\n<p class='content'>"; |
|
|
|
|
s << tmp_s.str () << "</p>\r\n</div>\r\n"; |
|
|
|
|
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "'><b>" << name |
|
|
|
|
<< "</b> ( " << cnt << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "'/>\r\n<div class='content'>" |
|
|
|
|
<< tmp_s.str () << "</div>\r\n</div>\r\n"; |
|
|
|
|
} |
|
|
|
|
if (!tmp_s6.str ().empty ()) |
|
|
|
|
{ |
|
|
|
|
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "v6'><b>" << name << "v6</b> ( " << cnt6 << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "v6'/>\r\n<p class='content'>"; |
|
|
|
|
s << tmp_s6.str () << "</p>\r\n</div>\r\n"; |
|
|
|
|
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "v6'><b>" << name |
|
|
|
|
<< "v6</b> ( " << cnt6 << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "v6'/>\r\n<div class='content'>" |
|
|
|
|
<< tmp_s6.str () << "</div>\r\n</div>\r\n"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -650,7 +677,7 @@ namespace http {
@@ -650,7 +677,7 @@ namespace http {
|
|
|
|
|
auto sessions = ssuServer->GetSessions (); |
|
|
|
|
if (!sessions.empty ()) |
|
|
|
|
{ |
|
|
|
|
s << "<div class='slide'><label for='slide_ssu'><b>SSU</b> ( " << (int) sessions.size() << " )</label>\r\n<input type='checkbox' id='slide_ssu'/>\r\n<p class='content'>"; |
|
|
|
|
s << "<div class='slide'><label for='slide_ssu'><b>SSU</b> ( " << (int) sessions.size() << " )</label>\r\n<input type='checkbox' id='slide_ssu'/>\r\n<div class='content'>"; |
|
|
|
|
for (const auto& it: sessions) |
|
|
|
|
{ |
|
|
|
|
auto endpoint = it.second->GetRemoteEndpoint (); |
|
|
|
@ -662,12 +689,12 @@ namespace http {
@@ -662,12 +689,12 @@ namespace http {
|
|
|
|
|
s << " [itag:" << it.second->GetRelayTag () << "]"; |
|
|
|
|
s << "<br>\r\n" << std::endl; |
|
|
|
|
} |
|
|
|
|
s << "</p>\r\n</div>\r\n"; |
|
|
|
|
s << "</div>\r\n</div>\r\n"; |
|
|
|
|
} |
|
|
|
|
auto sessions6 = ssuServer->GetSessionsV6 (); |
|
|
|
|
if (!sessions6.empty ()) |
|
|
|
|
{ |
|
|
|
|
s << "<div class='slide'><label for='slide_ssuv6'><b>SSUv6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type='checkbox' id='slide_ssuv6'/>\r\n<p class='content'>"; |
|
|
|
|
s << "<div class='slide'><label for='slide_ssuv6'><b>SSUv6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type='checkbox' id='slide_ssuv6'/>\r\n<div class='content'>"; |
|
|
|
|
for (const auto& it: sessions6) |
|
|
|
|
{ |
|
|
|
|
auto endpoint = it.second->GetRemoteEndpoint (); |
|
|
|
@ -679,7 +706,7 @@ namespace http {
@@ -679,7 +706,7 @@ namespace http {
|
|
|
|
|
s << " [itag:" << it.second->GetRelayTag () << "]"; |
|
|
|
|
s << "<br>\r\n" << std::endl; |
|
|
|
|
} |
|
|
|
|
s << "</p>\r\n</div>\r\n"; |
|
|
|
|
s << "</div>\r\n</div>\r\n"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -688,10 +715,14 @@ namespace http {
@@ -688,10 +715,14 @@ namespace http {
|
|
|
|
|
{ |
|
|
|
|
std::string webroot; i2p::config::GetOption("http.webroot", webroot); |
|
|
|
|
auto sam = i2p::client::context.GetSAMBridge (); |
|
|
|
|
if (!sam) { |
|
|
|
|
if (!sam) |
|
|
|
|
{ |
|
|
|
|
ShowError(s, "SAM disabled"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(sam->GetSessions ().size ()) |
|
|
|
|
{ |
|
|
|
|
s << "<b>SAM Sessions:</b><br>\r\n<br>\r\n"; |
|
|
|
|
for (auto& it: sam->GetSessions ()) |
|
|
|
|
{ |
|
|
|
@ -700,6 +731,9 @@ namespace http {
@@ -700,6 +731,9 @@ namespace http {
|
|
|
|
|
s << name << " (" << it.first << ")</a><br>\r\n" << std::endl; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
s << "<b>SAM Sessions:</b> no sessions currently running.<br>\r\n"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void ShowSAMSession (std::stringstream& s, const std::string& id) |
|
|
|
|
{ |
|
|
|
|