#include #include #include #include "util/base64.h" #include "util/Log.h" #include "Tunnel.h" #include "TransitTunnel.h" #include "transport/Transports.h" #include "NetDb.h" #include "util/I2PEndian.h" #include "Streaming.h" #include "Destination.h" #include "RouterContext.h" #include "ClientContext.h" #include "HTTPServer.h" // For image and info #include "version.h" namespace i2p { namespace util { const std::string HTTPConnection::itoopieImage = "\"ICToopie"; const std::string HTTPConnection::itoopieFavicon = "data:image/vnd.microsoft.icon;base64," "AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAABsAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgQAAAIMAAACEAAAAg" "wAAAIAAAACCAAAASQAAACUAAAAmAAAAOwAAAFIAAABgAAAAVAAAACcAAAAVAAAADQAAAAcAAAADAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjAAAA/wAAAP4AAAD+AAAA/gAAAP4AAAD+A" "AAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/" "AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAACbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAP8AA" "AD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4A" "AAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/wAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAKQAAAAAAAAAAAAAAAADbAAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP8AAAD/AAAA/gAA" "AP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAIA/gAAAPwAAAD/AAAA/gAAAP4AAAD+AAAA/gA" "AAP4AAAD+AAAA/wAAAFkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApAAAAAAAAAAAAHAAAAP8AAAD+AAAA/gAAAPwACwD9ABEA" "/QASAPgAFgD4ABUA+AATAP0ADQD8AAIA/AAAAP8AAAD+AAAA/gAAAP8ADQD7ACMA/QAlAP8AJwD/ACI" "A/QATAPwAAAD8AAAA/gAAAP4AAAD+AAAA/gAAAKIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADe" "AAAA/gAAAPwAJAD+AAwA+wAAAP8AAAD/AAAA/wAEAPwAEgD8ACQA/gAmAP8AHAD8AAEA/gAAAP4ACwD" "8ACUA/wAkAP8AFwD8AAkA/AAQAP0AIwD+ACQA/wANAPsAAAD+AAAA/gAAAP8AAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAEAAABNAAAA/wAAAP8AGAD8AAAA/QAYAPMARQDyAFEA9wBOAPIAPAD0ABEA8QAAAP8" "AGgD7ACMA/wAVAP0AAAD9ACMA/QAkAP8ADwD9AAgA+ABBAPUALADyAAAA/AAUAPwAJgD/ABgA/AAAAP" "0AAAD/AAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAP4ADQD8AAgA/wAqAPAAcAD/AGoA/wB" "qAP8AagD/AGoA/wBvAP8ATwDvAAAA/QAbAP0AEwD8AAYA/QAkAP8AGAD8AAsA9wBuAPgAagD/AGsA/w" "BjAPkADAD3AAQA/QAiAP4AGgD9AAAA/gAAAP8AAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZgAAAP8AAAD+ABY" "A+wAQAPQAcQD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBTAPEAAAD/AAcA/AAMAPwAIQD9AA" "AA+gBoAPgAagD/AGoA/wBqAP8AagD/AHAA/gAuAO0AAAD/AB8A/QAPAPwAAAD+AAAA+AAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAANIAAAD+AAwA+QAAAP0AZQD1AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8Abg" "D/ABcA8QAAAP4ACAD9AAAA+QBeAPkAagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AbQD/ADkA7wAAAP8AJ" "AD9AAAA/gAAAP8AAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAALi8AAAAAAAAAAAAAAAD/AAAA/QAAAP8AKwD1AGsA/wBqAP8AagD/AGoA/wBqAP" "8AagD/AGoA/wBqAP8AagD/AGoA/wA9APUAAAD/AAAA/wBKAPMAagD/AGoA/wBqAP8AagD/AGoA/wBqA" "P8AagD/AGoA/wBxAP8ADgD1ABMA/AAHAPsAAAD/AAAARQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzPAIAAAAgAAAA/wAAAPwAAAD/AGQA9A" "BqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8ASQD1AAAA/wASAPMAcAD/AGoA/" "wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AawD/ACsA+QAOAP4ADQD8AAAA/wAAAEUAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7gAAAAAAAADgwAQAYLwAA//8AAA" "ICIwAAAP8AAAD+AAYA8wBwAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/A" "EIA9QAAAP8AMADvAGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGsA/wApAP0AEQD8" "AAIA/QAAAP8AAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAVgEAAA" "AAACJ5AQA2ygAAND8BAHV+AgAAAAAAAAH/AAAA/gAcAPQAbAD/AGoA/wBqAP8AagD/AGoA/wBqAP8Aa" "gD/AGoA/wBqAP8AagD/AGsA/wApAPYAAAD+AB4A+gBsAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8A" "agD/AGoA/wBrAP8ALADxAAAA/AAAAP4AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAABYAhQAfAE8ABgBWAQAAAAAAIoABAAAAAAA5UgEAAAAAAAAA+AAAAP4AJQD2AGsA/wBqA" "P8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBsAPgAAAD6AAAA/gANAPAAbgD/AGoA/wBq" "AP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/ADsA+QAAAP8AAAD+AAAA4AAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtQAAAAAAAABYABgAZgEGAIMBAAAAAAA+fgEAAAAAAAAAA" "AACA8wAAAH+ACkA9wBgAPgARQDwADoA9gA5APYASgD0AHAA9wBrAP8AagD/AGoA/wBxAP0AFQD0AAAA" "/gAAAP4AAAD5AHMA/QBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBvAP0ATgDxAEwA9AA1AOkAAAD/AAA" "A/gAAAP8AAAB3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAvAAzAKcBAADXAAAAAAAcAFYBF" "gB4ASAAZwEAXT8BADpdAgAAAAAAAQG+AAEB/gAAAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAPsAJAD1" "AEQA9ABEAPMACQD3AAAA/wAAAP4AAAD+AAAA/wAiAPMASAD4AE8A9gBuAPgAbQD/AGoA/wBvAP8AFQD" "yAAAA/wAAAP8AAAD/AAAA/gAAAP4AAAD+AAAA/wAAABoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "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" "f7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf8/wCq5v4AERj+AAEA/gAAAP4AAAD+A" "AAA/gAAAP4AAAD/AAAAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgAAAD+AAAA/gAAAP4Aeqf9ALz//wC3+/8At/" "v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At" "/r/ALz//gAcJvwAAQH+AAAA/gAAAP4AAAD/AAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI0AAAD/AAAA/gAAAP" "4Ac579ALn+/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+" "/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Avf/+ABcg/QAAAf4AAAD+AAAA/wAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAABIAAAD/AAAA/gAAAP4AP1X9AL7//wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/" "wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wCy8v4AAAD+AAAA" "/gAAAP8AAACKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAACoAAAA/QAAAP4ABAb9AL7//wC3+/8At/v/ALf7/wC3+/8At/v/A" "Lf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/" "ALf7/wC3+/8Atvr/AHmm/QAAAP4AAAD+AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA/wAAAP4AAAD+AHWh/QC2+v8At" "/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8A" "t/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wDD//8AGSP9AAAA/gAAAP8AAABuAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbQAAA" "P8AAAD+AAUH/QDE//8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3" "+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Atvv/AH+s/gA" "AAP4AAAD+AAAA2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAALMAAAD+AAAA/gBZd/0At/z/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7" "/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf" "7/wC3+/8At/v/ALf7/wDF//8AAAD9AAAA/gAAAP8AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAA/gAAAP4Al9D9ALf7/wC3+/8At/v/" "ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v" "/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Auf7/AERe/QAAAP4AAAD/AAAAUQAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP4A" "AAD9AMb//gC3+/8At/v/ALf7/wC3+/8Auf7/AMb//gC2+f4AwP/+AMT//wC4/f8At/v/ALf7/wC3+/8" "At/v/ALf7/wC3+/8At/v/ALf7/wC8//8Avf//ALn+/wC3+/8At/v/ALf7/wC3+/8At/v/ALb7/wBvlf" "4AAAD+AAAA/gAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAACgAAAP8AAAD+ABgg/QDA//8At/v/ALf7/wC2+v8AuPz+AEVe/QAAAP0AAAD+AAAA/gA" "EBv0AU2/9ALz//wC3+/8At/v/ALf7/wC3+/8Atvr/AL7//wBmi/0ALj/9ACQx/QBJZP0Ai739AMD//w" "C3+/8At/v/ALf7/wC3+/8Aksj+AAAA/gAAAP4AAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcAAAD/AAAA/gAtPf4AvP//ALf7/wC3+/8As/T+AAo" "O/QAAAP0SEhLtAAAA/gAAAP4AAAD+AAAA/gAWH/0Av///ALf7/wC3+/8At/v/ALHx/gANEv0AAAD+AA" "AA/gAAAP4AAAD/AAAA/wAuP/0Avv//ALf7/wC3+/8At/v/AKjm/QAAAP4AAAD+AAAApwAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAA/wAAAP4AL0H" "+ALz//wC3+/8AvP//ADJE/QAAAPfc3Nz1TExM6wAAAP4AAAD+AAAA/gAAAP8AAAD+AGeN/gC3+/8At/" "v/AML//wAeKf0AAAH/AAAA/gAAAP4AAAD+cXFx3YSEhOoAAAD9AEVe/QC6//8At/v/ALf7/wCs7P8AA" "AD+AAAA/gAAAKEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAP8AAAD+ACAt/QC+//8At/v/ALP1/gAAAP95eXns/////2FhYeoBAQH/AAAA/gEBAf" "9eXl7lDQ0N9gAgLP0Av///ALf7/wCNwf4AAAD/NDQ03AAAAP8AAAD+AAAA/6Ojo+b/////eXl55AAAA" "P8AtPf+ALf7/wC3+/8AoNv9AAAA/gAAAP4AAACHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/gAAAP0Ax///ALf7/wCIu/0AAAD/ysrK6/" "/////8/Pz6Hx8f6wAAAP8kJCTm/f39/WVlZe4ABAX8AMT//wC3/P8AV3X9ERER7/////9MTEzrAAAA6" "ElJSeb///////////X19e8AAAD/AHuo/QC3+/8At/v/AIW2/gAAAP4AAAD/AAAAZAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0wAAAP4AAAD+AK" "fl/gC3+/8AjcH+AAAA/83Nze/////////////////////w//////////9gYGDsAA8V/QDC//8Auv//A" "EJa/UFBQeb////////////////////////////////////vAAAA/wBvlfwAt/v/ALf7/wBdff0AAAD+" "AAAA/wAAAC0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAI4AAAD+AAAA/gBnjP0At/v/ALz//gAAAP+CgoLx/////////////////////////////" "///CAkJ8QBCXP4Auf7/ALj8/wBScf0DAwPw////////////////////////////////tra26AAAAP8A" "hrf+ALf7/wDA//8AHCf9AAAA/gAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3AAAA/wAAAP4AEBb9AMT//wC6//8AQVn+AAAA9+Pj4" "/L/////////////////////cnJy1gAAAP8AlMr9ALf7/wC3+/8AhLT+AAAA/5mZmeL/////////////" "/////////////R0dHesAAAD9AL///gC3+/8ApuX+AAAA/gAAAP4AAAC1AAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMAAAD+AAAA/" "gCGtv0Atvr/ALn+/wARF/0AAAD3cHBw7bGxseqioqLuOjo67QAAAP8ARFz9ALz//wC3+/8At/v/AML/" "/wAbJf0AAAD/jo6O5v////b//////f397zw8PPEAAAD/AGCC/QC4/P8Auv//AEJb/QAAAP4AAAD/AAA" "AUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAABpAAAA/wAAAP4AERf9AMP//wC3+/8Auv/+AEVf/AAAAP8AAAD/AAAA/wAAAP0AWnn9" "AMH//wC3+/8At/v/ALf7/wC3+/8AtPf+ABsm/QAAAP8AAADwDg4O+QAAAPwAAAD+AD1T/QDB//8At/v" "/AKLd/gAAAP4AAAD+AAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPIAAAD+AAAA/gBfgP0Auf7/ALf7/wC5/v8A" "wv//AJnS/gCWzv4Awf//ALj9/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wDC//8Ahbb+AFBt/QA3TP0" "ATGn9AI/D/gC+//8At/v/AMD//wATGv0AAAD+AAAA/wAAAE4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA9AAAA/wAA" "AP4AAAD+AJPJ/QC2+v8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC" "3+/8At/v/ALf7/wC4/f8Au///ALj9/wC3+/8At/v/AML//wA0SP0AAAD+AAAA/QAAAMMAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAJYAAAD/AAAA/gAAAP4Andj9ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf" "7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/AML//wA+Vf0AAAD+AA" "AA/gAAAPYAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwwAAAP4AAAD+AAAA/gCGt/0AvP/" "/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Atv" "r/ALr//gAoNv0AAAD+AAAA/gAAAP8AAAAeAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAC9AAAA/wAAAP4AAAD+AEFY/QC6/f4At/z/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/" "8At/v/ALf7/wC2+v8Aw///AICv/gAEBv0AAAH+AAAA/QAAAP8AAAAiAAAAAQAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIMAAAD/AAAA/gAAAP4AAAD9AFl3/QCt7/4AwP//ALj9/w" "C2+/8At/v/ALf7/wC3+/8At/v/ALz//wDB//4AeKP+ABki/QAAAP4AAAD+AAAA/wAAAOEAAAASAAAAA" "QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAOUAAAD/AA" "AA/gAAAP4AAAD+ABcg/QBQbv0AbJD9AH2s/gCBsP0Ac5v+AFt6/QAtPv0AAAD9AAAA/gAAAP4AAAD+A" "AAA/wAAAIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAWgAAAOIAAAD/AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AA" "AD+AAAA/gAAAP8AAAD/AAAAmQAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAIgAAADRAAAA/wAAA" "P8AAAD/AAAA/wAAAP8AAAD/AAAA5QAAAJoAAABWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAIAAAACQAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///gAf///////4AAAAD/////wAAAAP////" "/AAAAB/////+AAAAH/////4AAAA//////gAAAD/////8AAAAH/////wAAAAP////+AAAAA/////4AAA" "AD/////gAAAAP////+AAAAA/////4AAAAD/////gAAAAP////+AAAAA/////4AAAAB/////gAAAAD//" "//+AAAAAP////wAAAAA////+AAAAAD////wAAAAAP///8AAAAAA////gAAAAAB///8AAAAAAH///gAA" "AAAAf//+AAAAAAA///4AAAAAAD///4AAAAAAP///wAAAAAAf///wAAAAAD////gAAAAAP////gAAAAB" "/////AAAAAP////+AAAAD/////wAAAAf////+AAAAB/////4AAAAD/////AAAAAP////8AAAAA/////" "wAAAAB////+AAAAAH////4AAAAAf////gAAAAA////+AAAAAD////4AAAAAP////gAAAAA////+AAAA" "AD////4AAAAAf////gAAAAB////+AAAAAH////8AAAAAf////wAAAAD/////gAAAAP////+AAAAB///" "//8AAAAH/////wAAAA//////gAAAH//////AAAA//////+AAAH//////+AAA///////+AAP///////+" "AH//////////////8="; const char HTTP_COMMAND_TUNNELS[] = "tunnels"; const char HTTP_COMMAND_TRANSIT_TUNNELS[] = "transit_tunnels"; const char HTTP_COMMAND_TRANSPORTS[] = "transports"; const char HTTP_COMMAND_START_ACCEPTING_TUNNELS[] = "start_accepting_tunnels"; const char HTTP_COMMAND_STOP_ACCEPTING_TUNNELS[] = "stop_accepting_tunnels"; const char HTTP_COMMAND_LOCAL_DESTINATIONS[] = "local_destinations"; const char HTTP_COMMAND_LOCAL_DESTINATION[] = "local_destination"; const char HTTP_PARAM_BASE32_ADDRESS[] = "b32"; const char HTTP_COMMAND_SAM_SESSIONS[] = "sam_sessions"; const char HTTP_COMMAND_SAM_SESSION[] = "sam_session"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; namespace misc_strings { const char name_value_separator[] = { ':', ' ' }; const char crlf[] = { '\r', '\n' }; } // namespace misc_strings std::vector HTTPConnection::reply::to_buffers(int status) { std::vector buffers; if (headers.size () > 0) { switch (status) { case 105: buffers.push_back(boost::asio::buffer("HTTP/1.1 105 Name Not Resolved\r\n")); break; case 200: buffers.push_back(boost::asio::buffer("HTTP/1.1 200 OK\r\n")); break; case 400: buffers.push_back(boost::asio::buffer("HTTP/1.1 400 Bad Request\r\n")); break; case 404: buffers.push_back(boost::asio::buffer("HTTP/1.1 404 Not Found\r\n")); break; case 408: buffers.push_back(boost::asio::buffer("HTTP/1.1 408 Request Timeout\r\n")); break; case 500: buffers.push_back(boost::asio::buffer("HTTP/1.1 500 Internal Server Error\r\n")); break; case 502: buffers.push_back(boost::asio::buffer("HTTP/1.1 502 Bad Gateway\r\n")); break; case 503: buffers.push_back(boost::asio::buffer("HTTP/1.1 503 Not Implemented\r\n")); break; case 504: buffers.push_back(boost::asio::buffer("HTTP/1.1 504 Gateway Timeout\r\n")); break; default: buffers.push_back(boost::asio::buffer("HTTP/1.1 200 OK\r\n")); } for (std::size_t i = 0; i < headers.size(); ++i) { header& h = headers[i]; buffers.push_back(boost::asio::buffer(h.name)); buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator)); buffers.push_back(boost::asio::buffer(h.value)); buffers.push_back(boost::asio::buffer(misc_strings::crlf)); } buffers.push_back(boost::asio::buffer(misc_strings::crlf)); } buffers.push_back(boost::asio::buffer(content)); return buffers; } void HTTPConnection::Terminate () { if (!m_Stream) return; m_Socket->close (); m_Stream->Close (); m_Socket->get_io_service ().post ([=](void) { m_Stream.reset (); m_Stream = nullptr; }); } void HTTPConnection::Receive () { m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), std::bind(&HTTPConnection::HandleReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (!ecode) { if (!m_Stream) // new request { m_Buffer[bytes_transferred] = 0; m_BufferLen = bytes_transferred; RunRequest(); } else // follow-on m_Stream->Send ((uint8_t *)m_Buffer, bytes_transferred); Receive (); } else if (ecode != boost::asio::error::operation_aborted) Terminate (); } void HTTPConnection::RunRequest () { auto address = ExtractAddress (); if (address.length () > 1 && address[1] != '?') // not just '/' or '/?' { std::string uri ("/"), b32; size_t pos = address.find ('/', 1); if (pos == std::string::npos) b32 = address.substr (1); // excluding leading '/' to end of line else { b32 = address.substr (1, pos - 1); // excluding leading '/' to next '/' uri = address.substr (pos); // rest of line } HandleDestinationRequest (b32, uri); } else HandleRequest (address); } std::string HTTPConnection::ExtractAddress () { char * get = strstr (m_Buffer, "GET"); if (get) { char * http = strstr (get, "HTTP"); if (http) return std::string (get + 4, http - get - 5); } return ""; } void HTTPConnection::ExtractParams (const std::string& str, std::map& params) { if (str[0] != '&') return; size_t pos = 1, end; do { end = str.find ('&', pos); std::string param = str.substr (pos, end - pos); LogPrint (param); size_t e = param.find ('='); if (e != std::string::npos) params[param.substr(0, e)] = param.substr(e+1); pos = end + 1; } while (end != std::string::npos); } void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) { boost::system::error_code ignored_ec; m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); Terminate (); } } void HTTPConnection::HandleWrite (const boost::system::error_code& ecode) { if (ecode || (m_Stream && !m_Stream->IsOpen ())) { if (ecode != boost::asio::error::operation_aborted) Terminate (); } else // data keeps coming AsyncStreamReceive (); } void HTTPConnection::HandleRequest (const std::string& address) { std::stringstream s; // Html5 head start s << "\n"; // TODO: Add support for locale. s << ""; // TODO: Find something to parse html/template system. This is horrible. s << "Purple I2P " << VERSION " Webconsole"; // Head end if (address.length () > 1) HandleCommand (address.substr (2), s); else FillContent (s); s << ""; SendReply (s.str ()); } void HTTPConnection::FillContent (std::stringstream& s) { s << "

