dweb: a lightweight portable webserver in C

I've been continuing to experiment with the source code to 'nweb' (a minimal web server written in C). In fact, I've probably experimented so much that I've changed most of the code beyond recognition by now. But I'm still calling my version 'dweb' in honour of the original.

Since the C# webserver I wrote ages ago has proved quite popular, I thought that I'd try something similar in C. I realised that I should be able to produce a lightweight little web server, which could also be a starting point for some other things I have in mind. Since I'm not using any external libraries, there are no dependencies to worry about. Well, OK I have used the POSIX thread library, but it can be taken out by changing a #define.

I'm attempting to make something which can easily be adapted, where you simply need to write a function which assembles your html response and everything else is done for you. So I'm making use of C function pointers for that. All you need to do is write your custom "responder" function (using the correct signature) and then call my webserver function, passing in a pointer to your own responder function.

That way, by adding a single C file to a project and writing a few lines of code you can have an embedded web server - albeit a very simple one of course.

Obviously I'm not attempting to write a fully featured web server platform, but this is the type of hobbyist project you could run on a Raspberry Pi to create a very simple web interface for something, whilst keeping it very lightweight and low on dependencies. It might work on different types of embedded Linux too (I'd be quite interested to know if it does).

But for my purposes, it will be an easy way to provide a simple web based API, where I can send commands with an http POST or just retrieve data by sending a GET.

But my main aim was to make a custom webserver possible in C with just a few lines of additional code. Being portable, it should run on Mac OS X, Linux (including Android) and even Windows if Cygwin is installed. It certainly worked OK on the Raspberry Pi and I've also used it on my Android tablet.

Since I've included support for HTTP POST (which nweb didn't have) it means that simple form posting scenarios will work, and Ajaxy type stuff should even work. The example code I've written allows HTML form values to be submitted. It also includes a simple Ajax call where a parameter is sent to the server and a return value comes back in the response.

So how does the code look? Well, here is the simplest (trivial) implementation:

void test_response(struct hitArgs *args,
   char *path, char *request_body, http_verb type)
{
    ok_200(args,
        "<html><head><title>Test Page</title></head>"
        "<body><h1>Testing...</h1>This is a test response.</body>"
        "</html>", path);
}

int main(int argc, char **argv)
{
    if (argc != 2 || !strcmp(argv[1], "-?"))
    {
        printf("hint: dweb [port number]\n");
        exit(0);
    }
    dwebserver(atoi(argv[1]), &test_response, NULL);
}

Not too bad - but it just gives the same response to every incoming request. The full source code includes more advanced examples showing an HTML form posting back some values. It also shows an Ajax call using jQuery.

Like 'nweb', it started out as a multi-process server, where each request spawned a new process using fork(). But I am now including support for single-threaded and multi-threaded modes as well, the default being multi-threaded.

Anyway, the source code is on GitHub, if you're interested (released under the MIT license). Meanwhile, I'll keep tinkering with it...

Islay Woolen Mill

During our recent holiday to Islay we visited the Islay Woolen Mill. In fact we visited it twice, so it must have been good. Not only is it cool to see the old machines working away, but Mr Covell will probably tell you a few stories if you start chatting to him.

You may also end up spending some money though. Vicky and I came out looking like this:

As you can see, I bought a hat, scarf and waistcoat. I also picked out some fabric and am having a second waistcoat made just for me. This is what happens when you get over enthusiastic about things being made the old fashioned way I suppose...

I was quite amazed that they managed to keep the oily bits of the old machines away from the bits where the fabric was being made - you really don't want oil stains on your tartan.

Anyway, it was one of those things that I enjoyed much more than I expected. So if you go to Islay, check it out.

I also enjoyed listening to Mr Covell's interest in newer technology, he was telling me that as a textile manufacturer the humble spreadsheet was one of the most wonderful inventions ever.

Island of drams

We've been back to Islay again (an island in the Hebrides) and had a fantastic time. The weather was just perfect, which even took the locals by surprise. Quite a few of them were quite literally red faced ... with sunburn. So we came back from Scotland with a suntan, which was quite unexpected.

Islay has some amazing beaches, which were very quiet, especially considering it was a bank holiday weekend. We went to a 2km stretch of sandy beach on a lovely sunny day and only had to share it with a handful of other people. It looked empty:

Of course we also visited a few of the distilleries - we were even treated to a private mini-tour of Laphroaig when we missed the official tour. It's really amazing that a company which makes that much whisky can still feel like a family business. They are extremely hospitable at Laphroaig if you visit them. When we walked back to our accommodation later that day, one of the distillery workers recognised us and stopped to offer us a lift in his car!

We stayed at the excellent Old Excise House, just outside Port Ellen (and within easy walking distance from Laphroaig). It's the same place we stayed last year. The accommodation is really excellent:

...and the breakfasts are truly amazing. So I'm sure we'll go back again.

At some point I need to mention the Islay Woollen Mill, but that's a whole separate blog entry.

Lubuntu 13.10 on Toshiba

My old Toshiba Satellite T130 laptop has been pretty much abandoned since I've switched to a MacBook Pro. But it's a shame to have an unused piece of kit. So I decided to use the Toshiba T130 for messing about with different Linux distros. As a test I tried to install Debian 7, but it looked like it was going to be a real pain to get the built in wifi adapter to work, so I gave up.

Then I tried Lubuntu 13.10, which worked a treat. All the hardware seems to have good driver support (even the built in Bluetooth). If anything, the driver support is better than Windows 7 or 8. So installation was very simple and painless.

