Bluish Coder

Programming Languages, Martials Arts and Computers. The Weblog of Chris Double.


2011-08-08

WDCNZ HTML Media Presentation

Last month I went down to Wellington to give a joint talk at the WDCNZ conference. The topic was "HTML Media: Where we are and where we need to go". The talk was shared between Nigel Parker, Mobile and Developer Evangelist for Microsoft, and myself. The conference was excellent with some great speakers and talks.

Nigel and I covered using HTML video and audio elements and how they can be used today across multiple browsers and mobile devices. We also covered upcoming API's and directions in the web media area. Demo's were shown on Microsoft Internet Explorer 9, Windows Phone 7 (running the Mango update which has a browser that supports HTML media) and Firefox. Nigel has slides and a summary in his blog post about the talk. I think it took a bit for attendees to get over the shock over a Mozilla and Microsoft representative sharing the stage and working together! Nigel's post explains how this came about.

I spoke to a few Kiwi developers afterwards about using HTML video and there was a fair bit of interest in using it. The main obstacles seemed to be people unsure what codec to use and wanting support for adaptive streaming. The first is an education issue, getting people aware of what codecs to support for maximum coverage across browsers and how to encode to those formats. With regards to adaptive streaming there has been discussion between interested parties in various mailing lists and groups - it's definitely something that is wanted.

At the time of the talk Nigel and I weren't able to find any existing New Zealand based sites that use HTML video. Hopefully this will change in the future and Microsoft New Zealand are leading by example by using HTML video on their own site.

Tags: mozilla  video 

2011-05-12

Namecoin - A DNS alternative based on Bitcoin

Namecoin is a domain name system based on Bitcoin. It extends Bitcoin to add transactions for registering, updating and transferring names. The idea behind this is to provide an alternative to the existing DNS system where names can be taken from their owners by groups that control the DNS servers.

The project was originally announced in the bitcoin forums and has seen some uptake. The namecoin author, vinced, states in the post:

  • This is a new blockchain, separate from the main Bitcoin chain
  • Name/value pairs are stored in the blockchain attached to coins
  • Names are acquired through new transaction types - new, first-update and update
  • Names expire after 12000 blocks unless renewed with an update
  • No two unexpired names can be identical
  • Block validation is extended to reject transactions that do not follow the above rules
  • The code is here: https://github.com/vinced/namecoin

A number of projects have been created around this to provide a mapping from namecoin names to standard DNS. This allows resolving namecoin names to a '.bit' suffixed domain. I'll go through building the namecoin software, registering and updating names, then the software to use these names.

Building Namecoin

Namecoin needs to be built from source. The following steps on a Linux based system will build without UPNP support:

$ git clone git://github.com/namecoin/namecoin.git
$ cd namecoin
namecoin $ make -f makefile.unix USE_UPNP=

Once built you'll need to create a ~/.namecoin/bitcoin.conf file that contains entries for a username and password used for the JSON-RPC server that namecoind runs. Notice the name of the .conf file is bitcoin.conf even though this is namecoind. It won't clash with an existing bitcoin installation as it is in a ~/.namecoin directory. To prevent conflict with an existing bitcoin install I suggest running namecoind on a different port. An example ~/.namecoin/bitcoin.conf is:

rpcuser=me
rpcpassword=password
rpcport=9332

Running namecoind will start the daemon and you can then use namecoind to execute commands:

$ ./namecoind
bitcoin server starting
$ ./namecoind getblockcount
2167

Yes, it prints out 'bitcoin server starting'. There are still bitcoin references in the code that need to be changed apparently.

Getting Namecoins

To register a name you need to have some namecoins. These can be obtained via mining, just like bitcoins. Or you can buy them. To mine namecoins you can run any of the standard bitcoin miners and point them to the server and port that is running namecoind. The difficulty level for namecoin mining is currently very low (about 290 at the time of writing) so even CPU miners have a chance. Generating a block gets you 50 namecoins.

You can also buy namecoins as described here. The going rate seems to be about 1BTC for 50 namecoins.

Registering a name

The name_new command will register a name. An example invocation is:

$ ./namecoind name_new d/myname
[
    "1234567890123456789012345678901234567890",
    "0987654321"
]   

This will start the registration process for the name myname. Note the two hash values returned. Once this is done you need to wait for 12 blocks to be generated by the namecoin network. You then need to run a name_firstupdate command:

$ ./namecoind name_firstupdate d/myname 0987654321 '{"map":{"":"1.2.3.4"}}'

