New MQTT library

I don’t know if the development world needs another .NET MQTT library, but I wrote one a few years ago and finally decided to dust it off and publish it in source form and as a NuGet package.  I considered doing a PCL version, but then I looked at the source and was reminded that the library heavily uses sockets and threads and figured that’s a bit more work than I feel like putting into it right now.

It’s fully functional and pretty solid. I used it in a production app, so it’s not just an experimental library.

Source code is on GitHub.

Package is in NuGet [id: opennetcf-mqtt]

NuGet Updates across the board

As I mentioned a couple weeks ago, I was in the process of unraveling a load of projects that were tied together, trying to get them all into separate code repositories.  I finally got that done and got them all published to NuGet (well not the CF versions of those that support the CF – patience).

And so you now have available:

 

Getting Mono Process Info from a Mono App

Since a large amount of the work I tend to do is for embedded devices, and since I don’t like to have to visit deployed devices to restart an app whenever it may crash, a pretty common pattern I use is to create a watchdog application that periodically checks to see if the actual application is running and start it if it’s not.  It a bit more complex than that because I typically have support for intentional shutdowns and I like to log all restarts for diagnostics, but the general premise is pretty simple.  The app should always be running.  If it’s not, start it again.

In Mono (under Linux anyway) that task turns out to be a bit of a challenge.  Process.GetProcesses doesn’t work because rather than giving the actuall Application name like the .NET Framework does under Windows, Mono simply returns a Process with a ProcessName of “mono-sgen” for all of the Mono apps running.  I can’t differentiate between the Watchdog app, the target app and any other app that may or may not be running.

I ended up creating a new class I called LinuxProcess (for lack of a better name).  Ideally it would be a Process derivative, or even rolled back into the Mono source, but for now it’s stand-alone and feature-limited to what I needed for a Watchdog.  Full source is below (sorry about the length, but I prefer this over a zip, and it’s searchable and indexable).

using System;
using System.IO;
using System.Linq;

using Output = System.Console;
using System.Collections.Generic;

namespace System.Diagnostics
{
	public class LinuxProcess
	{
		private Process m_process;

        private LinuxProcess(string fileName)
        {
            m_process = Process.Start(fileName);
        }

		private LinuxProcess(int pid)
		{
			Id = pid;
			m_process = Process.GetProcessById(pid);

			if (m_process == null)
			{
				Output.WriteLine("GetProcessById returned null");
			}
		}

        public static LinuxProcess Start(string fileName)
        {
            return new LinuxProcess(fileName);
        }

        public bool HasExited
        {
            get { return m_process.HasExited; }
        }

		public void Kill()
		{
			m_process.Kill();
		}

		public static LinuxProcess[] GetProcessesByName(string processName)
		{
			return GetProcesses().Where(p => p.ProcessName == processName).ToArray();
		}

		public static LinuxProcess[] GetProcesses()
		{
			var list = new List<LinuxProcess>();

			foreach (var path in Directory.GetDirectories("/proc")) 
			{
				var d = Path.GetFileName(path);
				int pid;

				if (!int.TryParse(d, out pid))
				{
					continue;
				}
					
				// stat
				var stat = GetStat(pid);
				if (stat == null) continue;

				var proc = new LinuxProcess(stat.PID);
				proc.ProcessState = stat.State;

				// look for mono-specific processes
				if (stat.FileName == "(mono)")
				{
					// TODO: handle command-line args to the Mono app
					var cmdline = GetCommandLine(stat.PID);

					// cmdline[0] == path to mono
					// cmdline[1] == mono app
					// cmdline[1+n] == mono app args
					proc.ProcessName = Path.GetFileName(cmdline[1]);
				}
				else
				{
					// trim out the parens
					proc.ProcessName = stat.FileName.Trim(new char[] { '(', ')' });
				}

				list.Add(proc);
			}

			return list.ToArray();
		}

		private static Stat GetStat(int pid)
		{
			try
			{
				var statDir = string.Format("/proc/{0}/stat", pid);
				if (!File.Exists(statDir))
					return null;

				var proc = new LinuxProcess(pid);

				using (var reader = File.OpenText(statDir))
				{
					var line = reader.ReadToEnd();
					return new Stat(line);
				}
			}
			catch (Exception ex)
			{
				Output.WriteLine("Stat Exception: " + ex.Message);
				return null;
			}
		}

		private static string[] GetCommandLine(int pid)
		{
			// The command line arguments appear in this file as a set of null-separated strings, with a further null byte after the last string. 
			using (var reader = File.OpenText(string.Format("/proc/{0}/cmdline", pid)))
			{
				string contents = reader.ReadToEnd();
				var args = contents.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
				return args;
			}
		}

		public int Id { get; private set; }
		public string ProcessName { get; private set; }

		public ProcessState ProcessState { get; private set; }
	}

	internal class Stat
	{
		internal Stat(string procLine)
		{
			try
			{
				var items = procLine.Split(new char[] { ' ' }, StringSplitOptions.None);

				PID = Convert.ToInt16(items[0]);
				FileName = items[1];

				switch (items[2][0])
				{
					case 'R':
						State = ProcessState.Running;
						break;
					case 'S':
						State = ProcessState.InterruptableWait;
						break;
					case 'D':
						State = ProcessState.UninterruptableDiskWait;
						break;
					case 'Z':
						State = ProcessState.Zombie;
						break;
					case 'T':
						State = ProcessState.Traced;
						break;
					case 'W':
						State = ProcessState.Paging;
						break;
				}
			}
			catch (Exception ex)
			{
				Output.WriteLine("Stat parse exception: " + ex.Message);
			}
		}

		public int PID { get; private set; }
		public string FileName { get; private set; }
		public ProcessState State { get; private set; }
	}

