<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Stuff &#187; Geekiness</title>
	<atom:link href="http://stuff.iain.cx/category/geekiness/feed/" rel="self" type="application/rss+xml" />
	<link>http://stuff.iain.cx</link>
	<description>Dumenil said I should write a blog</description>
	<lastBuildDate>Sun, 22 Feb 2015 12:25:36 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.8</generator>
	<item>
		<title>How Linux sets NFS filesystem ID on the wire</title>
		<link>http://stuff.iain.cx/2014/11/16/how-linux-sets-nfs-filesystem-id-on-the-wire/</link>
		<comments>http://stuff.iain.cx/2014/11/16/how-linux-sets-nfs-filesystem-id-on-the-wire/#comments</comments>
		<pubDate>Sun, 16 Nov 2014 13:43:46 +0000</pubDate>
		<dc:creator><![CDATA[iain]]></dc:creator>
				<category><![CDATA[Geekiness]]></category>

		<guid isPermaLink="false">http://stuff.iain.cx/?p=379</guid>
		<description><![CDATA[These tests were peformed by capturing NFS traffic with Wireshark and looking for the fsid major and minor numbers. # tshark -T fields -e nfs.fsid4.major -e nfs.fsid4.minor port 2049 Errors and omissions excepted. All mistakes my own. If you don&#8217;t know what I&#8217;m talking about or why this would be useful to know then this [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>These tests were peformed by capturing NFS traffic with Wireshark and looking for the <em>fsid</em> major and minor numbers.</p>
<p>
<pre>    # tshark -T fields -e nfs.fsid4.major -e nfs.fsid4.minor port 2049</pre>
</p>
<p>Errors and omissions excepted.  All mistakes my own.  If you don&#8217;t know what I&#8217;m talking about or why this would be useful to know then this post will not be very interesting.</p>
<p><span id="more-379"></span></p>
<h2>knfsd</h2>
<h3>With UUID fsid</h3>
<p>You have an export like this:</p>
<p>
<pre>    /export -rw,fsid=01234567-89ab-cdef-dead-beefcafebabe 192.168.0.0/24</pre>
</p>
<p>The <em>fsid</em> is found by considering the UUID as two unsigned 64-bit hexadecimal integers.  In the example above they would be <em>0x123456789abcdef</em> and </em>0xdeadbeefcafebabe</em>.  The major number is therefore <strong>81985529216486895</strong> and the minor number is <strong>16045690984503098046</strong>.</p>
<h3>With numeric fsid</h3>
<p>You have an export like this:</p>
<p>
<pre>    /export -rw,fsid=1234 192.168.0.0/24</pre>
</p>
<p>The <em>fsid</em> is found by setting the major number to the number specified and zeroing the minor number.  In the example above the major number is <strong>1234</strong> and the minor number is <strong>0</strong>.</p>
<p>The rule holds for the pseudo-root filesystem with <em>fsid=0</em> &#8211; alternatively specified as <em>fsid=root</em>.</p>
<h3>With no explicit fsid</h3>
<p>If your export doesn&#8217;t specify <em>fsid</em> the kernel will look for the exported filesystem UUID and apply the same logic above.
<p>For example on my test machine I exported the root filesystem.</p>
<p>
<pre>    # xfs_admin -l /dev/dm-0
    UUID = e2f1c059-e6c2-403d-9c80-ab7a9f86b91f
</pre>
</p>
<p>So the major number is <strong>16353063214315094077</strong> and the minor number is <strong>11277202010086488351</strong>.</p>
<h2>Ganesha</h2>
<h3>With Filesystem_Id</h3>
<p>No prizes for guessing what the <em>Filesystem_Id</em> parameter does.</p>
<p>
<pre>    EXPORT {
      Filesystem_Id = 1234.5678;
      ...
    }</pre>
</p>
<p>In the example above the major number is <strong>1234</strong> and the minor number is <strong>5678</strong>.</p>
<p><em>Yes, you can make the </em>fsid<em> for an export the same as given by </em>knfsd<em>.</em></p>
<p>
<pre>      Filesystem_Id = 81985529216486895.16045690984503098046;</pre>
</p>
<h3>With no explicit Filesystem_Id</h3>
<p>The documentation states that the <em>fsid</em> defaults to <em>666.666</em> if <em>Filesystem_Id</em> is not explicitly configured.  In my testing that statement didn&#8217;t appear to hold true.  Since my goal was to figure out how to set the <em>fsid</em> to be consistent &#8211; so I could fail over the IP providing NFS service &#8211; I didn&#8217;t delve too deeply into this case.</p>
]]></content:encoded>
			<wfw:commentRss>http://stuff.iain.cx/2014/11/16/how-linux-sets-nfs-filesystem-id-on-the-wire/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NSSM 2.16</title>
		<link>http://stuff.iain.cx/2012/10/17/nssm-2-16/</link>
		<comments>http://stuff.iain.cx/2012/10/17/nssm-2-16/#comments</comments>
		<pubDate>Wed, 17 Oct 2012 05:56:43 +0000</pubDate>
		<dc:creator><![CDATA[iain]]></dc:creator>
				<category><![CDATA[Geekiness]]></category>

		<guid isPermaLink="false">http://stuff.iain.cx/?p=364</guid>
		<description><![CDATA[The next release of NSSM will be version 2.16 and it will include a feature which has been requested a number of times over the years, namely the ability to redirect the standard I/O streams which UNIX users know as stdin, stdout and stderr. Surely getting an application to redirect its output would be easy. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>The next release of <a href="http://nssm.cc/">NSSM</a> will be version 2.16 and it will include a feature which has been requested a number of times over the years, namely the ability to redirect the standard I/O streams which UNIX users know as <em>stdin</em>, <em>stdout</em> and <em>stderr</em>.</p>
<p><span id="more-364"></span></p>
<p>Surely getting an application to redirect its output would be easy.  In fact I discovered:</p>
<ul>
<li>
<p>You have to explicitly pass the filehandles to <code>CreateProcess()</code>.</p>
</li>
<li>
<p>You have to explicitly tell <code>CreateProcess()</code> that the filehandles are inheritable when launching a child process.</p>
</li>
<li>
<p>You have to explicitly tell <code>CreateFile()</code> that the filehandles are inheritable when opening them in the first place.</p>
</li>
<li>
<p>Opening a file with <code>FILE_APPEND_DATA</code> semantics is not sufficient to append to a file.  You have to explicitly seek to the end of the file.</p>
</li>
<li>
<p>You can&#8217;t open two filehandles to the same path or there will be a race and one of them will lose data.  You need to call <code>DuplicateHandle()</code> if both targets are the same.  Determining that the user asked for both targets to be the same is an exercise for the reader.  Vista offers <code>GetFinalPathNameByHandle()</code> but I couldn&#8217;t use that in NSSM because NSSM needs to work on older Windows versions.</p>
</li>
<li>
<p>Trying to open a file with <code>FILE_APPEND_DATA | FILE_WRITE_DATA</code> and <code>OPEN_ALWAYS</code> will not result in opening a file for appending if it already exists or creating a new file if it didn&#8217;t.  You have to try to open it for append and, if that fails with <code>ERROR_FILE_NOT_FOUND</code>, try again as a new file.  Otherwise the file will be truncated.</p>
</li>
</ul>
<p>On the plus side, the use of <code>CreateFile()</code> behind the scenes makes it entirely possible that you will be able to do clever stuff like open named pipes and connect IPC for different services together, or take input from a serial port.</p>
<p>Although reading to and writing from plain files is working and, as mentioned above, other I/O should in theory work just as well, the release won&#8217;t be coming just yet.  I will also be including some rudimentary CPU affinity handling based on a contribution from Robert Middleton.  I may even make good on my longstanding threat to remove the readable standard C stuff like declaring variables as <code>unsigned long</code> and replace them with ugly Win32-isms such as <code>DWORD</code>.  I hate to do it but like it or not NSSM is a Windows application and probably should follow Windows coding conventions.</p>
<p>But not, under any circumstances, Hungarian notation.</p>
]]></content:encoded>
			<wfw:commentRss>http://stuff.iain.cx/2012/10/17/nssm-2-16/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Policing and monitoring</title>
		<link>http://stuff.iain.cx/2011/12/27/policing-and-monitoring/</link>
		<comments>http://stuff.iain.cx/2011/12/27/policing-and-monitoring/#comments</comments>
		<pubDate>Tue, 27 Dec 2011 12:17:38 +0000</pubDate>
		<dc:creator><![CDATA[iain]]></dc:creator>
				<category><![CDATA[Geekiness]]></category>

		<guid isPermaLink="false">http://stuff.iain.cx/?p=334</guid>
		<description><![CDATA[Last year I configured my Cisco 877 router to rate-limit downloads so as not to exceed my ISP&#8217;s monthly quota. Later I realised that rate-limiting is not the best method to cap downstream traffic and switched to policing instead. My method worked but with some changes to the implementation I have since been able to [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Last year I configured my Cisco 877 router to <a href="http://stuff.iain.cx/2010/07/11/cisco-877-download-rate-limiting/">rate-limit downloads</a> so as not to exceed my ISP&#8217;s monthly quota.  Later I realised that rate-limiting is not the best method to cap downstream traffic and switched to <a href="http://stuff.iain.cx/2010/08/31/policing-vs-rate-limiting/">policing</a> instead.  My method worked but with some changes to the implementation I have since been able to simplify the management and get access to more useful stats.</p>
<p><span id="more-334"></span></p>
<p>Explaining the difference between what I was doing and what I&#8217;m now doing would probably take almost as long as describing everything from scratch and would certainly be confusing let&#8217;s go back to the very beginning.</p>
<p>The situation was that my ISP imposed a strict download quota between the hours of 0900 and 1800 on weekdays.  I wanted to make sure that I didn&#8217;t inadvertently eat into that quota by configuring traffic management policies on the router.</p>
<p>Since the peak period is based on time of day I first configured the local timezone correctly.</p>
<p>
<pre>    clock timezone GMT 0
    clock summer-time BST recurring last Sun Mar 1:00 last sun Oct 2:00</pre>
</p>
<p>Then I created a time range to represent peak time.</p>
<p>
<pre>    time-range peak
     periodic weekdays 9:00 to 17:59</pre>
</p>
<p>The time range is used inside IP and IPv6 access lists which would match any connection at peak time.</p>
<p>
<pre>    ip access-list extended peak
     permit ip any any time-range peak

    ipv6 access-list peak6
     permit ipv6 any any time-range peak</pre>
</p>
<p>We next need a class-map which will categorise any traffic which matches the <em>peak</em> or <em>peak6</em> access lists.  Thus it must be a <em>match-any</em> class-map.</p>
<p>
<pre>    class-map match-any peak
     match access-group name peak
     match access-group name peak6</pre>
</p>
<p>Rather than just apply a blanket restriction I wanted to allow different types of traffic to have different speeds.  For example I decided that HTTP traffic should be allowed to attain 1Mbps in peak time.  Outside peak time I wasn&#8217;t applying any throttling at all.</p>
<p>Now we need a class-map to recognise HTTP.  That&#8217;s achieved with a combination of the router&#8217;s own protocol recognition and some custom access lists which match non-standard but commonly-used ports.</p>
<p>
<pre>    ip access-list extended http-alt
     permit tcp any eq 8080 any
     permit tcp any eq 8443 any

    ipv6 access-list http-alt6
     permit tcp any eq 8080 any
     permit tcp any eq 8443 any

    class-map match-any http
     match protocol http
     match protocol secure-http
     match access-group name http-alt
     match access-group name http-alt6</pre>
</p>
<p>In order to apply the 1Mbps restriction we need a <em>policy-map</em>.  The peak class-map is used to limit the effects of the policy to traffic in peak time.</p>
<p>
<pre>    policy-map 1Mbps
     class peak
        police rate 1024000
          conform-action transmit
          exceed-action drop
          violate-action drop</pre>
</p>
<p>The penultimate step is to create a policy, to be applied on the dialer interface, which will match traffic using the class-maps defined earlier and apply the appropriate restriction policies.  Any traffic not categorised by a class-map is handled by the <em>class-default</em> rule.</p>
<p>
<pre>    policy-map from_internet
     class http
      service-policy 1Mbps
     class class-default
      service-policy 512kbps</pre>
</p>
<p>Finally the <em>from_internet</em> policy is applied to the dialer interface so as to take effect.</p>
<p>
<pre>    interface Dialer 0
     service-policy input from_internet</pre>
</p>
<p>By configuring policing this way I am able to see stats for all the traffic classes I define without needing to set up a separate Netflow server.</p>
<p>
<pre>    # show policy-map interface Dialer 0 input class http
     Dialer0

      Service-policy input: from_internet

        Class-map: http (match-any)
          7880183 packets, 9841690612 bytes
          5 minute offered rate 7000 bps</pre>
</p>
<p>To keep this post simple I only described one speed for one traffic class.  In reality I created several more time-ranges and policy-maps, and nested service policies to allow variable restrictions at different times of day.  When my ISP tightened the download quota for evenings and weekends I was able to apply a tiered strategy whereby peak time traffic was severely restricted, nighttime traffic was unrestricted and remaining times were mildly restricted.  Then after a month I switched to an uncapped ISP but that's another story.</p>
<p>
<pre>    time-range off-peak
     periodic daily 2:00 to 5:59

    ip access-list extended off-peak
     permit ip any any time-range off-peak

    ipv6 access-list off-peak6
     permit ipv6 any any time-range off-peak

    class-map match-any off-peak
     match access-group name off-peak
     match access-group name off-peak6

    policy-map 256kbps
     class class-default
        police rate 256000
          conform-action transmit
          exceed-action drop
          violate-action drop

    policy-map unlimited
     class class-default

    policy-map low
     class peak
      service-policy 256kbps
     class off-peak
      service-policy unlimited
     class class-default
      service-policy 512kbps

    policy-map from_internet
     class p2p
      service-policy low
     class http
      service-policy medium</pre></p>
]]></content:encoded>
			<wfw:commentRss>http://stuff.iain.cx/2011/12/27/policing-and-monitoring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>libvirtd Kerberos</title>
		<link>http://stuff.iain.cx/2011/05/08/libvirtd-kerberos/</link>
		<comments>http://stuff.iain.cx/2011/05/08/libvirtd-kerberos/#comments</comments>
		<pubDate>Sun, 08 May 2011 10:24:35 +0000</pubDate>
		<dc:creator><![CDATA[iain]]></dc:creator>
				<category><![CDATA[Geekiness]]></category>

		<guid isPermaLink="false">http://stuff.iain.cx/?p=306</guid>
		<description><![CDATA[I had some fun getting libvirtd to work with GSSAPI. It looked like it should be easy but documentation was thin on the ground and some key points were glossed over. Eventually I did figure it out. Here&#8217;s how. The first step is to configure libvirtd to accept connections secured with GSSAPI. That means it [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I had some fun getting <a href="http://libvirt.org/">libvirtd</a> to work with GSSAPI.  It looked like it should be easy but documentation was thin on the ground and some key points were glossed over.  Eventually I did figure it out.  Here&#8217;s how.</p>
<p><span id="more-306"></span></p>
<p>The first step is to configure <em>libvirtd</em> to accept connections secured with GSSAPI.  That means it needs to listen on a TCP port, which it won&#8217;t do by default.  On my Fedora system that was rectified by editing <em>/etc/sysconfig/libvirtd</em> and uncommenting the line:</p>
<p>
<pre>    LIBVIRTD_ARGS=&quot;--listen&quot;</pre>
</p>
<p>This ensures the <strong>&#8211;listen</strong> flag is passed to <em>libvirtd</em>, enabling TCP connections.  That in itself, however, is not enough.  For security the default configuration disables unencrypted connections and enables only TLS-encrypted access.  Since we&#8217;ll be using Kerberos we don&#8217;t need TLS.  You can leave it on if you have a certificate set up but since I didn&#8217;t I turned it off; with no certificate and TLS configured the service won&#8217;t start.  The file to edit is <em>/etc/libvirt/libvirtd.conf</em>:</p>
<p>
<pre>    listen_tls = 0
    listen_tcp = 1</pre>
</p>
<p><em>libvirtd</em> uses SASL for GSSAPI so we need the appropriate libraries; on Fedora that means the <em>cyrus-sasl-gssapi</em> RPM.  Still in <em>libvirtd.conf</em> we need to configure SASL for unencrypted connections:</p>
<p>
<pre>    auth_tcp = &quot;sasl&quot;</pre>
</p>
<p>Then we need to set up a whitelist of users who are allowed to connect.  Wildcards are allowed so you could just use <strong>[&quot;*&quot;]</strong> if you wanted anyone with valid Kerberos credentials to get access to the hypervisor.  That probably isn&#8217;t a good idea.</p>
<p>Note that the comments in <em>libvirtd.conf</em> suggest that you need to use full user principal names in the list.  That&#8217;s only true for users who are not in the default realm configured in <em>/etc/krb5.conf</em>.  Indeed a UPN containing the default realm name <em>will not</em> work.</p>
<p>
<pre>    sasl_allowed_username_list = [&quot;admin&quot;, &quot;trusted@ANOTHER.REALM&quot;]</pre>
</p>
<p>The example above allows <em>admin</em> from the default realm and <em>trusted</em> from the <em>ANOTHER.REALM</em> realm.  No one else can connect.</p>
<p>Next we need to tell <em>libvirtd</em> that GSSAPI is a valid security mechanism by editing <em>/etc/sasl2/libvirt.conf</em>.  The default configuration allows DIGEST-MD5 so we need to comment out lines referencing that and uncomment the right one:</p>
<p>
<pre>    mech_list: gssapi</pre>
</p>
<p>Finally &#8211; for <em>libvirtd</em> itself &#8211; we need to create a keytab for <strong>libvirt/&lt;fqdn&gt;@&lt;REALM&gt;</strong> and install it as <strong>/etc/libvirt/krb5.tab</strong>.  It need only be accessible to root.</p>
<p>With all that done &#8211; and <em>libvirtd</em> restarted &#8211; a user with Kerberos credentials matching one of the users allowed above should be able to connect to the hypervisor.</p>
<p>
<pre>    virsh -c qemu+tcp://hostname/system</pre>
</p>
<p>You can also connect using <em>virt-manager</em> by adding a new connection.</p>
<ul>
<li>Connect to remote host</li>
<li>Method: TCP</li>
<li>Username: <em>blank</em></li>
<li>Hostname: <em>as appropriate</em></li>
</ul>
<p>At which point you will find that we&#8217;re only half done.  VNC needs to be Kerberized separately.</p>
<p>The process is similar.  First we need to enable SASL and make sure we are listening, since by default VNC only listens on the loopback interface.  This is done in <em>/etc/libvirt/qemu.conf</em>:</p>
<p>
<pre>    vnc_listen = &quot;[::]&quot;
    vnc_sasl = 1</pre>
</p>
<p>Since this post was originally made, newer versions of <em>libvirtd</em> changed the syntax of the listen address to <strong>::</strong> (no square brackets).  If you only need IPv4 networking you can use <strong>0.0.0.0</strong> and of course you can specify a particular address if you prefer.</p>
<p>As with <em>libvirtd</em>, we don&#8217;t need TLS with Kerberos.</p>
<p>
<pre>    vnc_tls = 0</pre>
</p>
<p>We also need to configure <em>/etc/sasl2/qemu.conf</em> in the same way as <em>libvirt.conf</em>:</p>
<p>
<pre>    mech_list: gssapi</pre>
</p>
<p>And finally we need a keytab installed as <strong>/etc/qemu/krb5.tab</strong> and readable by the <em>qemu</em> user.  Despite conflicting reports in the documentation I found, the service principal name needs to be <strong>vnc/&lt;fqdn&gt;@&lt;REALM&gt;</strong>.</p>
<p><em>Newly-started</em> guests will now have their consoles accessible from the Kerberized <em>virt-manager</em> connection.</p>
<p>Note that <em>qemu</em> supports ACLs restricting access to named users but at time of writing <em>libvirt</em> doesn&#8217;t know how to configure them.  If security is a concern you may prefer to use SSH tunnelling instead.  You can use Kerberos and not need to type a password&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://stuff.iain.cx/2011/05/08/libvirtd-kerberos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Error messages</title>
		<link>http://stuff.iain.cx/2010/11/18/error-messages/</link>
		<comments>http://stuff.iain.cx/2010/11/18/error-messages/#comments</comments>
		<pubDate>Thu, 18 Nov 2010 12:51:18 +0000</pubDate>
		<dc:creator><![CDATA[iain]]></dc:creator>
				<category><![CDATA[Geekiness]]></category>
		<category><![CDATA[Rants]]></category>

		<guid isPermaLink="false">http://stuff.iain.cx/?p=300</guid>
		<description><![CDATA[The command: snapdrive storage list -all The error message displayed to the user: Status call to SDU daemon failed The error hidden in the Snapdrive trace log: Fatal error: Assertion detected in production code: ../sbl/StorageOperation.cpp:182: Test &#8216;osAssistants.size() == 1&#8242; failed The actual problem: /etc/redhat-release contains the string CentOS not Red Hat.]]></description>
				<content:encoded><![CDATA[<p>The command: <code>snapdrive storage list -all</code></p>
<p>The error message displayed to the user: <em>Status call to SDU daemon failed</em></p>
<p>The error hidden in the Snapdrive trace log: <em>Fatal error: Assertion detected in production code: ../sbl/StorageOperation.cpp:182: Test &#8216;osAssistants.size() == 1&#8242; failed</em></p>
<p>The actual problem: <em>/etc/redhat-release</em> contains the string CentOS not Red Hat.</p>
]]></content:encoded>
			<wfw:commentRss>http://stuff.iain.cx/2010/11/18/error-messages/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Policing vs rate-limiting</title>
		<link>http://stuff.iain.cx/2010/08/31/policing-vs-rate-limiting/</link>
		<comments>http://stuff.iain.cx/2010/08/31/policing-vs-rate-limiting/#comments</comments>
		<pubDate>Tue, 31 Aug 2010 06:31:51 +0000</pubDate>
		<dc:creator><![CDATA[iain]]></dc:creator>
				<category><![CDATA[Geekiness]]></category>

		<guid isPermaLink="false">http://stuff.iain.cx/?p=291</guid>
		<description><![CDATA[I read some Cisco documentation recommending the use of traffic policing in a service policy over rate-limiting on an interface. I already used a policy to set DSCP values which later controlled the rate-limiting so switching to policing would cut out the middle man and be easier to understand. That being said, my goal is [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I read some Cisco documentation recommending the use of traffic policing in a service policy over rate-limiting on an interface.  I already used a policy to set DSCP values which later controlled the rate-limiting so switching to policing would cut out the middle man and be easier to understand.  That being said, my goal is not to enter my router into some kind of Cisco guideline conformance competition but to get it to to what I want efficiently.  The fact that Cisco recommend doing things differently is not in itself reason to switch.  For that I looked at the rather harsh effects of rate-limiting.</p>
<p><span id="more-291"></span></p>
<p>As an example I was downloading a file via HTTP during peak time yesterday.  The transfer was proceeding at 32kBps or so which is to be expected.  Then all of a sudden it dropped out.  From time to time I had been seeing similar things.  When Steam decides to download patches for games it will report wildly fluctuating download rates.  This is to be expected if your traffic management consists of dropping inbound packets but if anything can make things more civilised then I&#8217;m happy to hear about it.</p>
<p>I removed my rate-limiting options from the Dialer0 interface and instead added <em>police</em> rules (with the exact same bandwidth specifications) to my <em>peak</em> service policy, which now looks like this:</p>
<p>
<pre>    policy-map peak
      description Set bandwidth at peak time.
     class peak-default
        police 64000 12000 24000 conform-action transmit  exceed-action drop  violate-action drop
     class peak-lowest
        police 32000 6000 12000 conform-action transmit  exceed-action drop  violate-action drop
     class peak-low
        police 128000 24000 48000 conform-action transmit  exceed-action drop  violate-action drop
     class peak-medium
        police 512000 96000 192000 conform-action transmit  exceed-action drop  violate-action drop
     class peak-high
        police 1024000 192000 384000 conform-action transmit  exceed-action drop  violate-action drop</pre>
</p>
<p>It seemed to work.  Traffic was still limited to the desired bandwidth but the file which I consistently failed to download properly was successfully retrieved</p>
]]></content:encoded>
			<wfw:commentRss>http://stuff.iain.cx/2010/08/31/policing-vs-rate-limiting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rate limiting stats</title>
		<link>http://stuff.iain.cx/2010/07/13/rate-limiting-stats/</link>
		<comments>http://stuff.iain.cx/2010/07/13/rate-limiting-stats/#comments</comments>
		<pubDate>Tue, 13 Jul 2010 13:03:48 +0000</pubDate>
		<dc:creator><![CDATA[iain]]></dc:creator>
				<category><![CDATA[Geekiness]]></category>

		<guid isPermaLink="false">http://stuff.iain.cx/?p=283</guid>
		<description><![CDATA[My experiment with rate limiting downloads seems to be largely successful, modulo a few typos and omissions. I accidentally set the HTTP class as a match-all rule rather than a match-any rule, meaning it would always fail to match as traffic cannot be both HTTP and HTTPS traffic simultaneously. I also forgot to add SSH [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>My <a href="/2010/07/11/cisco-877-download-rate-limiting/">experiment with rate limiting downloads</a> seems to be largely successful, modulo a few typos and omissions.  I accidentally set the HTTP class as a <em>match-all</em> rule rather than a <em>match-any</em> rule, meaning it would always fail to match as traffic cannot be both HTTP and HTTPS traffic simultaneously.  I also forgot to add SSH to a policy class.  As a result both these protocols ended up being the default (slow) group.  Everything else is working well so far.</p>
<p><span id="more-283"></span></p>
<p>I can see some statistics on the rate limiting.</p>
<p>
<pre>    # sh int d0 rate-limit
     Dialer0 
      Input
        matches: dscp 1
          params:  64000 bps, 12000 limit, 24000 extended limit
          conformed 58600 packets, 4220034 bytes; action: transmit
          exceeded 0 packets, 0 bytes; action: drop
          last packet: 64ms ago, current burst: 0 bytes
          last cleared 02:04:55 ago, conformed 4000 bps, exceeded 0 bps
        matches: dscp 2
          params:  32000 bps, 6000 limit, 12000 extended limit
          conformed 10541 packets, 12268452 bytes; action: transmit
          exceeded 12986 packets, 18191623 bytes; action: drop
          last packet: 36ms ago, current burst: 10018 bytes
          last cleared 1d22h ago, conformed 0 bps, exceeded 0 bps
        matches: dscp 3
          params:  128000 bps, 24000 limit, 48000 extended limit
          conformed 71436 packets, 7030498 bytes; action: transmit
          exceeded 81 packets, 77046 bytes; action: drop
          last packet: 24ms ago, current burst: 0 bytes
          last cleared 1d22h ago, conformed 0 bps, exceeded 0 bps
        matches: dscp 4
          params:  256000 bps, 48000 limit, 96000 extended limit
          conformed 1021747 packets, 109363738 bytes; action: transmit
          exceeded 4012 packets, 3572353 bytes; action: drop
          last packet: 20ms ago, current burst: 0 bytes
          last cleared 1d22h ago, conformed 5000 bps, exceeded 0 bps
        matches: dscp 5
          params:  1024000 bps, 192000 limit, 384000 extended limit
          conformed 407623 packets, 249878838 bytes; action: transmit
          exceeded 13419 packets, 13016776 bytes; action: drop
          last packet: 4789ms ago, current burst: 0 bytes
          last cleared 1d22h ago, conformed 11000 bps, exceeded 0 bps</pre>
</p>
<p>Unfortunately it isn&#8217;t apparent which types of traffic are ending up with each classification.</p>
<p>
<pre>    # sh policy-map int d0
     Dialer0 
    
      Service-policy input: peak
    
        Class-map: peak-lowest (match-all)
          24951 packets, 32543191 bytes
          5 minute offered rate 86000 bps, drop rate 0 bps
          Match: access-group name peak
          Match: class-map match-any lowest
            Match: class-map match-any p2p
              0 packets, 0 bytes
              5 minute rate 0 bps
              Match: protocol bittorrent
                0 packets, 0 bytes
                5 minute rate 0 bps
              Match: protocol edonkey
                0 packets, 0 bytes
                5 minute rate 0 bps
              Match: protocol gnutella
                0 packets, 0 bytes
                5 minute rate 0 bps
              Match: protocol kazaa2
                0 packets, 0 bytes
                5 minute rate 0 bps
              Match: protocol winmx
                0 packets, 0 bytes
                5 minute rate 0 bps
            Match: class-map match-any rsync
              0 packets, 0 bytes
              5 minute rate 0 bps
              Match: access-group name rsync
                0 packets, 0 bytes
                5 minute rate 0 bps
          QoS Set
            dscp 2
              Packets marked 24948
        ...</pre>
</p>
<p>So traffic is being marked as lowest priority but I can&#8217;t see whether it&#8217;s peer-to-peer or rsync.</p>
<p>This is because the class contains subclasses.  The solution is to set up a separate policy map on the LAN interface to classify traffic sent out of the router to the internal network.  So let&#8217;s set up a policy map with the individual classes I&#8217;m interested in.</p>
<p>
<pre>    policy-map classify
     class p2p
     class rsync</pre>
</p>
<p>My LAN interface happens to be Vlan1 so the policy should be applied on that interface&#8217;s output, going to clients.  There&#8217;s no rate limiting on the interface so all we&#8217;re doing is gathering statistics.</p>
<p>
<pre>    interface Vlan1
     service-policy output classify</pre>
</p>
<p>Now we can see that it&#8217;s rsync which is currently active.</p>
<p>
<pre>    # sh policy-map int vlan1
     Vlan1 
    
      Service-policy output: classify
    
        Class-map: p2p (match-any)
          56 packets, 5525 bytes
          5 minute offered rate 0 bps
          Match: protocol bittorrent
            0 packets, 0 bytes
            5 minute rate 0 bps
          Match: protocol edonkey
            0 packets, 0 bytes
            5 minute rate 0 bps
          Match: protocol gnutella
            0 packets, 0 bytes
            5 minute rate 0 bps
          Match: protocol kazaa2
            0 packets, 0 bytes
            5 minute rate 0 bps
          Match: protocol winmx
            0 packets, 0 bytes
            5 minute rate 0 bps
    
        Class-map: rsync (match-any)
          181 packets, 274034 bytes
          5 minute offered rate 12000 bps
          Match: access-group name rsync
            0 packets, 0 bytes
            5 minute rate 0 bps
</pre>
</p>
<p>Afterwards the temporary policy map can be removed.</p>
<p>
<pre>    no policy-map classify</pre>
</p>
<p>Or it could be kept around for further analysis, adding and removing classes as appropriate.</p>
]]></content:encoded>
			<wfw:commentRss>http://stuff.iain.cx/2010/07/13/rate-limiting-stats/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cisco 877 download rate limiting</title>
		<link>http://stuff.iain.cx/2010/07/11/cisco-877-download-rate-limiting/</link>
		<comments>http://stuff.iain.cx/2010/07/11/cisco-877-download-rate-limiting/#comments</comments>
		<pubDate>Sun, 11 Jul 2010 16:37:16 +0000</pubDate>
		<dc:creator><![CDATA[iain]]></dc:creator>
				<category><![CDATA[Geekiness]]></category>

		<guid isPermaLink="false">http://stuff.iain.cx/?p=273</guid>
		<description><![CDATA[I&#8217;m in the process of migrating to a different ISP. Whereas until now I have been on a flat rate for download usage, the new provider charges significantly more for downloads between 0900 and 1800 on weekdays. As I have a Cisco 877 router I should be able to throttle downloads during peak times and [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m in the process of migrating to a different ISP.  Whereas until now I have been on a flat rate for download usage, the new provider charges significantly more for downloads between 0900 and 1800 on weekdays.</p>
<p>As I have a Cisco 877 router I should be able to throttle downloads during peak times and save myself money compared to the plan I&#8217;ve been using.</p>
<p><span id="more-273"></span></p>
<p>Note that the ISP doesn&#8217;t charge for excessive <em>upload</em> so my work was focussed 100% on download throttling.</p>
<p>The first thing to do was set up a <em>time-range</em> so the router knows what peak time is.  Well actually the zeroth thing to do was configure my timezone correctly.</p>
<p>
<pre>    clock timezone GMT 0
    clock summer-time BST recurring last Sun Mar 1:00 last sun Oct 2:00</pre>
</p>
<p>Now I could define the time range.</p>
<p>
<pre>    time-range peak
     periodic weekdays 9:00 to 17:59</pre>
</p>
<p>Just for fun I set up an off-peak time range.</p>
<p>
<pre>    time-range off-peak
     periodic weekdays 0:00 to 8:59
     periodic weekdays 18:00 to 23:59
     periodic weekend 0:00 to 23:59</pre>
</p>
<p>The <em>sh time-range</em> command verifies that these are set up.</p>
<p>
<pre>    # sh time-range
    time-range entry: off-peak (active)
       periodic weekdays 0:00 to 8:59
       periodic weekdays 18:00 to 23:59
       periodic weekend 0:00 to 23:59
    time-range entry: peak (inactive)
       periodic weekdays 9:00 to 17:59</pre>
</p>
<p>The off-peak range shows as active which is correct because it&#8217;s Sunday at time of writing.</p>
<p>Next I created an access list which would match any connection at peak time.</p>
<p>
<pre>    ip access-list extended peak
     permit ip any any time-range peak</pre>
</p>
<p>At this point I could have just set things up so downloads were throttled at peak times but that would have been inelegant and I wanted more control.  For instance Rebecca will be at home working during the day and she wants to be able to download her mail and make calls to China with Skype.  So for want of a better idea I decided to set up five usage categories:</p>
<ol>
<li>
<p><strong>Default</strong> Anything I forget about and don&#8217;t fit into one of the subsequent categories.  Limited to 64kbps.</p>
</li>
<li>
<p><strong>Lowest:</strong> Stuff that has no business running during the day, like Bittorrent.  Limited to 32kbps.</p>
</li>
<li>
<p><strong>Low:</strong> Stuff like Steam automatic downloads and SSH.  Limited to 128kbps.</p>
</li>
<li>
<p><strong>Medium:</strong> Stuff which could well run during the day and which shouldn&#8217;t be horrendously slow but which I don&#8217;t want spiralling out of control.  Skype and HTTP for example.  Limited to 256kbps.</p>
</li>
<li>
<p><strong>High:</strong> For things that gotta do what they gotta do.  Mail, DNS etc.  Limited to 1Mbps.</p>
</li>
</ol>
<p>Now I set up a <em>class-map</em> for each protocol I was interested in.  The Cisco 877 has some protocol information builtin such as for Skype:</p>
<p>
<pre>    class-map match-any skype
     match protocol skype</pre>
</p>
<p>Others can be defined manually with access lists.</p>
<p>
<pre>    ip access-list extended steam
     permit tcp any range 27014 27050 any

    class-map match-any steam
     match access-group name steam</pre>
</p>
<p>Further class maps allow grouping of protocols according to the classification defined earlier.  Here&#8217;s <em>medium</em>.  <em>lowest</em>, <em>low</em> and <em>high</em> are similar.  These are <em>match-any</em> classes which match any of the listed protocols.</p>
<p>
<pre>    class-map match-any medium
     match class-map http
     match class-map skype</pre>
</p>
<p>A final set of class maps match only at peak time.  These are <em>match-all</em> classes so both criteria &#8211; it&#8217;s peak time and it&#8217;s a particular protocol class &#8211; must match.  Here&#8217;s <em>peak-medium</em>.</p>
<p>
<pre>    class-map match-all peak-medium
     match access-group name peak
     match class-map medium</pre>
</p>
<p>One more class,  <em>peak-default</em> acts as the catchall.</p>
<p>
<pre>    class-map match-all peak-default
     match access-group name peak
     match not class-map lowest
     match not class-map low
     match not class-map medium
     match not class-map high</pre>
</p>
<p>With those classes defined we can now set up a <em>policy-map</em> which assigns a DSCP tag to traffic matching particular classes.</p>
<p>
<pre>    policy-map peak
     class peak-default
      set dscp 1
     class peak-lowest
      set dscp 2
     class peak-low
      set dscp 3
     class peak-medium
      set dscp 4
     class peak-high
      set dscp 5</pre>
</p>
<p>To convert these policies into actual rate limiting we set <em>rate-limit</em> rules matching the defined DSCP values on the ADSL interface, which for me is <em>Dialer0</em>.</p>
<p><em>rate-limit</em> expects three numbers: a target bitrate, a normal burst rate and a maximum burst rate.  Cisco recommend setting the normal parameter as 1.5/8 x the target and the maximum as twice the normal.  So for the 128kbps profile (DSCP 3) the numbers are 128000 24000 48000.  If in doubt just multiply the target rate by 0.1875 for the second number and then double it&#8230;</p>
<p>
<pre>    interface Dialer0
     rate-limit input dscp 1 64000 12000 24000 conform-action transmit exceed-action drop
     rate-limit input dscp 2 32000 6000 12000 conform-action transmit exceed-action drop
     rate-limit input dscp 3 128000 24000 48000 conform-action transmit exceed-action drop
     rate-limit input dscp 4 256000 48000 96000 conform-action transmit exceed-action drop
     rate-limit input dscp 5 1024000 192000 384000 conform-action transmit exceed-action drop</pre>
</p>
<p>Actually there is one more thing.  As it stands the configuration won&#8217;t have any effect.  We have to apply the service policy to the interface for the magic to happen.</p>
<p>
<pre>    interface Dialer0
     service-policy input peak</pre>
</p>
<p>Initial testing suggests that this works.  A Steam download at peak time claims to run at 7kBps and at 800kBps at off-peak.  Temporarily adding a line to the peak time range allows easy testing when the actual time is off-peak.</p>
<p>I&#8217;m sure I&#8217;ll need to tweak the download rates and/or move protocol definitions around as real life usage patterns become apparent but the underlying concepts work well enough.</p>
]]></content:encoded>
			<wfw:commentRss>http://stuff.iain.cx/2010/07/11/cisco-877-download-rate-limiting/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Automount trickery, submounts, cross-platform stuff etc</title>
		<link>http://stuff.iain.cx/2010/05/12/automount-trickery-submounts-cross-platform-stuff-etc/</link>
		<comments>http://stuff.iain.cx/2010/05/12/automount-trickery-submounts-cross-platform-stuff-etc/#comments</comments>
		<pubDate>Wed, 12 May 2010 21:48:23 +0000</pubDate>
		<dc:creator><![CDATA[iain]]></dc:creator>
				<category><![CDATA[Geekiness]]></category>

		<guid isPermaLink="false">http://stuff.iain.cx/?p=250</guid>
		<description><![CDATA[Hands up if your home directory is full of crap. Mine is. It has junk going back to 1999. As a measure of just how much junk I have let me tell you that at time of writing my home directory is 20Gb in size. In addition to having eleven years&#8217; worth of files that [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Hands up if your home directory is full of crap.  Mine is.  It has junk going back to 1999.  As a measure of just how much junk I have let me tell you that at time of writing my home directory is 20Gb in size.  In addition to having eleven years&#8217; worth of files that I never got round to deleting, a large chunk of that disk usage comes from my Mac in the form of the <em>Library</em> subdirectory which contains pretty much everything Macs need in a user account as well as my Firefox and Thunderbird profiles.  Needless to say these are huge.</p>
<p>In fact my home directory is only as small as it is because I moved a wodge of files to a separate storage area.  The Documents directory, in which my Mac wants to save &#8230; pretty much anything &#8230; is actually a symlink to <em>/files/iain/Documents</em> which is automounted from somewhere else.  And since my documents are the kind of things which I like to have available all over the place, that same directory is also shared by Samba and my Windows roaming profile knows to go there when I try to open (My) Documents.  Some other directories are similarly shared across operating systems, including Desktop, Pictures and Movies.</p>
<p>I&#8217;d been thinking for a while that it might be better to move these well-known file stores into their own separate ZFS filesystems on my fileserver.  Things came to a head this very evening when I downloaded <a href="http://steampowered.com/">Steam</a> for Mac only to have it refuse to install because <em>Library/Application Support/Steam</em> wasn&#8217;t on a case-insensitive filesystem.  It occurred to me that if <em>Library</em> were its own filesystem as I&#8217;d been considering, I could make it case-insensitive <em>and</em> trim the size of my home directory by a considerable margin.  Although I wouldn&#8217;t advocate actually doing it in so crude a way, I believe that a home directory should be small enough that if you were given a UNIX account on a new system you should be able to get yourself up to speed by quickly transferring your entire home area from another environment.  A home directory should be for dotfiles, SSH keys and the like.  Everything else (real documents) should go Somewhere Else.</p>
<p>Since I use the <a href="/index.php?s=automount">automounter</a> for everything I figured this would be pretty simple.  As it turns out it actually is.  The syntax works with Mac, Solaris and Linux as is documented to a greater or lesser extent in each system&#8217;s AutoFS manpages.  The only potential stumbling block was getting it to work with LDAP but ended up being just as simple as you might hope.</p>
<p>The syntax to have the automounter mount a subdirectory of a configured mount is as follows, in <em>auto.home</em> for instance:</p>
<p>
<pre>    * / files:/export/home/&#038; /Library files:/export/library/&#038;</pre>
</p>
<p>So for all x <em>/home/x</em> will be mounted from <em>fileserver:/export/home/x</em> and <em>/home/x/Library</em> will be mounted from <em>fileserver:/export/library/x</em>.</p>
<p>On Linux I found I didn&#8217;t need the initial / by itself but both Mac and Solaris didn&#8217;t work without it.  Another gotcha was that the <em>Library</em> directory had to actually exist in the original directory for it to be mounted from the specified location.  In other words it wasn&#8217;t sufficient to export <em>/export/home/iain</em> and <em>/export/library/iain</em> from my file server.  I also needed to create <em>/export/home/iain/Library</em> for it to be mounted.</p>
<p>In LDAP speak my <em>auto.home</em> became:</p>
<p>
<pre>    dn: cn=/,ou=auto.home,ou=mounts,dc=iain,dc=cx
    objectClass: automount
    cn: /
    automountInformation: -fstype=nfs,tcp,rw,intr / files:/export/home/&#038;
     /Library files:/export/library/&#038;</pre>
</p>
<p>To automount more subdirectories it suffices to add more bits to the automount entry.</p>
<p>
<pre>    dn: cn=/,ou=auto.home,ou=mounts,dc=iain,dc=cx
    objectClass: automount
    cn: /
    automountInformation: -fstype=nfs,tcp,rw,intr / files:/export/home/&#038;
     /Library files:/export/library/&#038; /Documents files:/export/documents/&#038;</pre>
</p>
<p>And by redirecting my Windows shell folders to point to these filesystems in their CIFS form I can share them between operating systems.</p>
]]></content:encoded>
			<wfw:commentRss>http://stuff.iain.cx/2010/05/12/automount-trickery-submounts-cross-platform-stuff-etc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NSSM 2.3</title>
		<link>http://stuff.iain.cx/2010/04/21/nssm-2-3/</link>
		<comments>http://stuff.iain.cx/2010/04/21/nssm-2-3/#comments</comments>
		<pubDate>Wed, 21 Apr 2010 23:15:42 +0000</pubDate>
		<dc:creator><![CDATA[iain]]></dc:creator>
				<category><![CDATA[Geekiness]]></category>

		<guid isPermaLink="false">http://stuff.iain.cx/?p=221</guid>
		<description><![CDATA[I&#8217;m running final tests on, and will soon release, NSSM 2.3. NSSM &#8211; the Non-Sucking Service Manager &#8211; was originally written as a replacement for the venerable srvany, a tool which allows you to install any application as a Windows NT service. The new release will fix some bugs and add a new feature which [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m running final tests on, and will soon release, <a href="http://iain.cx/src/nssm/">NSSM</a> 2.3.  NSSM &#8211; the Non-Sucking Service Manager &#8211; was originally written as a replacement for the venerable <em>srvany</em>, a tool which allows you to install any application as a Windows NT service.</p>
<p><span id="more-221"></span></p>
<p>The new release will fix some bugs and add a new feature which may be of benefit to some users who were trying to use NSSM in a way contrary to its original design.  I&#8217;m posting here to respond to some criticism of NSSM I&#8217;ve read on the internet and to talk a bit about how it&#8217;s evolved.  A more objective discussion about how the tool works is more appropriate for its homepage, hence my choice of a blog post for this theme.</p>
<p>It&#8217;s been a source of pride to me that NSSM has carried on trucking for several years now without any updates.  When you see a project which hasn&#8217;t had a release in years and years you can either look at it as an abandoned project or a stable one.  It&#8217;s nice to know that people are still downloading it and finding it useful so long after it was originally written.</p>
<p>This brings me to the criticism I mentioned.  I read a piece whose author described what he saw as a &quot;disadvantage&quot; of NSSM, namely its behaviour when the monitored application exits.  The author thought that it was a waste of time and symptomatic of a Not-Invented-Here attitude to detect application failure and restart it.  He argued that the existing ability of Windows to take service recovery action should be used instead.</p>
<p>This got me thinking.  I&#8217;m not averse to criticism and I do try not to reinvent wheels so I considered the point carefully.  The conclusion I drew was that it&#8217;s been so long since NSSM was originally written that people may have forgotten the problem it was designed to solve.  That&#8217;s not necessarily a bad thing, as it implies that the problem may have gone away.  Join me, then, as we walk down memory lane and meet <em>srvany</em>&#8230;</p>
<h3>Freelancer and srvany</h3>
<p>Back in 2003 I was playing <em>Freelancer</em>, an enjoyable space trading/combat game where you flew around fighting off pirates, running trade routes through the galaxy, making money and upgrading your ship.  You could play multiplayer over the internet and there was a dedicated server which enabled you to disconnect and reconnect to find your character and ship intact.  It only lacked a truly persistent world with thousands of players, rather than five or six to be an awesome MMO.  Indeed even now when any space MMO is released nowadays I find myself lamenting how much cooler it would be if the developers had just taken <em>Freelancer</em> and made it bigger instead of building their own game from scratch.</p>
<p>But I digress.</p>
<p><em>Freelancer</em> was a lot of fun and had a lot going for it.  What it didn&#8217;t have going for it was its dedicated server stability.  That thing would crash and burn and it wasn&#8217;t pretty.  People wanted to run it as an NT service so their friends could connect to the game without someone having to connect to the server machine and start it up.  In those days if you wanted to run a service more or less your only choice was <em>srvany</em>.</p>
<h3>All about services</h3>
<p><em>srvany</em> is a tool provided by Microsoft which allows you to take any application and run it as a service.  It may be instructive to talk about services.  They have a special API and must behave it specific ways.  You can&#8217;t just whack in any old application and say &quot;you&#8217;re a service&quot; &#8211; you need to implement particular routines in the source code for your program.  <em>srvany</em> does the service manager interaction for you.  It implements the necessary functionality to run as a service itself and launches your application in a separate process.  So whilst <em>Freelancer</em> doesn&#8217;t know how to be a service, <em>srvany</em> does, and it knows how to run <em>Freelancer</em>.</p>
<h3>The bad news</h3>
<p>The problem with <em>srvany</em> is that it is somewhat unsophisticated.  Yes, it knows how to be a service.  Yes, it knows how to run your application.  But that&#8217;s about it.  It doesn&#8217;t know what to do if your application crashes and, as I already mentioned, <em>Freelancer</em> would indeed crash.</p>
<p><em>srvany</em> would start up, register itself with the service manager, launch <em>Freelancer</em> and go to sleep.  Then <em>Freelancer</em> would crash and <em>srvany</em> would stay asleep.  As far as Windows was concerned, everything was fine.  <em>srvany</em> was still running which means everything&#8217;s good.  Except that everything wasn&#8217;t good because the thing you actually wanted to run wasn&#8217;t running at all.</p>
<h3>The evolution of NSSM</h3>
<p>This is where NSSM comes in.  It&#8217;s an abstraction of a tool I wrote called <a href="http://iain.cx/articles/flmonitor/">flmonitor</a> which was designed to run <em>Freelancer</em> as a service by doing exactly what <em>srvany</em> did except that if <em>Freelancer</em> died it would start it up again.  Remove the hardcoded execution path of <em>Freelancer</em> and throw in a simple GUI to allow the user to choose which program to monitor and you have NSSM, a clean-room reimplementation of <em>srvany</em> which didn&#8217;t fall in a heap if the program you servicified happened to crash.</p>
<p>All these years later the criticism is made that it isn&#8217;t NSSM&#8217;s job to go around restarting services; that should be left to Windows itself.  I take the point.  In an ideal world NSSM wouldn&#8217;t have to restart things.  Unless you remember how it was back in 2003, however, you may not realise that saying &quot;Windows will restart my service when it fails&quot; doesn&#8217;t help you much if Windows thinks your service hasn&#8217;t failed.  Not to mention that service recovery actions, though they are not a new thing and were available back then, still need to be manually configured.  NSSM solved a real problem and as a nice side effect gave you some useful functionality that you&#8217;d otherwise have to go out of your way to get.</p>
<p>Nonetheless the point stands and NSSM 2.3 features the ability to configure what NSSM does when the monitored program exits.</p>
<p>So as not to give an unwanted surprise to people who are used to its original functionality, NSSM&#8217;s default behaviour will still be to restart a failed application just like it always did.  It can be configured, however, to do one of two other things.  First of all it can ignore the failure and carry on running.  In this sense it will act exactly like <em>srvany</em>.  Useful for nostalgics or for people who want to run a service once at startup.  Indeed I&#8217;ve received a handful of emails over the years from people trying to use NSSM to run a batch job when their machine boots up, only to find that after the batch script runs NSSM will run it again, spamming the system with batch jobs and eating CPU.  If you really want to do this with NSSM you now can.</p>
<p>The other option is for NSSM to tell the service manager that it is stopping when the monitored application exits.  This means that you can then configure the service recovery options in Windows and have the operating system restart your service or run a custom script which you could never reliably get to work with <em>srvany</em>.</p>
<p>As an added bonus NSSM will let you configure different actions depending on the exit code of the application it runs.  You could do stuff like exit if the job ran successfully or restart it if it failed, for example.</p>
<h3>Bug fixes</h3>
<p>Finally there are some bug fixes.  I&#8217;ve fixed a longstanding complaint whereby NSSM&#8217;s messages to the event log were prefixed by a blurb from Windows about missing a messages file.  Anyone who&#8217;s tried to use <code>FormatMessage()</code> and <code>ReportEvent()</code> to interact with the event log knows what a monumental hassle it is to do so correctly.  Anyone who hasn&#8217;t can take my word for it.  In any case I got round to doing The Right Thing and NSSM&#8217;s log messages are now less cluttered and more elegant.</p>
<p>Lastly an issue reported to me on these very pages by Joel Reingold has been fixed.  Running applications with <em>really really long</em> command lines now works properly.</p>
]]></content:encoded>
			<wfw:commentRss>http://stuff.iain.cx/2010/04/21/nssm-2-3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
