I’ve been working on removing a COM component from our App-V integration in XenDesktop recently and replacing it with a Windows service. Previously the design needed a out of process COM object which was run under the context of a administrative user. This COM object would interact with the Microsoft App-V API, particularly the parts of the API that required administrative privileges. The COM object responsibilities traditionally was to add App-V packages to the VDA, add/remove publishing server URLs, and recently to create Isolation groups, basically a fledgling implementation of Connection Groups – see 1, 2, 3 . These normally occur when the App-V packages are published in XenDesktop.
One of the problems with this is that the COM object cannot access the network, and this is primarily what moving to a service, which runs under the context of Local System, allows us to now achieve. The COM object is owned by a local administrator account(which is generated randomly on installation). This wasn’t an issue for a long time because for a long time we didn’t need to access the local network. However with the introduction of a new way to manage App-V in XenDesktop called Single Admin, we now need to. With the traditional App-V support for XenDesktop, we would interact with the existing App-V infrastructure/servers and as such just needed to access those and through these servers, much of the integration of these servers into XenDesktop was achieved. One thing you needed to ensure was you had a managed App-V system up and running. That was called Dual-Admin support for App-V and XenDesktop because effectively you needed to administrator two systems – the existing App-V infrastructure and the Citrix integration. With the newer integration model, you don't need the App-V infrastructures to take advantage of deploying App-V packages in XenDesktop. Single Admin allows you to do that by putting you in charge of the App-V packages(which previously was a responsibility of the App-V servers).
So with this, you’ll need to define a location of your App-V packages on your network and we’ll need to access them – something the COM component can’t do without the help of another component which fetches the packages and copies them locally, then the COM component can access them. So we’re doing away with this need to copy the packages locally as its a little stupid to tell you the honest truth: Shared content mode, fault streaming,feature block streaming are effectively impossible to achieve, not to mention the fact that we’re clogging up the space on the VDA by coping these packages locally, before publishing and using them. So all be gone!
So that’s what I’ve been working on, designing a service to manage much of these tasks, it’ll have access to the app-v packages on the network, wont need to copy them down, and should still be able to perform the admin functions that the Microsoft API require, while lifting those serious restrictions currently in place with Single Admin. There is still more stuff to do to make Single Admin as feature rich as Dual admin because its still getting started but this is a step in the right direction. We don't support many things that Dual admin does, such as user/package deployment configuration and a whole bunch of other things, but we’re well on our way.
The implementation requires a communication channel between the App-V Broker VDA plugin and the service, in much the same way it needed one with the COM component – and basically accessing the COM component from the VDA plugin was that. So we’ve implemented a named pipe between the two parts to be that communication channel – so the VDA plugin can ask the service to perform those admin functions when it needs to. Its currently pretty rudimentary but it works. Like the previous implementation this communication channel will be locked down so that only communication can occur between our two components, thereby maximising security because security is important.
I implemented a nice way to stream strings across the named pipe from both sides because like I found in BSD Sockets, you need to tell the server how much data your are going to send and the server needs to read just that much. Same requirement but in the Named pipe implementation, you write to a stream by sending bytes or a group of bytes. If you send the length of your buffer(data to send) in the first byte, what could happen is that the length of your buffer cannot be represented by merely one byte, so you’d find on the server, the buffer overflow would occur because the byte had the number ‘wrap-around’ and be represented as something like –254. So the solution I came up with was cool:
Send the number of bytes it would take to represent the length of the buffer, in one single byte. Then store the length into that number of bytes and send those number of bytes to the server. Then send the entire buffer to the server. On the server, it would get how many bytes it must take off the stream in order to represent the length of the buffer, do that and then interpret those bytes as the actual length of the incoming data and then read that amount.
I say the solution is cool but its really not, I can’t really see any other way to do this without doing some naïve tricks(see below) to store a big number in one byte(like reducing that number on the client and increasing that number again on the server side – eventually your algorithm will blow up in your face somewhere and it will be defeated, say or instance when you’re sending lots of data – buffer overflow!). Here is what I mean by naïve and by naïve I mean I naïvely tried it and it eventually corrupted my test data… :
public string ReadString() { int len = 0; // Here begins a hack that works..until it doesn't: len = ioStream.ReadByte() * 256; len += ioStream.ReadByte(); byte[] inBuffer = new byte[len]; ioStream.Read(inBuffer, 0, len); return streamEncoding.GetString(inBuffer); } public int WriteString(string outString) { byte[] outBuffer = streamEncoding.GetBytes(outString); int len = outBuffer.Length; if (len > UInt16.MaxValue) { len = (int)UInt16.MaxValue; } // Here begins a hack that works..until it doesn't: ioStream.WriteByte((byte)(len / 256)); ioStream.WriteByte((byte)(len & 255)); ioStream.Write(outBuffer, 0, len); ioStream.Flush(); return outBuffer.Length + 2; }
In other news, I’m also working on writing a game engine – really more for the challenge than anything else. I’m finished my foray into the broker pattern so I'm moving on. I’ve got a rudimentary game loop, with a fixed framerate update function with a rendering part which runs as much as possible – two facts you need to start implementing a game. The next steps really are to compute the frame’s contents – what will happen in forming each frame – animation will need to be calculated, AI will need to be processed for that frame, player input will need to be used to adjust stuff and that stuff needs to be reflected in the frame. When all that is done, the rendering part needs to draw everything we’ve done. The tricky and interesting parts is implementing AI, simulating, animating, and efficiently storing and manipulating data in such a small amount of time – one frame.
One thing I’m toying with is writing the game engine in C++, because then I can abstract a lot of stuff and can use the STL library. The other part of me wants to write it in C because its faster and I could use the Glib library or roll my own library into it – stulibc. But then again, C++ is really C with extra bits to make things more complex… I’m particularly looking forward to interfacing with technologies I’ve not worked with before – DirectX, Direct3D, OpenGL and that kind of stuff – I guess particularly around the rendering and animation side of things. Oh and I’ve not even decided what this ‘game’ is going to be – don't know if that's a good thing or not. A game engine needs to be tested and a game tests a game engine. I think it will be a 2D game, very simple and hopefully I can engineer the game engine so its cross platform and relatively platform independent – though I hear the input aspects are hard to implement generically and perhaps this is where C++ comes into its own with abstraction capabilities – not that pure C can achieve the same outcome(but with extra legwork).
That's pretty much the week’s work. Today is Saturday and we’ll continue again on Monday.