We pass to name_firstupdate the domain name we are updating, the shorter hash that we got from name_new and a JSON value that defines how that name is mapped to an IP address.

In this case the name is mapped to the IP address 1.2.3.4. Using the existing systems for mapping names this would make myname.bit resolve to 1.2.3.4. You can also do subdomains (See the update example later).

The cost to do a name_new, followed by a name_firstupdate, varies depending on how many blocks there are in the namecoin block chain. It started at 50 namecoins and slowly reduces. The formula is defined in the namecoin design document as:

  • Network fees start out at 50 NC per operation at the genesis block
  • Every block, the network fees decreases based on this algorithm, in 1e-8 NC:

      res = 500000000 >> floor(nBlock / 8192)
      res = res - (res >> 14)*(nBlock % 8192)
    
  • nBlock is zero at the genesis block

  • This is a decrease of 50% every 8192 blocks (about two months)
  • As 50 NC are generated per block, the maximum number of registrations in the first 8192 blocks is therefore 2/3 of 8192, which is 5461
  • Difficulty starts at 512

Updating a name

To update the domain mapping you use name_update:

$ ./namecoind name_update d/myname '{"map":{"":"1.2.3.4","www":"5.6.7.8"}}'

This example updates the value of myname so it includes a www subdomain. The name www.myname.bit will now map to 5.6.7.8.

There are other possibilities for the JSON mapping. See the namecoin README for details. Note that the JSON code must be valid JSON (ie. use double quotes, unlike the examples currently shown in the README unfortunately).

Transferring a name

To transfer a name to another person you need to get their namecoin address and do an update passing that address:

$ ./namecoind name_update d/myname '{"map":{"":"1.2.3.4"}}' NGZs7UndoWgpfTstoxryYEW8b1GtDLPwMa

Addresses can be generated with:

$ ./namecoind getnewaddress
N9jzzaptnQ28uiLgWm19WZAqrGqRVVGkFX

Transferring namecoins

You can transfer namecoins to other people by sending coins to their address just like bitcoin:

$ ./namecoind sendtoaddress N9jzzaptnQ28uiLgWm19WZAqrGqRVVGkFX 50

This will send 50 namecoins to N9jzzaptnQ28uiLgWm19WZAqrGqRVVGkFX.

Listing registered names

You can list all registered namecoin names using name_scan:

$ ./namecoind name_scan
{
    "name" : "d/bluishcoder",
    "value" : "{\"map\":{\"\":\"69.164.206.88\"}}",
    "txid" : "....",
    "expires_in" : 10874
},

You can also list only the names you've registered using name_list:

$ ./namecoind name_list
{
    "name" : "d/bluishcoder",
    "value" : "{\"map\":{\"\":\"69.164.206.88\"}}",
    "expires_in" : 10874
}

Using namecoin names

Software needs to be modified to use namecoind to lookup the name, or you can run DNS software that connects to namecoin to do lookups. To be able to try out namecoin I modified an HTTP proxy and later tried using DNS software.

HTTP Proxy

I modified the Polipo web proxy to use namecoin for lookups. The modified source is available at https://github.com/doublec/namecoin-polipo. This can be built and run with:

$ git clone https://github.com/doublec/namecoin-polipo
$ cd namecoin-polipo
$ make
$ ./polipo namecoindServer="127.0.0.1:9332" namecoindUsername=rpcuser namecoindPassword=rpcpassword

Changing your browser to point to the proxy on localhost, port 8123, will allow .bit domains to be used. See my forum post about it for more details.

dnsmasq

Another approach I tried was to write a program that generates a 'host file' from namecoind and uses dnsmasq to run a local DNS server that serves domains from this host file, falling back to the standard DNS server. The 'quick and dirty' code to generate the hosts file is in namecoin-hosts.c and uses libcurl and libjansson to build:

$ gcc -o namecoin-hosts namecoin-hosts.c -lcurl -ljansson

I added the following to my dnsmasq.conf:

local=/.bit/
local-ttl=300
addn-hosts=/tmp/hosts.txt

And created a shell script to update /tmp/hosts.txt with the namecoin related data:

while true; do
  ./namecoin-hosts 127.0.0.1:9332 rpcuser rpcpassword >/tmp/hosts.txt
  kill -HUP `cat /var/run/dnsmasq/dnsmasq.pid`
  echo `date`
  sleep 300
done

Pointing my OS DNS resolver to the dnsmasq IP address and port allowed .bit names to resolve.