Welcome to the Webconsole!


"; s << "Uptime: " << boost::posix_time::to_simple_string ( boost::posix_time::time_duration (boost::posix_time::seconds ( i2p::context.GetUptime ()))) << "
"; s << "Status: "; switch (i2p::context.GetStatus ()) { case eRouterStatusOK: s << "OK"; break; case eRouterStatusTesting: s << "Testing"; break; case eRouterStatusFirewalled: s << "Firewalled"; break; default: s << "Unknown"; } s << "
"; s << "Tunnel creation success rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%
"; s << "Received: " << i2p::transport::transports.GetTotalReceivedBytes ()/1000 << "K"; s << " (" << i2p::transport::transports.GetInBandwidth () <<" Bps)
"; s << "Sent: " << i2p::transport::transports.GetTotalSentBytes ()/1000 << "K"; s << " (" << i2p::transport::transports.GetOutBandwidth () <<" Bps)
"; s << "Data path: " << i2p::util::filesystem::GetDataDir().string() << "

"; s << "Our external address:" << "
" ; for (auto& address : i2p::context.GetRouterInfo().GetAddresses()) { switch (address.transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: if (address.host.is_v6 ()) s << "NTCP6  "; else s << "NTCP  "; break; case i2p::data::RouterInfo::eTransportSSU: if (address.host.is_v6 ()) s << "SSU6     "; else s << "SSU     "; break; default: s << "Unknown  "; } s << address.host.to_string() << ":" << address.port << "
"; } s << "
Routers: " << i2p::data::netdb.GetNumRouters () << " "; s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " "; s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "
"; s << "
Local destinations"; s << "
Tunnels"; s << "
Transit tunnels"; s << "
Transports"; if (i2p::client::context.GetSAMBridge ()) s << "
SAM sessions"; s << "
"; if (i2p::context.AcceptsTunnels ()) s << "
Stop accepting tunnels
"; else s << "
Start accepting tunnels
"; s << "