	public enum ProcessState
	{
		Running, // R
		InterruptableWait, // S
		UninterruptableDiskWait, // D
		Zombie, // Z
		Traced, // T
		Paging // W
	}
}

HOWTO: Add the Win32 file version to your .NET Compact Framework assemblies

[NOTE: This is an old post from November 15, 2004 by Neil Cowburn that is hit fairly frequently and that I’ve recovered using the Wayback Machine]

Currently, this is only one supported method of setting the Win32 file version of your .NET Compact Framework assemblies. This is by command-line compiling your project using the “/win32res” switch with csc.exe and a Win32 resource file. This is definitely not an optimal solution if you are not familiar with command-line compiling .NET CF apps.

In the .NET Framework, those lucky developers are able to set the Win32 file version using a special attribute in the AssemblyInfo file. However this attribute, System.Reflection.AssemblyFileVersionAttribute, is missing from the .NET Compact Framework. How can we fix this so that we can easily set the Win32 file version? Easy! Add the following code to your project:

using System;
namespace System.Reflection
{
    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple=false)]
    public class AssemblyFileVersionAttribute : Attribute
    {
        private string version;
        public string Version
        {
            get { return version; }
        }
        public AssemblyFileVersionAttribute(string version)
        {
            if(version == null)
            {
                throw new ArgumentNullException("version");
            }
            this.version = version;
        }
    }
}

And then, in your AssemblyInfo file, add the following attribute:

[C#]

[assembly: AssemblyFileVersion("1.0.0")]

 

[VB]

<Assembly: AssemblyFileVersion("1.0.0")>

 

Compile your project and then check out its property page using Windows Explorer. You should see that the File Version information has been successfully added to your assembly.

Building a Mono Solution with Jenkins

I recently switched our entire build system over to using a Jenkins build server.  It’s been running for a couple weeks now and I keep expanding the jobs I have it doing, and all in all I’m very happy with how it’s going.  It’s certainly saved me a load of time and the fact we now are getting automated nightly builds of all of our installers is extremely valuable to us and our customers.

Once of the challenges in getting things working was getting the build of the Linux installer for Solution Engine automated.  The Jenkins Server is a Windows Server and Solution Engine in built using Mono, but the actual deployment package is a tarball.  Generating tarballs on a Windows platform really isn’t well documented or outlined anywhere that I could find, but I was able piece the process together from some help files, man pages and a lot of iterations.

In the end, the build portion of the job is done through four separate “Execute Windows Batch Command” steps.

Step 1: Compile the Solution

This one was pretty straightforward.  You simply use the xbuild.exe application that ships with Mono and point it at your Visual Studio/Xamarin Solution File:

"C:Program Files (x86)Mono-3.2.3libmono4.5xbuild.exe" /p:Configuration=Debug SolutionEngine.Mono.sln

Step 2: Copy the results

xbuild puts the files into the output structure I want (that’s how the Visual Studio solution is architected) but it also generates a lot of cruft.  I use robocopy, which is already part of Server, to copy all of my files except files with a *.pdb or *.mdb extension to a temporary output location:

robocopy PublishSolutionEngineDebugMono Installersoutput /s /xf *.pdb *.mdb

Step 3: Put the results into a tarball

Next I use 7-zip to build the tarball.  This part was surprisingly confusing.  7-zip has some documentation, but it’s far from clear, and I even found a page that had “command line examples” but I’m not sure that it really gave me any more clarity.  In the end I just did lots and lots of iterations on the build, checking the output every time to see what happened.  In the end, this is the command I ended up with:

"C:Program Files (x86)7-Zip7z.exe" a -ttar SolutionEngine.tar "%WORKSPACE%Installersoutput*.*" -mmt -r

This breaks down as follows:

  • The ‘a’ flag means I’m creating (as opposed to extracting from) an archive
  • -ttar is a switch meaning “type tar” – I’m using a tar container (as opposed to say a zip, iso or whatever)
  • SolutionEngine.tar is the output file.  It ends up in the working folder where I’m running command.
  • The next section is the “source”.  %WORKSPACE% is an environment variable Jenkins sets and the rest of the path you can see is the destination from Step 2 above.  *.* means I want everything found at the source location in the tar.
  • -mmt means “use multi-threading when compressing” which I think ends up using multiple cores if available.  I didn’t compare times with and without, so I don’t know how much it helps and it’s probably negligible – my end tar is only about 9MB.  Having the switch doesn’t cause problems, so I’m leaving it in.
  • The -r flag means “recurse the source.”  My source folder has several layers of subdirectories and I want them all in the tarball, maintaining the folder structure.  This flag achieves that.

Step 4: Compress the tarball

For those unaware, a “tar.gz” file is a double operation – package, then compress the package.  Step 3 built the package, but to be friendly to both my upload process and our customers who have to download it, I also compress the file.  To compress the tarball with gzip compression I again use 7-zip.

"C:Program Files (x86)7-Zip7z.exe" a -tgzip SolutionEngine.tar.gz "%WORKSPACE%SolutionEngine.tar"

This one is simpler than Step 3 and breaks down as follows:

  • The ‘a’ flag, again, means I’m creating an archive
  • -tgzip is a switch meaning “compress using type gzip”
  • SolutionEngine.tar.gz is the output file.  Again, it ends up in the working folder where I’m running command.
  • The next section is the “source” file, which was the tar file output by Step 3 above.

New Blog for IoT/Intelligent Systems Topics

I’ve created a new blog page specifically for information on Intelligent Systems, IoT and M2M topics.  This blog will continue to have the same type of content I’ve typically posted: developer-centric information covering cross-platform and embedded devices for the .NET developer, but topics that are specifically looking at IoT and our Solution Family products will now be over on our sister blog.