public void DeserializeCSV(String input)
        {
            StreamReader data    = new StreamReader(input);
            String       version = data.ReadLine();

            if (version == Constants.Version1509 ||
                version == Constants.Version1510)
            {
                // Skip over the headers
                data.ReadLine();

                var consoleData = new PerConsoleData();
                m_perConsoleData.Add("Console", consoleData);

                while (!data.EndOfStream)
                {
                    String          row  = data.ReadLine();
                    ServiceCallItem item = ServiceCallItem.FromCSV1509(row);
                    item.m_logVersion = version;
                    if (item != null)
                    {
                        if (!consoleData.m_servicesHistory.ContainsKey(item.m_host))
                        {
                            consoleData.m_servicesHistory.Add(item.m_host, new LinkedList <ServiceCallItem>());
                        }
                        consoleData.m_servicesHistory[item.m_host].AddLast(item);
                    }
                }

                foreach (var endpoint in consoleData.m_servicesHistory)
                {
                    consoleData.m_servicesStats.Add(endpoint.Key, new ServiceCallStats(endpoint.Value));
                }
            }
        }
        public void DeserializeJson(String input)
        {
            String data = File.ReadAllText(input);

            data = "{\"Data\":" + data + "}";
            XmlDocument doc = JsonConvert.DeserializeXmlNode(data, "Root");

            var consoleData = new PerConsoleData();

            m_perConsoleData.Add("Console", consoleData);

            //gather data from every endpoint
            foreach (XmlNode endpointNode in doc.FirstChild.ChildNodes)
            {
                String endpointName = endpointNode.FirstChild.InnerText;

                for (int j = 1; j < endpointNode.ChildNodes.Count; ++j)
                {
                    XmlNode         itemNode = endpointNode.ChildNodes[j];
                    ServiceCallItem item     = ServiceCallItem.FromJson(itemNode);
                    item.m_host = endpointName;
                    if (!consoleData.m_servicesHistory.ContainsKey(item.m_host))
                    {
                        consoleData.m_servicesHistory.Add(item.m_host, new LinkedList <ServiceCallItem>());
                    }
                    consoleData.m_servicesHistory[item.m_host].AddLast(item);
                }
            }

            foreach (var endpoint in consoleData.m_servicesHistory)
            {
                consoleData.m_servicesStats.Add(endpoint.Key, new ServiceCallStats(endpoint.Value));
            }
        }
 public static bool IsAnalyzedService(ServiceCallItem frame, String customUserAgent)
 {
     return((frame.m_reqHeader.Contains("x-xbl-api-build-version:") && !frame.m_reqHeader.Contains("x-xbl-api-build-version: adk")) ||
            (frame.m_reqHeader.Contains("User-Agent: XboxServicesAPI") && !frame.m_reqHeader.Contains("x-xbl-client-name")) ||
            frame.m_reqHeader.Contains("X-XBL-Build-Version") || // XCE CS1.0 event
            frame.m_reqHeader.Contains("X-AuthXToken") || // UTC upload CS2.1 events
            (!String.IsNullOrEmpty(customUserAgent) && frame.m_reqHeader.Contains($"User-Agent: {customUserAgent}")));
 }
        // Helper method to add a violation with a single call
        public void AddViolation(ViolationLevel level, String description, ServiceCallItem call)
        {
            Violation v = new Violation();

            v.m_level    = level;
            v.m_endpoint = Endpoint;
            v.m_summary  = description;
            v.m_violatingCalls.Add(call);
            Violations.Add(v);
        }