Flibusta

"; } void HTTPConnection::HandleCommand (const std::string& command, std::stringstream& s) { size_t paramsPos = command.find('&'); std::string cmd = command.substr (0, paramsPos); if (cmd == HTTP_COMMAND_TRANSPORTS) ShowTransports (s); else if (cmd == HTTP_COMMAND_TUNNELS) ShowTunnels (s); else if (cmd == HTTP_COMMAND_TRANSIT_TUNNELS) ShowTransitTunnels (s); else if (cmd == HTTP_COMMAND_START_ACCEPTING_TUNNELS) StartAcceptingTunnels (s); else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS) StopAcceptingTunnels (s); else if (cmd == HTTP_COMMAND_LOCAL_DESTINATIONS) ShowLocalDestinations (s); else if (cmd == HTTP_COMMAND_LOCAL_DESTINATION) { std::map params; ExtractParams (command.substr (paramsPos), params); auto b32 = params[HTTP_PARAM_BASE32_ADDRESS]; ShowLocalDestination (b32, s); } else if (cmd == HTTP_COMMAND_SAM_SESSIONS) ShowSAMSessions (s); else if (cmd == HTTP_COMMAND_SAM_SESSION) { std::map params; ExtractParams (command.substr (paramsPos), params); auto id = params[HTTP_PARAM_SAM_SESSION_ID]; ShowSAMSession (id, s); } } void HTTPConnection::ShowTransports (std::stringstream& s) { auto ntcpServer = i2p::transport::transports.GetNTCPServer (); if (ntcpServer) { s << "NTCP
"; for (auto it: ntcpServer->GetNTCPSessions ()) { if (it.second && it.second->IsEstablished ()) { // incoming connection doesn't have remote RI auto outgoing = it.second->GetRemoteRouter (); if (outgoing) s << "-->"; s << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase64 ().substr (0, 4) << ": " << it.second->GetSocket ().remote_endpoint().address ().to_string (); if (!outgoing) s << "-->"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << "
"; } s << std::endl; } } auto ssuServer = i2p::transport::transports.GetSSUServer (); if (ssuServer) { s << "
SSU
"; for (auto it: ssuServer->GetSessions ()) { // incoming connections don't have remote router auto outgoing = it.second->GetRemoteRouter (); auto endpoint = it.second->GetRemoteEndpoint (); if (outgoing) s << "-->"; s << endpoint.address ().to_string () << ":" << endpoint.port (); if (!outgoing) s << "-->"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; if (it.second->GetRelayTag ()) s << " [itag:" << it.second->GetRelayTag () << "]"; s << "
"; s << std::endl; } } } void HTTPConnection::ShowTunnels (std::stringstream& s) { s << "Queue size:" << i2p::tunnel::tunnels.GetQueueSize () << "
"; for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ()) { it->GetTunnelConfig ()->Print (s); auto state = it->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) s << " " << "Failed"; else if (state == i2p::tunnel::eTunnelStateExpiring) s << " " << "Exp"; s << " " << (int)it->GetNumSentBytes () << "
"; s << std::endl; } for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ()) { it.second->GetTunnelConfig ()->Print (s); auto state = it.second->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) s << " " << "Failed"; else if (state == i2p::tunnel::eTunnelStateExpiring) s << " " << "Exp"; s << " " << (int)it.second->GetNumReceivedBytes () << "
"; s << std::endl; } } void HTTPConnection::ShowTransitTunnels (std::stringstream& s) { for (auto it: i2p::tunnel::tunnels.GetTransitTunnels ()) { if (dynamic_cast(it.second)) s << it.second->GetTunnelID () << "-->"; else if (dynamic_cast(it.second)) s << "-->" << it.second->GetTunnelID (); else s << "-->" << it.second->GetTunnelID () << "-->"; s << " " << it.second->GetNumTransmittedBytes () << "
"; } } void HTTPConnection::ShowLocalDestinations (std::stringstream& s) { for (auto& it: i2p::client::context.GetDestinations ()) { auto ident = it.second->GetIdentHash ();; s << ""; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
" << std::endl; } } void HTTPConnection::ShowLocalDestination (const std::string& b32, std::stringstream& s) { i2p::data::IdentHash ident; ident.FromBase32 (b32); auto dest = i2p::client::context.FindLocalDestination (ident); if (dest) { s << "Base64:
" << dest->GetIdentity ().ToBase64 () << "