Public .bit DNS servers

Details of a public .bit DNS server that doesn't require you to run namecoin are available at namecoin.bitcoin-contact.org. That site also provides details on using namecoin.

More Information

Namecoin seems to be very much an experiment in having an alternative DNS like system. The developer has taken the approach of 'release early' and iterate towards a solution. As such it may fizzle out and go nowhere. Or it may prove a useful test-bed for ideas that make it into a successful DNS alternative.

More details about Namecoin can be obtained from:

Are there any other alternatives to DNS around with similar ideas?

Tags: namecoin  bitcoin 

2011-05-11

Building Mozart/Oz on Windows

The Mozart Programming System is an implementation of the Oz programming language. It's the language used in the book Concepts, Techniques, and Models of Computer Programming by Peter Van Roy and Seif Haridi. From the Mozart website:

Mozart is based on the Oz language, which supports declarative programming, object-oriented programming, constraint programming, and concurrency as part of a coherent whole. For distribution, Mozart provides a true network transparent implementation with support for network awareness, openness, and fault tolerance. Mozart supports multi-core programming with its network transparent distribution and is an ideal platform for both general-purpose distributed applications as well as for hard problems requiring sophisticated optimization and inferencing abilities.

The last release of Mozart was a couple of years ago and the steps to build on Windows no longer seem to work. It required Cygwin to build but used the MingW compiler to get a native Windows build.

Mozart/Oz has recently seen a bit of a life with activity in the mailing lists and a move to github for source control and issue tracking. I was working on a project that needed Windows and Linux support so thought I'd have a try at converting Mozart to compile using MingW on Windows.

I've got a basic build working and have patches that I hope will eventually be merged. In the meantime I thought I'd post about how to build using MingW with my patches. The following steps will build Mozart, the standard library, Emacs (used as the IDE) and Tcl/Tk (for GUI).

  1. Download and install mingw-get-inst. Install the 'MSYS Basic System' and the 'C++ Compiler'.
  2. From the 'MingW Shell', run the following commands to install the required support packages:

     $ mingw-get install mingw32-libgmp
     $ mingw-get install mingw32-gmp
     $ mingw-get install mingw32-libz
     $ mingw-get install msys-libgdbm
     $ mingw-get install msys-libregex
     $ mingw-get install mingw32-autoconf2.1
     $ mingw-get install mingw32-autoconf
     $ mingw-get install msys-flex
     $ mingw-get install msys-bison
     $ mingw-get install mingw32-gcc-g++
     $ mingw-get install msys-wget
    
  3. Download and install the msysgit package. I installed it in C:/git. It's best to install it in a directory that doesn't have spaces in the name.

  4. Make a directory to store the resulting 'Mozart/Oz' binaries. I used /p to keep my command lines short but you could also use /mingw to install alongside the existing MingW programs:

     $ mkdir /p
    
  5. Download and build Tcl/Tk 8.5 from source, configured to install in the directory above:

     $ wget http://prdownloads.sourceforge.net/tcl/tcl8.5.9-src.tar.gz
     $ wget http://prdownloads.sourceforge.net/tcl/tk8.5.9-src.tar.gz
     $ tar xvf tcl8.5.9-src.tar.gz
     $ tar xvf tk8.5.9-src.tar.gz
     $ cd tcl8.5.9
     tcl8.5.9 $ ./win/configure --prefix=/p
     tcl8.5.9 $ make && make install
     tcl8.5.9 $ cd ../tk8.5.9
     tk8.5.9 $ ./win/configure --prefix=/p --with-tcl=`pwd`/../tcl8.5.9
     tk8.5.8 $ make && make install
    
  6. Download and build emacs from source:

     $ wget http://ftp.gnu.org/gnu/emacs/emacs-23.3.tar.gz
     $ tar xvf emacs-23.3.tar.gz
     $ cd emacs-23.3
     emacs-23.3 $ cd nt
     emacs-23.3/nt $ cmd /c "configure --prefix=/p --without-xpm \
                      --without-png --without-jpeg --without-tiff --without-gif"
     emacs-23.3/nt $ make && make install
    
  7. Build my win32_build branch of Mozart. Note that I add the directory where I installed Git into the path. I also add the 'bin' directory of where I set Mozart to be installed.

     $ export PATH=$PATH:/c/git/bin:/p/bin
     $ git clone git://github.com/doublec/mozart.git
     $ cd mozart
     mozart $ git checkout -b win32_build origin/win32_build
     mozart $ cd ..
     $ mkdir build
     $ cd build
     build $ windlldir=/p ../mozart/configure --prefix=/p \
              --with-inc-dir=/p/include --with-lib-dir=/p/lib \
              --with-tcl=/p --with-tk=/p --disable-contrib-compat \
              --disable-contrib --enable-modules-static \
              --disable-doc --disable-chm
     build $ make && make install
    
  8. Build my win32_build branch of the Mozart standard library:

     $ git clone git://github.com/doublec/mozart-stdlib.git
     $ cd mozart-stdlib
     mozart-stdlib $ git checkout -b win32_build origin/win32_build
     mozart-stdlib $ cd ..
     $ mkdir build-stdlib
     $ cd build-stdlib
     build-stdlib $ ../mozart-stdlib/configure --prefix=/p
     build-stdlib $ make && make install
    
  9. You can now test Mozart by running the comand oz. This should start emacs with a Mozart/Oz system running. You can evaluate an example by entering {Browse 1+1} into the topmost emacs pane and evaluating with Ctrl+. Ctrl+l. You'll need to set the OZEMACS environment variable to point to the location of emacs:

     $ export OZEMACS=/p/bin/emacs.exe
     $ oz
    