Example #5
0
        private void GatherFirstOrderStats(ServiceCallItem item)
        {
            // Ignore shoulder taps
            if (item.m_isShoulderTap)
            {
                return;
            }

            UInt64 n = m_numCalls;

            UInt64 avg = m_avgElapsedCallTimeMs;

            avg  = n * avg + item.m_elapsedCallTimeMs;
            avg /= (n + 1);

            //update values
            m_avgElapsedCallTimeMs = avg;

            //track skipped calls
            if (item.m_reqTimeUTC < m_lastReqTimeUTC)
            {
                ++m_numSkippedCalls;
            }

            //m_avgTimeBetweenReqsMs
            if (m_lastReqTimeUTC != 0 && item.m_reqTimeUTC >= m_lastReqTimeUTC)
            {
                UInt64 avgTime = m_avgTimeBetweenReqsMs;
                avgTime  = n * avgTime + (item.m_reqTimeUTC - m_lastReqTimeUTC) / TimeSpan.TicksPerMillisecond;
                avgTime /= (n + 1);
                m_avgTimeBetweenReqsMs = avgTime;
            }

            //update last call time
            m_lastReqTimeUTC = item.m_reqTimeUTC;

            //increment num calls for next time
            ++m_numCalls;

            // Update m_maxElapsedCallTimeMs if applicable
            if (item.m_elapsedCallTimeMs > m_maxElapsedCallTimeMs)
            {
                m_maxElapsedCallTimeMs = item.m_elapsedCallTimeMs;
            }

            // m_reqBodyHashCountMap
            if (!m_reqBodyHashCountMap.ContainsKey(item.m_reqBodyHash))
            {
                m_reqBodyHashCountMap.Add(item.m_reqBodyHash, 1);
            }
            else
            {
                ++m_reqBodyHashCountMap[item.m_reqBodyHash];
            }
        }
        public static ServiceCallItem FromCSV1509(String row)
        {
            ServiceCallItem item = new ServiceCallItem();

            String[] values = Utils.GetCSVValues(row);
            try
            {
                item.m_host       = values[(UInt32)CSVValueIndex.Host];
                item.m_uri        = values[(UInt32)CSVValueIndex.Uri];
                item.m_xboxUserId = values[(UInt32)CSVValueIndex.XboxUserId];
                item.m_multiplayerCorrelationId = values[(UInt32)CSVValueIndex.MultiplayerCorrelationId];
                item.m_reqHeader   = values[(UInt32)CSVValueIndex.RequestHeader];
                item.m_reqBody     = values[(UInt32)CSVValueIndex.RequestBody];
                item.m_reqBodyHash = (ulong)item.m_reqBody.GetHashCode();
                item.m_rspHeader   = values[(UInt32)CSVValueIndex.ResponseHeader];
                item.m_rspBody     = values[(UInt32)CSVValueIndex.ResponseBody];
                UInt32.TryParse(values[(UInt32)CSVValueIndex.HttpStatusCode], out item.m_httpStatusCode);
                UInt64.TryParse(values[(UInt32)CSVValueIndex.ElapsedCallTime], out item.m_elapsedCallTimeMs);

                DateTime reqTime;
                bool     valid = DateTime.TryParse(values[(UInt32)CSVValueIndex.RequestTime], null, System.Globalization.DateTimeStyles.RoundtripKind, out reqTime);
                if (valid)
                {
                    item.m_reqTimeUTC = (UInt64)reqTime.ToFileTimeUtc();
                }

                bool.TryParse(values[(UInt32)CSVValueIndex.IsGet], out item.m_isGet);
                UInt32.TryParse(values[(UInt32)CSVValueIndex.Id], out item.m_id);
                bool.TryParse(values[(UInt32)CSVValueIndex.IsShoulderTap], out item.m_isShoulderTap);
                UInt64.TryParse(values[(UInt32)CSVValueIndex.ChangeNumber], out item.m_changeNumber);
                item.m_sessionReferenceUriPath = values[(UInt32)CSVValueIndex.SessionReferenceUriPath];
                bool.TryParse(values[(UInt32)CSVValueIndex.IsInGameEvent], out item.m_isInGameEvent);
                item.m_eventName       = values[(UInt32)CSVValueIndex.EventName];
                item.m_playerSessionId = values[(UInt32)CSVValueIndex.PlayerSessionId];
                UInt16.TryParse(values[(UInt32)CSVValueIndex.EventVersion], out item.m_version);
                item.m_dimensions   = values[(UInt32)CSVValueIndex.Dimensions];
                item.m_measurements = values[(UInt32)CSVValueIndex.Measurements];
                item.m_breadCrumb   = values[(UInt32)CSVValueIndex.BreadCrumb];
            }
            catch (Exception)
            {
                Console.WriteLine("Error Parsing a CSV Item.");
                return(null);
            }

            return(item);
        }