So I'm very impressed. The machine is nice and responsive and everything is easy to find in the user interface. It's almost like having a new laptop (well OK, you'd have a hard job getting me to part with my MacBook actually).

Since then, I've even tried installing Lubuntu on my Acer Iconia Tab W500. The result is that the machine works fine as a laptop, but you couldn't really use it as a tablet (not without a lot of configuring anyway). Umm, experimenting with Linux distros on one laptop has led to me wiping another; you need to be careful with these types of experiment I guess...

But ... if you have an old machine sitting around doing nothing, and you want to get some more use out of it (without costing any money) then installing Lubuntu might be a good thing to try.

Music by numbers

I wanted to use a Raspberry Pi to play some songs (mp3s) through a very simple interface. Something where you can just type in a number and a corresponding mp3 file would play. This is what I've come up with:

The songs play with mpg321, a simple and lightweight mp3 player. I've used a spare "Dream Cheeky" LED display to show which mp3 is being played (by number). Obviously in the photo shown above there is nothing plugged into the audio socket ... but it was easier to take the picture this way.

The LED display is driven by the excellent dcled utility which works perfectly on the Raspberry Pi. A cheap numeric keypad allows input (although I have also made a web-based interface too).

I'll probably describe some of the software in more detail, when I have time.

Essential Travel Items

We've recently enjoyed a fantastic holiday in Fuerteventura (near the resort of Jandia). A brilliant place to relax, and it's on a 30km stretch of beautiful sandy beach. The weather was fantastic too (it's often a bit breezy on Fuerteventura but we don't mind that).

The view from our balcony was quite nice too:

When travelling, I carry a bag to keep my Camera, Kindle, Tablet, etc... in, but it greatly amuses my wife that I also carry: graph paper, a variety of pens, a ruler, and a protractor. I view this as entirely sensible, since at any moment I may decide I need to draw some kind of diagram.

Now, I don't actually use graph paper or a protractor very often when I'm on holiday, but I still like to carry them... just in case. I find it strangely comforting. Is that weird?

Having said that, I also make sure I have a C compiler on my tablet these days, which is actually quite likely to see gentle use during a holiday. That probably is weird, but I'm happy to accept that.

For example, during this holiday I wrote some C helper functions to make it easier to allocate resizable blocks of memory. Basic boilerplate stuff, but I enjoy tinkering with things like that...

No kill switch on Awesome

Most years I buy a Dilbert calendar for my desk. For some reason, I've kept the title page for the 2014 calendar:

It's now heading towards the end of February and I've still kept it. I don't really know why, but it keeps making me smile. So I thought that I'd post it here, enjoy.

Messing about with Ncurses

For a long time I've been aware of Ncurses, but I've never actually used it. So when I accidentally wandered across this tutorial for using Ncurses in Xcode, I decided that it would be worth checking out.

But, when I found myself with a few spare minutes... I was sitting in front of a machine running Debian Linux rather than Mac OS X. So I experimented there instead. To get the snakey program to run I had to do the following:

  1. First of all, I had to get the ncurses stuff:
    sudo apt-get install libncurses5-dev

  2. Then I had to compile the example code (I had renamed the program to box.c):
    gcc box.c -lncurses -o box

  3. Then finally, I could run it:
    ./box

So that was pretty easy. Ncurses is one of those things that I'd like to mess about with some more, because I still like running stuff in a console window.

More hudl notes

So, after fiddling with my Tesco hudl for a reasonable amount of time, here are some more of my thoughts... In fairness I should state that the other tablet I've used a lot is an iPad mini, so that tends to be what I'll naturally compare it to.

So here goes:

  • standby mode on the hudl uses much more battery than I'm used to with the iPad mini. You're much better off shutting down the hudl when you're not using it for a while. It will make a big difference if you shut your hudl down at night, for example.
  • the software feels a little more flaky than the iPad ... the hudl has frozen up a couple of times and needed a reboot.
  • it doesn't always reconnect to wifi automatically if you have been out of range. I've had to manually reconnect to my home wifi a few times.
  • you can hide most of the Tesco stuff quite easily, so you don't need to have Tesco in your face if you don't want it (which is what I've done).
  • some people say the touchscreen is not as responsive as an iPad ... but I've not noticed too much. Although gestures, like swiping across the screen seem slightly more difficult to achieve than on an iOS device. But it hasn't caused me any problems.
  • the on-screen keyboard / predictive text can be annoying sometimes. But maybe I just need to get used to it.
  • the hudl always seems to make a startup sound... even when you've silenced everything else. If you boot up your hudl then be prepared to advertise it :-(
  • overall, I have no major complaints considering the price, I think the hudl is a good value little tablet.

When I have a choice I tend to revert back to the iPad mini, but I am much happier dragging the hudl around Cambridge in my bag. So far, the hudl is doing exactly what I wanted... so I'm generally impressed.

Bluetooth Speaker: Minx Go

A while back (probably towards the end of 2012 in fact) I saw one of those Bose SoundLink bluetooth speakers being demonstrated. I was pretty impressed and made a mental note that it would be a cool thing to buy. Since my phone/tablet/laptop all have bluetooth, it makes sense to be able to beam out some nice quality sounds from them. If nothing else, it's a bit like having a hi-fi in every room of your house, you can just carry the speaker round with you.

Anyway, now I've finally decided to get one there seems to be a lot more choice, and there are some cheaper alternatives that still give good sound quality.

So I've bought a Minx Go made by Cambridge Audio. It's quite an impressive thing and has worked with every bluetooth device I've got. It also means that if we're watching BBC iPlayer on my MacBook, then I can enjoy nicer sound quality.

The Minx Go is a bit bigger than the Bose one, but that doesn't matter to me... It was quite a lot cheaper though.

But despite the cheaper price, the sound quality still seems excellent as evidenced by the review in What Hi-Fi found here where it receives top marks. It especially gives nice bass for a relatively small unit I reckon.

Of course, other bluetooth speakers are available, but I have to say I'm quite happy with my choice.