That's a large number of steps but it gives a complete Mozart/Oz environment. From there you can work through the tutorial. There's work to be done to make it easier and get more testing. One contributor is looking at creating a Visual Studio project to do the builds as well as to improve on the basic MingW support I've got working, so there's hope for less steps in the future.

The Mozart/Oz system is interesting and there's some neat projects written in it. A short list of some of them:

  • BeerNet, a P2P network.
  • TransDraw, a distributed shared drawing program. I run a live transdraw instance which you can connect too. Instructions here.
  • Roads, a web application framework.
  • EBL/Tk, an UI library that can do migration of user interface elements across the network.
Tags: mozartoz 

2011-04-25

Sharing Linear Resources in ATS

My previous post on converting C programs to ATS had an example of passing a linear resource to a callback function. The code looked like:

typedef evhttp_callback (t1:viewtype) = (!evhttp_request1, !t1) -<fun1> void
extern fun evhttp_set_cb {a:viewtype} (http: !evhttp1,
                                       path: string,
                                       callback: evhttp_callback (a),
                                       arg: !a): int = "mac#evhttp_set_cb"
...
val _ = evhttp_set_cb {event_base1} (http,
                                     "/quit",
                                     lam (req, arg) => ignore(event_base_loopexit(arg, null)),
                                     base)

The base argument to be passed to the callback is an instance of a linear type:

absviewtype event_base (l:addr)
viewtypedef event_base0 = [l:addr | l >= null ] event_base l
viewtypedef event_base1 = [l:addr | l >  null ] event_base l

For some callback programming I need to pass more than one argument to the callback. I needed a way to package up a number of linear resources, pass them to the callback, and have the callback possibly consume some of them. I took a stab at solving this problem myself before asking for advice on the ats-lang-users mailing list for comments. Hongwei Xi replied with some great advice on how to deal with the issue.

I'll go through a cut down example of the callback program, my first attempt at solving it, and then onto a solution based on Hongwei's reply.

Callback example

The following program, callback1.dats (pretty-printed html) is a small test case for the callback program where I pass one linear resource to the callback as in my libevent example referred to above. The main code body is:

absviewtype resource (l:addr)
viewtypedef resource1 = [l:addr | l > null] resource l
extern fun resource_new():resource1 = "mac#resource_new"
extern fun resource_use(r: !resource1):void = "mac#resource_use"
extern fun resource_free(r: resource1):void = "mac#resource_free"

typedef callback = (!resource1) -<fun1> void
extern fun do_something(f: callback, arg: !resource1):void = "mac#do_something"

implement main() = let
  val r = resource_new()
  val () = do_something(lam (r) => resource_use(r), r) 
  val () = resource_free(r)
in
  ()
end

In this example I pass my linear object, r, to do_something along with a callback. do_something then calls the callback passing my linear object as an argument. The callback uses and does not consume the object. My next task was to tackle the issue of passing multiple linear objects. Something like:

implement main() = let
  var r = resource_new()
  var r2 = resource_new()
  val () = do_something(lam (r_and_r2) => (resource_use(r);resource_use(r2)),
                        ...want_to_pass_r_and_r2_here...)
  val () = resource_free(r)
  val () = resource_free(r2)