Example #7
0
        private void GatherSecondOrderStats(ServiceCallItem item)
        {
            // Ignore shoulder taps
            if (item.m_isShoulderTap)
            {
                return;
            }

            //
            // Calculate variance
            //
            // Var[n+1] = ( n * Var[n] + ( x[n+1] - Avg ) ^ 2 ) / ( n + 1)
            //
            UInt64 avg = m_avgElapsedCallTimeMs;
            UInt64 n   = m_numCalls;

            // m_varElapsedCallTimeMs
            UInt64 var = m_varElapsedCallTimeMs;
            UInt64 dev = item.m_elapsedCallTimeMs - avg;

            var  = n * var + dev * dev;
            var /= (n + 1);

            //m_varTimeBetweenReqsMs
            if (m_lastReqTimeUTC != 0 && item.m_reqTimeUTC >= m_lastReqTimeUTC)
            {
                UInt64 localVar = m_varTimeBetweenReqsMs;
                UInt64 localDev = (item.m_reqTimeUTC - m_lastReqTimeUTC) / TimeSpan.TicksPerMillisecond - avg;
                localVar  = n * localVar + localDev * localDev;
                localVar /= (n + 1);
                //update values
                m_varTimeBetweenReqsMs = localVar;
            }

            m_lastReqTimeUTC = item.m_reqTimeUTC;

            // increment m_numCalls for next time
            ++n;

            //update values
            m_numCalls             = n;
            m_varElapsedCallTimeMs = var;
        }
        public ServiceCallItem Copy()
        {
            var copy = new ServiceCallItem();

            copy.m_logVersion = m_logVersion;
            copy.m_host       = m_host;
            copy.m_uri        = m_uri;
            copy.m_xboxUserId = m_xboxUserId;
            copy.m_multiplayerCorrelationId = m_multiplayerCorrelationId;
            copy.m_reqHeader               = m_reqHeader;
            copy.m_reqBody                 = m_reqBody;
            copy.m_rspHeader               = m_rspHeader;
            copy.m_rspBody                 = m_rspBody;
            copy.m_rspFullString           = m_rspFullString;
            copy.m_branch                  = m_branch;
            copy.m_sessionReferenceUriPath = m_sessionReferenceUriPath;
            copy.m_eventName               = m_eventName;
            copy.m_playerSessionId         = m_playerSessionId;
            copy.m_dimensions              = m_dimensions;
            copy.m_measurements            = m_measurements;
            copy.m_breadCrumb              = m_breadCrumb;
            copy.m_xsapiMethods            = m_xsapiMethods;
            copy.m_callDataFromJSON        = m_callDataFromJSON;
            copy.m_consoleIP               = m_consoleIP;
            copy.m_version                 = m_version;
            copy.m_httpStatusCode          = m_httpStatusCode;
            copy.m_reqBodyHash             = m_reqBodyHash;
            copy.m_elapsedCallTimeMs       = m_elapsedCallTimeMs;
            copy.m_reqTimeUTC              = m_reqTimeUTC;
            copy.m_startTimeUTC            = m_startTimeUTC;
            copy.m_changeNumber            = m_changeNumber;
            copy.m_isGet         = m_isGet;
            copy.m_method        = m_method;
            copy.m_isShoulderTap = m_isShoulderTap;
            copy.m_isInGameEvent = m_isInGameEvent;

            return(copy);
        }
        public static ServiceCallItem FromFiddlerFrame(UInt32 frameId, ZipArchiveEntry cFileStream, ZipArchiveEntry mFileStream, ZipArchiveEntry sFileStream, Func <WebHeaderCollection, bool> filterCallback)
        {
            ServiceCallItem frame = new ServiceCallItem();

            frame.m_id = frameId;

            // Read the client part of the frame (###_c.txt)
            using (var cFileMemory = Utils.DecompressToMemory(cFileStream))
            {
                using (var cFile = new BinaryReader(cFileMemory))
                {
                    var fileLine = cFile.ReadLine();

                    var firstLineSplit = fileLine.Split(' ');

                    // CONNECT Frames should not be in the analysis.
                    if (firstLineSplit[0] == "CONNECT")
                    {
                        return(null);
                    }

                    // Fiddler Test Frames can cause LTA to break.  This filters out those fames.
                    if (firstLineSplit[1].StartsWith("http:///", true, null))
                    {
                        return(null);
                    }

                    frame.m_isGet  = firstLineSplit[0].Equals("GET");
                    frame.m_method = firstLineSplit[0];

                    // Extract the XUID (if any) from the first line of the client side of the frame
                    // POST https://userpresence.xboxlive.com/users/xuid(2669321029139235)/devices/current HTTP/1.1
                    frame.m_xboxUserId = Utils.GetXboxUserID(firstLineSplit[1]);

                    // Grab just the url from the line
                    frame.m_uri = firstLineSplit[1];

                    // Read the Request Headers
                    fileLine = cFile.ReadLine();
                    var reqHeaders = new WebHeaderCollection();
                    while (String.IsNullOrWhiteSpace(fileLine) == false)
                    {
                        reqHeaders.Add(fileLine);
                        fileLine = cFile.ReadLine();
                    }

                    // Filter calls with headers
                    if (filterCallback != null && !filterCallback(reqHeaders))
                    {
                        return(null);
                    }

                    frame.m_host = reqHeaders["Host"];

                    // Read the Request Body
                    string contentEncoding = reqHeaders["Content-Encoding"];
                    if (!string.IsNullOrWhiteSpace(contentEncoding) && contentEncoding.Equals("deflate", StringComparison.OrdinalIgnoreCase))
                    {
                        using (var memory = Utils.InflateData(cFile.ReadToEnd()))
                        {
                            using (var data = new BinaryReader(memory))
                            {
                                fileLine = Encoding.ASCII.GetString(data.ReadToEnd());
                            }
                        }
                    }
                    else
                    {
                        fileLine = Encoding.ASCII.GetString(cFile.ReadToEnd());
                    }

                    frame.m_reqHeader   = reqHeaders.ToString();
                    frame.m_reqBody     = fileLine;
                    frame.m_reqBodyHash = (UInt64)frame.m_reqBody.GetHashCode();
                }
            }

            // Read the frame metadata (###_m.xml)
            using (var mFile = new StreamReader(mFileStream.Open()))
            {
                String rawData = mFile.ReadToEnd();
                var    xmldata = System.Xml.Linq.XDocument.Parse(rawData);

                var sessionTimers = xmldata.Element("Session").Element("SessionTimers");
                var reqTime       = DateTime.Parse((String)sessionTimers.Attribute("ClientBeginRequest")).ToUniversalTime();
                frame.m_reqTimeUTC = (UInt64)reqTime.ToFileTimeUtc();

                var endTime = DateTime.Parse((String)sessionTimers.Attribute("ClientDoneResponse")).ToUniversalTime();
                frame.m_elapsedCallTimeMs = (UInt64)(endTime - reqTime).TotalMilliseconds;

                var sessionFlags = xmldata.Element("Session").Element("SessionFlags");

                foreach (var flag in sessionFlags.Descendants())
                {
                    if ((String)flag.Attribute("N") == "x-clientip")
                    {
                        frame.m_consoleIP = (String)flag.Attribute("V");
                        frame.m_consoleIP = frame.m_consoleIP.Substring(frame.m_consoleIP.LastIndexOf(':') + 1);
                        break;
                    }
                }
            }

            //Read the server part of the frame(###_s.txt)
            using (var sFileMemory = Utils.DecompressToMemory(sFileStream))
            {
                using (var sFile = new BinaryReader(sFileMemory))
                {
                    var fileLine = sFile.ReadLine();

                    if (String.IsNullOrEmpty(fileLine) == false)
                    {
                        var statusCodeLine = fileLine.Split(' ');

                        frame.m_httpStatusCode = UInt32.Parse(statusCodeLine[1]);
                    }

                    // Read the Response Headers
                    var headers = new WebHeaderCollection();
                    fileLine = sFile.ReadLine();
                    while (!String.IsNullOrWhiteSpace(fileLine))
                    {
                        headers.Add(fileLine);
                        fileLine = sFile.ReadLine();
                    }

                    // Read the Response Body
                    string contentEncoding = headers["Content-Encoding"];
                    if (!string.IsNullOrWhiteSpace(contentEncoding) && contentEncoding.Equals("deflate", StringComparison.OrdinalIgnoreCase))
                    {
                        using (var memory = Utils.InflateData(sFile.ReadToEnd()))
                        {
                            using (var data = new BinaryReader(memory))
                            {
                                fileLine = Encoding.ASCII.GetString(data.ReadToEnd());
                            }
                        }
                    }
                    else
                    {
                        fileLine = Encoding.ASCII.GetString(sFile.ReadToEnd());
                    }

                    frame.m_rspHeader = headers.ToString();

                    // Read the Response Body
                    frame.m_rspBody = fileLine;
                }
            }

            return(frame);
        }
        public static ServiceCallItem FromJson(XmlNode serviceCallNode)
        {
            ServiceCallItem item = new ServiceCallItem();

            foreach (XmlNode propertyNode in serviceCallNode.ChildNodes)
            {
                try
                {
                    //check for each service call property
                    if (propertyNode.Name == "Uri")
                    {
                        item.m_uri = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "Host")
                    {
                        item.m_host = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "XboxUserId")
                    {
                        item.m_xboxUserId = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "MultiplayerCorrelationId")
                    {
                        item.m_multiplayerCorrelationId = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "RequestHeaders")
                    {
                        item.m_reqHeader = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "RequestBody")
                    {
                        item.m_reqBody     = propertyNode.InnerText;
                        item.m_reqBodyHash = (ulong)item.m_reqBody.GetHashCode();
                    }
                    else if (propertyNode.Name == "ResponseHeaders")
                    {
                        item.m_rspHeader = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "ResponseBody")
                    {
                        item.m_rspBody = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "FullResponse")
                    {
                        item.m_rspFullString = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "HttpStatusCode")
                    {
                        UInt32.TryParse(propertyNode.InnerText, out item.m_httpStatusCode);
                    }
                    else if (propertyNode.Name == "RequestBodyHashCode")
                    {
                        UInt64.TryParse(propertyNode.InnerText, out item.m_reqBodyHash);
                    }
                    else if (propertyNode.Name == "ElapsedCallTimeMs")
                    {
                        UInt64.TryParse(propertyNode.InnerText, out item.m_elapsedCallTimeMs);
                    }
                    else if (propertyNode.Name == "ReqTimeUTC")
                    {
                        double reqTimeUTC;
                        bool   valid = double.TryParse(propertyNode.InnerText, out reqTimeUTC);
                        if (valid)
                        {
                            item.m_reqTimeUTC = (UInt64)BitConverter.DoubleToInt64Bits(reqTimeUTC);
                        }
                    }
                    else if (propertyNode.Name == "StartTimeUTC")
                    {
                        double startTimeUTC;
                        bool   valid = double.TryParse(propertyNode.InnerText, out startTimeUTC);
                        if (valid)
                        {
                            item.m_startTimeUTC = (UInt64)BitConverter.DoubleToInt64Bits(startTimeUTC);
                        }
                    }
                    else if (propertyNode.Name == "IsGet")
                    {
                        bool.TryParse(propertyNode.InnerText, out item.m_isGet);
                    }
                    else if (propertyNode.Name == "Id")
                    {
                        UInt32.TryParse(propertyNode.InnerText, out item.m_id);
                    }
                    else if (propertyNode.Name == "IsShoulderTap")
                    {
                        bool.TryParse(propertyNode.InnerText, out item.m_isShoulderTap);
                    }
                    else if (propertyNode.Name == "ChangeNumber")
                    {
                        UInt64.TryParse(propertyNode.InnerText, out item.m_changeNumber);
                    }
                    else if (propertyNode.Name == "Branch")
                    {
                        item.m_branch = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "SessionReferenceUriPath")
                    {
                        item.m_sessionReferenceUriPath = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "IsInGameEvent")
                    {
                        bool.TryParse(propertyNode.InnerText, out item.m_isInGameEvent);
                    }
                    else if (propertyNode.Name == "EventName")
                    {
                        item.m_eventName = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "EventPlayerSessionId")
                    {
                        item.m_playerSessionId = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "EventVersion")
                    {
                        UInt16.TryParse(propertyNode.InnerText, out item.m_version);
                    }
                    else if (propertyNode.Name == "EventDimensionsData")
                    {
                        item.m_dimensions = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "EventMeasurementsData")
                    {
                        item.m_measurements = propertyNode.InnerText;
                    }
                    else if (propertyNode.Name == "BreadCrumb")
                    {
                        item.m_breadCrumb = propertyNode.InnerText;
                    }
                }
                catch (ArgumentException)
                {
                }
            }

            return(item);
        }
        private void ConvertCS1ToEvent(Dictionary <string, LinkedList <ServiceCallItem> > servicesHistory)
        {
            var events = servicesHistory["data-vef.xboxlive.com"];

            servicesHistory.Remove("data-vef.xboxlive.com");

            LinkedList <ServiceCallItem> inGameEvents = null;

            if (servicesHistory.ContainsKey("inGameEvents"))
            {
                inGameEvents = servicesHistory["inGameEvents"];
            }
            else
            {
                inGameEvents = new LinkedList <ServiceCallItem>();
                servicesHistory.Add("inGameEvents", inGameEvents);
            }

            // Event Name starts with a string in the form of {Publisher}_{TitleId}
            Regex eventNameMatch = new Regex("[a-zA-z]{4}_[a-zA-Z0-9]{8}");

            foreach (var eventCall in events)
            {
                var requestBody = eventCall.m_reqBody;

                var eventArray = requestBody.Split(Environment.NewLine.ToCharArray());

                foreach (var eventLine in eventArray)
                {
                    var fields = eventLine.Split('|');

                    if (fields.Length < 12)
                    {
                        // This event is not valid as it is missing fields
                        continue;
                    }

                    // The name field is in the form of {Publisher}_{TitleId}.{EventName}
                    var eventNameParts = fields[1].Split('.');

                    if (eventNameParts.Length > 1 && eventNameMatch.IsMatch(eventNameParts[0]))
                    {
                        ServiceCallItem splitEvent = eventCall.Copy();

                        splitEvent.m_host          = "inGameEvents";
                        splitEvent.m_eventName     = eventNameParts[1];
                        splitEvent.m_reqTimeUTC    = (UInt64)DateTime.Parse(fields[2]).ToFileTimeUtc();
                        splitEvent.m_reqBody       = String.Empty;
                        splitEvent.m_dimensions    = CS1PartBC(fields);
                        splitEvent.m_isInGameEvent = true;

                        if (splitEvent.m_eventName.Contains("MultiplayerRoundStart") || splitEvent.m_eventName.Contains("MultiplayerRoundEnd"))
                        {
                            splitEvent.m_playerSessionId          = fields[15];
                            splitEvent.m_multiplayerCorrelationId = fields[16];
                        }

                        inGameEvents.AddLast(splitEvent);
                    }
                }
            }
        }
        public void DeserializeFiddlerTrace(String filePath, String customAgent)
        {
            // Open the SAZ
            var archive = System.IO.Compression.ZipFile.Open(filePath, ZipArchiveMode.Read);

            // Group the archive entries by frame number
            var result = from e in archive.Entries
                         where e.Name.Contains("_c.txt") || e.Name.Contains("_s.txt") || e.Name.Contains("_m.xml")
                         group e by Utils.GetFrameNumber(e.Name) into g
                         select new { Frame = g.Key, Data = g };

            m_dataTelemetry.m_totalCalls = result.Count();

            List <ServiceCallItem> frameData = new List <ServiceCallItem>();

            int frameNumber = 1;

            // Process data per frame
            foreach (var group in result)
            {
                // Grab the individual files
                ZipArchiveEntry cFileArchive = group.Data.ElementAt(0);
                ZipArchiveEntry mFileArchive = group.Data.ElementAt(1);
                ZipArchiveEntry sFileArchive = group.Data.ElementAt(2);

                ServiceCallItem frame = null;

                System.Diagnostics.Debug.WriteLine("Analyzing Frame# " + frameNumber);
                frameNumber++;

                frame = ServiceCallItem.FromFiddlerFrame((UInt32)group.Frame, cFileArchive, mFileArchive, sFileArchive, o => m_allEndpoints || Utils.IsAnalyzedService(o, customAgent));

                // If this is not an Xbox Service Endpoint that we are checking, then move along.
                if (frame == null)
                {
                    System.Diagnostics.Debug.WriteLine("Skipping\r\n");
                    continue;
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine("Processing Call\r\n");
                }

                frameData.Add(frame);
                m_dataTelemetry.m_callsProcessed++;
            }

            var consoleGroups = from f in frameData
                                group f by f.m_consoleIP;

            foreach (var consoleFrames in consoleGroups.Where(g => g.Key != String.Empty))
            {
                var consoleData = new PerConsoleData();

                var xboxServiceFrames = consoleFrames.GroupBy(f => f.m_host)
                                        .Select(group => new { Host = group.Key, History = group.AsEnumerable() });

                consoleData.m_servicesHistory = xboxServiceFrames.ToDictionary(g => g.Host, g => new LinkedList <ServiceCallItem>(g.History.OrderBy(call => call.m_reqTimeUTC)));

                // Xbox telemetry endpoint
                if (consoleData.m_servicesHistory.ContainsKey("data-vef.xboxlive.com"))
                {
                    ConvertCS1ToEvent(consoleData.m_servicesHistory);
                }

                // Windows Telemetry endpoint
                if (consoleData.m_servicesHistory.Any(k => k.Key.Contains(".data.microsoft.com")))
                {
                    ConvertCS2ToEvent(consoleData.m_servicesHistory);
                }

                // clear empty items
                consoleData.m_servicesHistory = consoleData.m_servicesHistory.Where(o => o.Value.Count > 0).ToDictionary(x => x.Key, x => x.Value);

                foreach (var endpoint in consoleData.m_servicesHistory)
                {
                    consoleData.m_servicesStats.Add(endpoint.Key, new ServiceCallStats(endpoint.Value));
                }

                m_perConsoleData.Add(consoleFrames.Key, consoleData);
            }
        }
        public static ServiceCallItem FromFiddlerFrame(UInt32 frameId, ZipArchiveEntry cFileStream, ZipArchiveEntry mFileStream, ZipArchiveEntry sFileStream)
        {
            ServiceCallItem frame = new ServiceCallItem();

            frame.m_id = frameId;

            // Read the client part of the frame (###_c.txt)
            using (var cFileMemory = Utils.DecompressToMemory(cFileStream))
            {
                using (var cFile = new BinaryReader(cFileMemory))
                {
                    var fileLine = cFile.ReadLine();

                    var firstLineSplit = fileLine.Split(' ');

                    // CONNECT Frames should not be in the analysis.
                    if (firstLineSplit[0] == "CONNECT")
                    {
                        return(null);
                    }

                    frame.m_isGet = firstLineSplit[0].Equals("GET");

                    // Extract the XUID (if any) from the first line of the client side of the frame
                    // POST https://userpresence.xboxlive.com/users/xuid(2669321029139235)/devices/current HTTP/1.1
                    frame.m_xboxUserId = Utils.GetXboxUserID(firstLineSplit[1]);

                    // Grab just the url from the line
                    frame.m_uri = firstLineSplit[1];

                    // Read the Request Headers
                    fileLine          = cFile.ReadLine();
                    frame.m_reqHeader = String.Empty;
                    while (String.IsNullOrEmpty(fileLine) == false)
                    {
                        frame.m_reqHeader += (fileLine + "\r\n");
                        fileLine           = cFile.ReadLine();
                    }

                    var index = frame.m_reqHeader.IndexOf("Host:");
                    index += 6;

                    var endIndex = frame.m_reqHeader.IndexOf("\r\n", index);

                    frame.m_host = frame.m_reqHeader.Substring(index, endIndex - index);

                    // Read the Request Body
                    if (frame.m_reqHeader.Contains("Content-Encoding: deflate"))
                    {
                        using (var memory = Utils.InflateData(cFile.ReadToEnd()))
                        {
                            using (var data = new BinaryReader(memory))
                            {
                                fileLine = Encoding.ASCII.GetString(data.ReadToEnd());
                            }
                        }
                    }
                    else
                    {
                        fileLine = Encoding.ASCII.GetString(cFile.ReadToEnd());
                    }
                    frame.m_reqBody     = fileLine;
                    frame.m_reqBodyHash = (UInt64)frame.m_reqBody.GetHashCode();
                }
            }

            // Read the frame metadata (###_m.xml)
            using (var mFile = new StreamReader(mFileStream.Open()))
            {
                String rawData = mFile.ReadToEnd();
                var    xmldata = System.Xml.Linq.XDocument.Parse(rawData);

                var sessionTimers = xmldata.Element("Session").Element("SessionTimers");
                var reqTime       = DateTime.Parse((String)sessionTimers.Attribute("ClientBeginRequest")).ToUniversalTime();
                frame.m_reqTimeUTC = (UInt64)reqTime.ToFileTimeUtc();

                var endTime = DateTime.Parse((String)sessionTimers.Attribute("ClientDoneResponse")).ToUniversalTime();
                frame.m_elapsedCallTimeMs = (UInt64)(endTime - reqTime).TotalMilliseconds;

                var sessionFlags = xmldata.Element("Session").Element("SessionFlags");

                foreach (var flag in sessionFlags.Descendants())
                {
                    if ((String)flag.Attribute("N") == "x-clientip")
                    {
                        frame.m_consoleIP = (String)flag.Attribute("V");
                        frame.m_consoleIP = frame.m_consoleIP.Substring(frame.m_consoleIP.LastIndexOf(':') + 1);
                        break;
                    }
                }
            }

            //Read the server part of the frame(###_s.txt)
            using (var sFileMemory = Utils.DecompressToMemory(sFileStream))
            {
                using (var sFile = new BinaryReader(sFileMemory))
                {
                    var fileLine = sFile.ReadLine();

                    if (String.IsNullOrEmpty(fileLine) == false)
                    {
                        var statusCodeLine = fileLine.Split(' ');

                        frame.m_httpStatusCode = UInt32.Parse(statusCodeLine[1]);
                    }

                    // Read the Response Headers
                    fileLine          = sFile.ReadLine();
                    frame.m_rspHeader = String.Empty;
                    while (String.IsNullOrEmpty(fileLine) == false)
                    {
                        frame.m_rspHeader += (fileLine + "\r\n");
                        fileLine           = sFile.ReadLine();
                    }

                    // Read the Response Body
                    if (frame.m_rspHeader.Contains("Content-Encoding: deflate"))
                    {
                        using (var memory = Utils.InflateData(sFile.ReadToEnd()))
                        {
                            using (var data = new BinaryReader(memory))
                            {
                                fileLine = Encoding.ASCII.GetString(data.ReadToEnd());
                            }
                        }
                    }
                    else
                    {
                        fileLine = Encoding.ASCII.GetString(sFile.ReadToEnd());
                    }

                    // Read the Response Body
                    frame.m_rspBody = fileLine;
                }
            }

            return(frame);
        }