"; s << "LeaseSets: " << dest->GetNumRemoteLeaseSets () << "
"; auto pool = dest->GetTunnelPool (); if (pool) { s << "Tunnels:
"; for (auto it: pool->GetOutboundTunnels ()) { it->GetTunnelConfig ()->Print (s); auto state = it->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) s << " " << "Failed"; else if (state == i2p::tunnel::eTunnelStateExpiring) s << " " << "Exp"; s << "
" << std::endl; } for (auto it: pool->GetInboundTunnels ()) { it->GetTunnelConfig ()->Print (s); auto state = it->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) s << " " << "Failed"; else if (state == i2p::tunnel::eTunnelStateExpiring) s << " " << "Exp"; s << "
" << std::endl; } } s << "
Streams:
"; for (auto it: dest->GetStreamingDestination ()->GetStreams ()) { s << it.first << "->" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetRemoteIdentity ()) << " "; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << " [out:" << it.second->GetSendQueueSize () << "][in:" << it.second->GetReceiveQueueSize () << "]"; s << "[buf:" << it.second->GetSendBufferSize () << "]"; s << "[RTT:" << it.second->GetRTT () << "]"; s << "[Window:" << it.second->GetWindowSize () << "]"; s << "[Status:" << (int)it.second->GetStatus () << "]"; s << "
"<< std::endl; } } } void HTTPConnection::ShowSAMSessions (std::stringstream& s) { auto sam = i2p::client::context.GetSAMBridge (); if (sam) { for (auto& it: sam->GetSessions ()) { s << ""; s << it.first << "
" << std::endl; } } } void HTTPConnection::ShowSAMSession (const std::string& id, std::stringstream& s) { auto sam = i2p::client::context.GetSAMBridge (); if (sam) { auto session = sam->FindSession (id); if (session) { auto& ident = session->localDestination->GetIdentHash(); s << ""; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
" << std::endl; s << "Streams:
"; for (auto it: session->sockets) { switch (it->GetSocketType ()) { case i2p::client::eSAMSocketTypeSession: s << "session"; break; case i2p::client::eSAMSocketTypeStream: s << "stream"; break; case i2p::client::eSAMSocketTypeAcceptor: s << "acceptor"; break; default: s << "unknown"; } s << " [" << it->GetSocket ().remote_endpoint() << "]"; s << "
" << std::endl; } } } } void HTTPConnection::StartAcceptingTunnels (std::stringstream& s) { i2p::context.SetAcceptsTunnels (true); s << "Accepting tunnels started" << std::endl; } void HTTPConnection::StopAcceptingTunnels (std::stringstream& s) { i2p::context.SetAcceptsTunnels (false); s << "Accepting tunnels stopped" << std::endl; } void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri) { std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n"; LogPrint("HTTP Client Request: ", request); SendToAddress (address, 80, request.c_str (), request.size ()); } void HTTPConnection::SendToAddress (const std::string& address, int port, const char * buf, size_t len) { i2p::data::IdentHash destination; if (!i2p::client::context.GetAddressBook ().GetIdentHash (address, destination)) { LogPrint ("Unknown address ", address); SendReply ("" + itoopieImage + "
Unknown address " + address + "", 404); return; } auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination); if (leaseSet && leaseSet->HasNonExpiredLeases ()) SendToDestination (leaseSet, port, buf, len); else { memcpy (m_Buffer, buf, len); m_BufferLen = len; i2p::client::context.GetSharedLocalDestination ()->RequestDestination (destination); m_Timer.expires_from_now (boost::posix_time::seconds(HTTP_DESTINATION_REQUEST_TIMEOUT)); m_Timer.async_wait (std::bind (&HTTPConnection::HandleDestinationRequestTimeout, shared_from_this (), std::placeholders::_1, destination, port, m_Buffer, m_BufferLen)); } } void HTTPConnection::HandleDestinationRequestTimeout (const boost::system::error_code& ecode, i2p::data::IdentHash destination, int port, const char * buf, size_t len) { if (ecode != boost::asio::error::operation_aborted) { auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination); if (leaseSet && leaseSet->HasNonExpiredLeases ()) SendToDestination (leaseSet, port, buf, len); else // still no LeaseSet SendReply (leaseSet ? "" + itoopieImage + "
Leases expired" : "" + itoopieImage + "LeaseSet not found", 504); } } void HTTPConnection::SendToDestination (std::shared_ptr remote, int port, const char * buf, size_t len) { if (!m_Stream) m_Stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (remote, port); if (m_Stream) { m_Stream->Send ((uint8_t *)buf, len); AsyncStreamReceive (); } } void HTTPConnection::AsyncStreamReceive () { if (m_Stream) m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192), std::bind (&HTTPConnection::HandleStreamReceive, shared_from_this (), std::placeholders::_1, std::placeholders::_2), 45); // 45 seconds timeout } void HTTPConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (!ecode) { boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), std::bind (&HTTPConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); } else { if (ecode == boost::asio::error::timed_out) SendReply ("" + itoopieImage + "
Not responding", 504); else if (ecode != boost::asio::error::operation_aborted) Terminate (); } } void HTTPConnection::SendReply (const std::string& content, int status) { m_Reply.content = content; m_Reply.headers.resize(2); m_Reply.headers[0].name = "Content-Length"; m_Reply.headers[0].value = boost::lexical_cast(m_Reply.content.size()); m_Reply.headers[1].name = "Content-Type"; m_Reply.headers[1].value = "text/html"; boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status), std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1)); } HTTPServer::HTTPServer (const std::string& address, int port): m_Thread (nullptr), m_Work (m_Service), m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)), m_NewSocket (nullptr) { } HTTPServer::~HTTPServer () { Stop (); } void HTTPServer::Start () { m_Thread = new std::thread (std::bind (&HTTPServer::Run, this)); m_Acceptor.listen (); Accept (); } void HTTPServer::Stop () { m_Acceptor.close(); m_Service.stop (); if (m_Thread) { m_Thread->join (); delete m_Thread; m_Thread = nullptr; } } void HTTPServer::Run () { m_Service.run (); } void HTTPServer::Accept () { m_NewSocket = new boost::asio::ip::tcp::socket (m_Service); m_Acceptor.async_accept (*m_NewSocket, boost::bind (&HTTPServer::HandleAccept, this, boost::asio::placeholders::error)); } void HTTPServer::HandleAccept(const boost::system::error_code& ecode) { if (!ecode) { CreateConnection(m_NewSocket); Accept (); } } void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket) { auto conn = std::make_shared (m_NewSocket); conn->Receive (); } } }