in
  ()
end

Linear Closure Containing Linear Types

My first attempt at passing multiple values to the callback was to use a closure as the argument to the callback function. I could then close over the multiple objects. This code is in callback2.dats (pretty-printed html). The main changes are:

viewtypedef func = () -<lincloptr1> void
extern fun do_something(f: (func) -<fun1> void, arg: func):void = "mac#do_something"

fun callback(f: func):void = let val () = f() in cloptr_free(f) end

implement main() = let
  extern prfun __borrow {l:addr}
                        (pf: ! resource1 @ l): (resource1 @ l, resource1 @ l -<lin,prf> void)
  var r = resource_new()
  var r2 = resource_new()
  prval (pf, pff) = __borrow(view@ r)
  prval (pf2, pff2) = __borrow(view@ r2)

  val () = do_something(callback,
                        llam () => let
                          val () = resource_use(r)
                          val () = resource_use(r2)
                          prval () = pff(pf)
                          prval () = pff2(pf2)
                        in () end) 
  val () = resource_free(r2)
  val () = resource_free(r)
in
  ()
end

In this code the actual callback is a function that takes as an argument another callback which takes no arguments and calls it. This new callback is a closure. The code closes over the value of r and r2 and calls resource_use on them. As r and r2 are linear resources I can't use an ordinary closure to close over them. I use a 'linear closure containing linear types' type of closure, identified by the <lincloptr1> tag in:

viewtypedef func = () -<lincloptr1> void

This tells the type system that this closure can contain references to linear resources in the enclosing scope. The other thing I have to do is use the proof system to explicitly 'borrow' the linear object from the enclosing scope. This is done using this code:

extern prfun __borrow {l:addr} (pf: ! resource1 @ l): (resource1 @ l, resource1 @ l -<lin,prf> void)
...
prval (pf, pff) = __borrow(view@ r)

The __borrow proof function takes a view to the resource and returns a new proof variable for this view along with a proof function that we need to call to return the borrowed resource. Inside the closure we call this proof function, passing it the new proof variable we got, to say that we have finished borrowing the resource. This is what this code does:

prval () = pff(pf)

If the code doesn't __borrow the resource then the type system expects the linear resources in the closure to be consumed. In this example we don't want to do that as we consume them later, outside of the closure, using resource_free. Think of __borrow as "Dear type system, I'm borrowing this resource temporarily in another function, I'll let you know when I'm done with it".

When using closures memory has to be allocated to store the enclosed environment. I discuss this in my Closures in ATS post. A linear closure has that memory automatically freed by the caller. In this case however the caller is a function implemented in C so ATS can't insert the call to free the memory. This results in a type check failure if I don't manually free the memory which is what the call to cloptr_free is doing in this code. If I was calling the callback from ATS code then I wouldn't need it and no type check error would occur. I wrote more about linear closures around linear resource in lin and llam with closures.

This example works and is flexible in that I can pass any objects along, captured within the closure. Complications arise when there are objects that need to be consumed.

Using a container dataviewtype

If I want to consume the resources I pass to the callback I can use a dataviewtype to hold the resources I pass. The code for this is in callback3.dats (pretty-printed html). The changed parts of this code are:

dataviewtype container = Container of (resource1, resource1)
typedef callback = (container) -<fun1> void
extern fun do_something(f: callback, arg: container):void = "mac#do_something"

fun mycallback(c: container): void = let
  val ~Container (r,r2) = c
  val () = resource_use(r)
  val () = resource_use(r2)
  val () = resource_free(r)
  val () = resource_free(r2)
in
  ()
end

implement main() = let
  val r = resource_new()
  val r2 = resource_new()

  val c = Container(r, r2)
  val () = do_something(mycallback, c)
in
  ()
end

In this code the Container dataviewtype holds the two resources. Ownership of r and r2 are passed to the Container. The argument for the callback is Container rather than !Container to indicate that the container itself gets destroyed. The following line does a deconstructing bind of the objects in the container to r and r2 and destroys the container (The ~ is the notation that does this):

val ~Container (r,r2) = c

Hopefully that code is easier to understand than the linear closure example previously. The next approach is how to deal with passing objects where some are to be consumed and some aren't.

Using call-by-reference

The approach here is to create a record containing the resources I want to share. I pass this record around using call by reference. The equivalent of the container example above, but using call-by-reference, is in callback4.dats (pretty-printed html). The changed code is:

viewtypedef env (l1:addr, l2:addr) = @{r1= resource l1, r2= resource l2}
viewtypedef env = [l1,l2:agz] env(l1, l2)
typedef callback = (&env) -<fun1> void
extern fun do_something(f: callback, arg: &env):void = "mac#do_something"

fun mycallback(e: &env): void = let
  val () = resource_use(e.r1)
  val () = resource_use(e.r2)
in
  ()
end

implement main() = let
  var env: env(null, null)
  val () = env.r1 := resource_new()
  val () = env.r2 := resource_new()

  val () = do_something(mycallback, env)

  val () = resource_free(env.r1)
  val () = resource_free(env.r2)
in
  ()
end

The &env syntax in the argument to a function means pass that argument by reference. In this example the linear resources are owned by the env instance and a reference to that is passed around. env is a flat record (the { says it's a record, the @ says it's flat vs ' for boxed). A flat record is like a struct in C. In fact the generated C code from ATS uses a C struct allocated on the stack.

Consuming only some resources

Extending the previous 'call-by-reference' example I show how to consume some of the resources but not others. See callback5.dats (pretty-printed html) for the full code with the changed bits below:

viewtypedef env (l1:addr) = @{r1= resource l1, r2= Option_vt (resource1)}
viewtypedef env = [l1:agz] env(l1)
typedef callback = (&env) -<fun1> void
extern fun do_something(f: callback, arg: &env):void = "mac#do_something"

fun mycallback (e: &env): void = let
  val () = resource_use(e.r1)
  val () = case+ e.r2 of
           | ~Some_vt(x) => let
                              val () = resource_use(x)
                              val () = resource_free(x)
                              val () = e.r2 := None_vt
                            in () end
           | ~None_vt () => let
                              val () = e.r2 := None_vt
                            in () end
in
 ()
end

implement main() = let
  var env: env(null)
  val () = env.r1 := resource_new()
  val () = env.r2 := Some_vt (resource_new())

  val () = do_something(mycallback, env)

  val () = resource_free(env.r1)
  val () = case+ env.r2 of 
           | ~Some_vt (x) => resource_free(x)
           | ~None_vt () => ()
in
  ()
end

For resources that can be consumed I use the Option_vt viewtype defined in the ATS prelude. This has constructors Some_vt and None_vt. The former holds a value and the latter means no value is contained. The _vt suffix is the prelude's naming standard to say that this is a viewtype. There also exists an equivalent to Option for datatypes (garbage collectable objects). We use a viewtype here since we a holding on to values that are viewtypes.

The callback uses case to check if a value is held by the record. if it is Some_vt I use the the resource, free it, and assign None_vt back to say there is no longer a resource being held. In the main body I do the same to free the resource if a resource is being held. Note the use of the ~ in the patterns to consume and free the Option_vt resources.

Summary

This final example most closely follows the way some C programs work, allocating a context object to hold semi-global objects. And passing that around as needed. What ATS buys us is the checking at compile time that these objects are correctly destroyed and not used again.

An example of this type of C program is download.c (originally based on this code) which uses libevent to read the contents of a URL via HTTP. It allocates a download_context object which contains pointers to other objects, some of which are destroyed and some are supposed to be retained. My explorations into linear resource sharing was motivated by converting this example.

Tags: ats 

2011-04-24

Converting C Programs to ATS

I tend to use ATS as a low level programming language - a better, safer, C. Often I start with a C program and slowly add ATS features as I go. I do this so I can utilize existing C code, write my higher level functionality in ATS, and slowly convert parts of the C to ATS to add compile time safety and resource utilisation checks. ATS facilitates this by allowing C to be embedded in ATS programs directly.

http-server.c

Recently I needed an HTTP server that I could embed in a program to serve simple pages and proxy requests, with modifications, to another server. I decided on using libevent since it has HTTP functionality integrated with the event system. The libevent 2 distribution has an http-server sample program and I started with a slightly modified version of that. The C sample can be compiled with:

gcc -o http-server http-server.c -levent

Running it with a path to a docroot as an argument starts an HTTP server on port 8080. Requests are served with the files from the docroot. The special URL '/dump' prints details of the request on standard output.

http-server.dats

The first step at embedding this in my ATS program was to create http-server.dats (pretty-printed html) with the same C code embedded in the ATS program. The C include files are enclosed as follows:

%{^
#include <stdio.h>
...
#include <event2/event.h>
#}

The '%{' marker tells ATS that this is C code that should be placed at the top of any compiled ATS code. The rest of the C code was embedded as-is using '%{':

%{
/* Try to guess a good content-type for 'path' */
static const char *
guess_content_type(const char *path)
{
    ...
}
...
%}

Code in beween the '%{...%}' markers is inserted in the compiled ATS code directly. I made a small change to remove the C main function and factor parts of that out into a http-server function so I could write a main in ATS that calls it. The ATS code to call the C code looks like:

extern fun syntax():void = "mac#syntax"
extern fun http_server(docroot: string):int = "mac#http_server"
exception Error of ()

implement main(argc, argv) =
  if argc < 2 then
    syntax()
  else
    if http_server(argv[1]) = 0 then () else $raise Error ()

The 'extern fun' definitions are what allows the ATS code to call the C code. Instead of providing a body for these functions I assign a string like, "mac#syntax". This tells ATS that this function is implemented in C with the name of the C function after the #. The 'mac' before the # gives instructions to ATS about how to use the C function. More on the # syntax is available in this mailing list post.

The program can be compiled and tested with:

atscc -o http-server http-server.dats -levent

There isn't much advantage in this program vs the C program. There's the slight benefit of the compile time checking that argv isn't referenced out of bounds but that's it. However, now that it's embedded in ATS we can start converting code.

http-server2.dats

The first function I tackled at converting was http_server. The resulting ATS code is in http-server2.dats (pretty-printed html). For this code I need to call libevent functions from ATS. libevent uses C structures to hold state - these structures are abstract in that C code can't look inside them. All access is via libevent functions. The structures used by http_server are:

  • event_base
  • evhttp
  • evhttp_request

libevent has functions to manage the allocation and freeing of these structures. If you've been reading my other ATS posts on safer C usage you'll know that these can be represented as abstract viewtypes. The type wrapper for event_base looks like:

absviewtype event_base (l:addr)
viewtypedef event_base0 = [l:addr | l >= null ] event_base l
viewtypedef event_base1 = [l:addr | l >  null ] event_base l

This defines event_base as an abstract view type with an address, l. It's effectively a C pointer of type event_base*. The two viewtypedef statements define aliases for an event_base type that can be NULL (event_base0) and an event_base type that cannot be NULL (event_base1). Defining these typedef's makes it easier to tell which functions accept NULL objects and which don't. It also allows defining functions without having to have universal type quantifiers everywhere (eg, the {l:addr} in function definitions). Similar wrappers are done for evhttp and evhttp_request.

event_base objects are created and destroyed with event_base_new and event_base_free. Events are dispatched using event_base_dispatch. The ATS definitions for these look like:

extern fun event_base_new(): event_base0 = "mac#event_base_new"
extern fun event_base_free (p: event_base1):void = "mac#event_base_free"
extern fun event_base_dispatch (base: !event_base1):int = "mac#event_base_dispatch"

This says that event_base_new returns a possible NULL event_base and event_base_free takes a non-NULL event_base. Abstract viewtype's are linear objects which means the compile time type system checks that they are destroyed and that they aren't used after destruction. event_base_free consumes the linear type (For it not to consume the type it would have to define the argument with a ! like p: !event_base1). You can see this in the definition of event_base_dispatch which has the ! annotation in the argument to say it doesn't consume the type.

Code to create and destroy an event_base will look like:

val base = event_base_new()
val () = assert_errmsg(~base, "event_base_new failed")
...
val _  = event_base_dispatch(base)
...
val () = event_base_free(base)

Note the assert_errmsg call. The ~ operator returns true if base is not NULL. So the assert checks that base is non-NULL and the type system tracks this. It knows that base from then on is a non-NULL pointer (ie. The event_base1 typedef). This allows it to be passed to event_base_free. Without this assert (or other check for non-NULL-ness) there would be a compile error.

Similar wrappers are done for the other libevent functions that http_server uses. evhttp_set_cb and evhttp_set_gencb are a little different however. Their C definitions look like:

void evhttp_set_gencb(struct evhttp *http,
    void (*cb)(struct evhttp_request *, void *), void *arg);
int evhttp_set_cb(struct evhttp *http, const char *path,
    void (*cb)(struct evhttp_request *, void *), void *cb_arg);

They take a C function as a callback and an argument to pass to that C function. The callback is called by libevent when a particular URL is accessed. The argument is typed as a void* but we can do better in ATS. Here's the ATS definitions:

typedef evhttp_callback (t1:viewtype) = (!evhttp_request1, !t1) -<fun1> void
extern fun evhttp_set_cb {a:viewtype} (http: !evhttp1,
                                       path: string,
                                       callback: evhttp_callback (a),
                                       arg: !a): int = "mac#evhttp_set_cb"
extern fun evhttp_set_gencb {a:viewtype} (http: !evhttp1,xi
                                          callback: evhttp_callback (a),
                                          arg: !a): void = "mac#evhttp_set_gencb"

The typedef defines an alias for referring to the callback function. It is parameterized over the type of the argument. The definition states that an evhttp_callback is a C function (the fun1, see Functions in ATS) that takes two arguments. A non-NULL evhttp_request object that is not consumed, and an object of type t1 where t1 is any viewtype. It is also not consumed. The function returns void. An evhttp_callback (event_base) is therefore a C function that takes an event_base as the second argument.

evhttp_set_cb is a polymorphic function. The arg parameter can be any viewtype. The callback paramter is a evhttp_callback parameterized over this same type. This means that the callback must accept as an argument the same type as the argument we pass to evhttp_set_cb. evhttp_set_cb and evhttp_set_gencb are called like:

 val _ = evhttp_set_cb {ptr} (http, "/dump", dump_request_cb, null)
 val () = evhttp_set_gencb {string} (http, send_document_cb, docroot)

Note that we pass the argument type (ptr and string in the example) as a static argument in the call so ATS knows which type to use in the polymorphic function. Sometimes ATS can infer this and the argument is not needed but in this case ATS' type inference can't do it. The ATS wrappers for dump_request_cb and send_document_cb are:

extern fun dump_request_cb (request: !evhttp_request1, arg: !ptr): void = "mac#dump_request_cb"
extern fun send_document_cb (request: !evhttp_request1, arg: !string): void = "mac#send_document_cb"

http-example2.dats adds an additional callback to cause the server to exit. The server exit is done by breaking out of the event loop using event_base_loopexit. That function needs an event_base so I pass this as the callback argument. In this case there is no C function to wrap so I create the callback function as an ATS anonymous function:

val _ = evhttp_set_cb {event_base1} (http,
                                     "/quit",
                                     lam (req, arg) => ignore(event_base_loopexit(arg, null)),
                                     base)

The equivalent callback function in C would need to cast the void* argument to a base_event*. I don't need to do this in ATS as the callback argument is correctly typed thanks to the definition of evhttp_set_cb and evhttp_callback as described above.

The ignore call is to help make the ATS code a bit more readable. event_base_loopexit returns an integer but the callback returns void. We need to consume the return value of event_base_loopexit. In ATS this needs to be done using the verbose syntax let val _ = ... in () end. ignore is a macro that hides this:

macdef ignore (x) = let val _ = ,(x) in () end

This version of http-server2.dats provides a little bit more type safety than the C version. It still utilizes a lot of the C code. There is no overhead from ATS - all the wrappers are defined in terms of the existing C functions. They provide additional checking at compile time, no extra run time code is generated. Although the wrappers look verbose, they'd usually be in a libevent ATS module. The resulting ATS code is a little smaller and clearer if you ignore the wrapper's the sample code includes.

Next steps

The next steps would be to start converting the existing functions, or to add extra functionality in ATS (like I did with the quit callback). I'll do a followup post on anything interesting or new found during the remaining conversion. Otherwise you might like to try it as an exercise in learning ATS.

One interesting thing to look at would be how to handle the very callback oriented libevent code. This can make code difficult to follow. Writing libevent code that does HTTP requests looks something like:

fun handle_result(result: string) = ...
...
var () = http_get("http://www.bluishcoder.co.nz", handle_result)

I much prefer something like the following and have the compiler break the code up into the callback style:

var result = http_get("http://www.bluishcoder.co.nz")

Languages that have continuations or coroutines make this sort of thing easy. It'd be nice to be able to factor code like this to be easier to read and use in ATS. If anyone has any ideas I'd love to hear them.

Tags: ats 


This site is accessable over tor as hidden service 6vp5u25g4izec5c37wv52skvecikld6kysvsivnl6sdg6q7wy25lixad.onion, or Freenet using key:
USK@1ORdIvjL2H1bZblJcP8hu2LjjKtVB-rVzp8mLty~5N4,8hL85otZBbq0geDsSKkBK4sKESL2SrNVecFZz9NxGVQ,AQACAAE/bluishcoder/-61/


Tags

Archives
Links