/* Copyright (c) Citrix Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Net; using XenAPI; using XenAdmin.ServerDBs.FakeAPI; namespace XenAdmin.ServerDBs { public class SimulatorWebStream : Stream { // might be null private SimulatorWebProxy simProxy; private Uri Url; private long position; private long Start; private bool CycleResponse = true; private string HttpResponse = " \n"; public SimulatorWebStream(Uri url, IWebProxy proxy) { simProxy = proxy as SimulatorWebProxy; Url = url; } public override bool CanRead { get { return true; } } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return true; } } public override void Flush() { } public override long Length { get { return HttpResponse.Length; } } public override long Position { get { return position; } set { position = value; } } public override int Read(byte[] buffer, int offset, int count) { for (int i = offset; i < count; i++) { if (position >= HttpResponse.Length) { if (CycleResponse) position = Start; else { buffer[i] = unchecked((byte)-1); return i - offset; } } buffer[i] = (byte)HttpResponse[(int)position++]; } return count; } public override long Seek(long offset, SeekOrigin origin) { position += offset; return position; } public override void SetLength(long value) { } public override void Write(byte[] buffer, int offset, int count) { StringBuilder builder = new StringBuilder(); for (int i = offset; i < count; i++) builder.Append((char)buffer[i]); ParseHttpHeader(builder.ToString()); } private void ParseHttpHeader(string header) { string[] cmds = header.Split(' '); if (cmds.Length < 1) return; switch (cmds[0]) { case "PUT": case "GET": case "CONNECT": break; default: return; } if (cmds.Length < 2) return; string[] param = cmds[1].Split('?'); if (param.Length < 1) return; Dictionary query = param.Length > 1 ? ParseQuery(param[1]) : new Dictionary(); Position = 0; Start = 0; CycleResponse = false; switch (param[0]) { case "/pool_patch_upload": CycleResponse = true; HttpResponse = "HTTP 200 simulator\n \n"; PoolPatchUpload(query); break; case "/rrd_updates": string host_ref = HostRef(); string uuid = (string)simProxy.proxy.db.GetValue("host", host_ref, "uuid"); HttpResponse = string.Format(@"HTTP 200 simulator 0 5 0 1 1 AVERAGE:host:{0}:cpu0 {1} {2} ", uuid, (long)(new TimeSpan(DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks).TotalSeconds), CpuStatsForHost(host_ref)); break; case "/console": StringBuilder response = GetConsoleResponse(); if (response != null) { CycleResponse = true; Start = response.Length; response.Append(WriteFlag(false)); HttpResponse = response.ToString(); } else { HttpResponse = " \n"; } break; case "/host_backup": HttpResponse = "HTTP 200 simulator\n \n" + header; break; default: //Support for export if (param[0].StartsWith("/%3Fsession_id=")) { HttpResponse = GetVMExportResponse(); } else HttpResponse = " \n"; break; } } protected virtual string GetVMExportResponse() { return null; } protected virtual StringBuilder GetConsoleResponse() { return null; } protected string WriteCard32(int p) { byte[] bytes = BitConverter.GetBytes(p); Array.Reverse(bytes); StringBuilder builder = new StringBuilder(); foreach (byte b in bytes) { builder.Append((char)b); } return builder.ToString(); } protected string WriteCard16(short p) { byte[] bytes = BitConverter.GetBytes(p); Array.Reverse(bytes); StringBuilder builder = new StringBuilder(); foreach (byte b in bytes) { builder.Append((char)b); } return builder.ToString(); } protected string WriteCard8(byte p) { return ((char)p).ToString(); } protected string WriteFlag(bool p) { return p ? ((char)1).ToString() : ((char)0).ToString(); } protected string WriteString(string p) { return string.Format("{0}{1}", WriteCard32(p.Length), p); } private string HostRef() { return simProxy.proxy.db.ObjectWithFieldValue("host", "address", Url.Host); } Random rand = new Random(); private double CpuStatsForHost(string host_ref) { switch (host_ref) { // hack for ExpectedResults search test case "OpaqueRef:d3a48ddc-8261-33df-64b2-1309e98b395d": return rand.Next(0, 49)/100d; case "OpaqueRef:83b5a7dc-4eae-ba93-f9ca-53ef5a664814": return rand.Next(50, 100)/100d; default: return rand.Next(0, 100)/100d; } } private void PoolPatchUpload(Dictionary query) { string task_ref = query["task_id"]; string session_id = query["session_id"]; Proxy_Task task = simProxy.proxy.GetTask(task_ref); Proxy_Pool_patch patch = new Proxy_Pool_patch(); patch.after_apply_guidance = new string[] { "unknown" }; patch.name_label = "fake-patch"; patch.name_description = ""; patch.size = "0"; patch.uuid = Guid.NewGuid().ToString(); patch.version = "1.0"; task.result = new fakePool_Patch(simProxy.proxy).create(session_id, patch).Value; task.finished = DateTime.Now; task.status = "success"; } private Dictionary ParseQuery(string query) { Dictionary dict = new Dictionary(); foreach (string q in query.Split('&')) { string[] var = q.Split('='); dict[var[0]] = var[1]; } return dict; } } }