Category Archives: Go

Why Go gets exceptions right

How does Go get exceptions right? Why, by not having them in the first place.

First, a little history.

Before my time, there was C, and errors were your problem. This was generally okay, because if you owned an 70’s vintage mini computer, you probably had your share of problems. Because C was a single return language, things got a bit complicated when you wanted to know the result of a function that could sometimes go wrong. IO is a perfect example of this, or sockets, but there are also more pernicious cases like converting a string to its integer value. A few idioms grew to handle this problem. For example, if you had a function that would mess around with the contents of a struct, you could pass a pointer to it, and the return code would indicate if the fiddling was successful. There are other idioms, but I’m not a C programmer, and that isn’t the point of this article.

Next came C++, which looked at the error situation and tried to improve it. If you had a function which would do some work, it could return a value or it could throw an exception, which you were then responsible for catching and handling. Bam! Now C++ programmers can signal errors without having to conflate their single return value. Even better, exceptions can be handled anywhere in the call stack. If you don’t know how to handle that exception it’ll bubble up to someone who does. All the nastyness with errno and threads is solved. Achievement unlocked!

Sorta.

The downside of C++ exceptions is you can’t tell (without the source and the impetus to check) if any function you call may throw an exception. In addition to worrying about resource leaks and destructors, you have to worry about RAII and transactional semantics to ensure your methods are exception safe in case they are somewhere on the call stack when an exception is thrown. In solving one problem, C++ created another.

So the designers of Java sat down, stroked their beards and decided that the problem was not exceptions themselves, but the fact that they could be thrown without notice; hence Java has checked exceptions. You can’t throw an exception inside a method without annotating that method’s signature to indicate you may do so, and you can’t call a method that may throw an exception without wrapping it in code to handle the potential exception. Via the magic of compile time bondage and discipline the error problem is solved, right?

This is about the time I enter the story, the early millennium, circa Java 1.4. I agreed then, as I do now, that the Java way of checked exceptions was more civilised, safer, than the C++ way. I don’t think I was the only one. Because exceptions were now safe, developers started to explore their limits. There were coroutine systems built using exceptions, and at least one XML parsing library I know of used exceptions as a control flow technique. It’s commonplace for established Java webapps to disgorge screenfuls of exceptions, dutifully logged with their call stack, on startup. Java exceptions ceased to be exceptional at all, they became commonplace. They are used from everything from the benign to the catastrophic, differentiating between the severity of exceptions falls to the caller of the function.

If that wasn’t bad enough, not all Java exceptions are checked, subclasses of java.Error and java.RuntimeException are unchecked. You don’t need to declare them, just throw them. This probably started out as a good idea, null references and array subscript errors are now simple to implement in the runtime, but at the same time because every exception Java extends java.Exception any piece of code can catch it, even if it makes little sense to do so, leading to patterns like

catch (e Exception) { // ignore }

So, Java mostly solved the C++ unchecked exception problem, and introduced a whole slew of its own. However I argue Java didn’t solve the actual problem, the problem that C++ didn’t solve either. The problem of how to signal to caller of your function that something went wrong.

Enter Go

Go solves the exception problem by not having exceptions. Instead Go allows functions to return an error type in addition to a result via its support for multiple return values. By declaring a return value of the interface type error you indicate to the caller that this method could go wrong. If a function returns a value and an error, then you can’t assume anything about the value until you’ve inspected the error. The only place that may be acceptable to ignore the value of error is when you don’t care about the other values returned.

Go does have a facility called panic, and if you squint hard enough, you might imagine that panic is the same as throw, but you’d be wrong. When you throw and exception you’re making it the caller’s problem

throw new SomeoneElsesProblem();

For example in C++ you might throw an exception when you can’t convert from an enum to its string equivalent, or in Java when parsing a date from a string. In an internet connected world, where every input from a network must be considered hostile, is the failure to parse a string into a date really exceptional? Of course not.

When you panic in Go, you’re freaking out, it’s not someone elses problem, it’s game over man.

panic("inconceivable")

panics are always fatal to your program. In panicing you never assume that your caller can solve the problem. Hence panic is only used in exceptional circumstances, ones where it is not possible for your code, or anyone integrating your code to continue.

The decision to not include exceptions in Go is an example of its simplicity and orthogonality. Using multiple return values and a simple convention, Go solves the problem of letting programmers know when things have gone wrong and reserves panic for the truly exceptional.

Three new SSH client features in Go weekly.2011-11-18

Over the last few weeks the exp/ssh package has been bubbling away quietly.

Firstly, the Client has finally grown support for publickey authentication. In place of handing over your username and password to the ClientConfig, now you can specify a number of ClientAuth implementations that will be negotiated with the remote server.

To use publickey authentication you need to supply your own type that implements the ClientKeyring interface. Here is a simple example, but more complicated intergrations with operating system keyrings is possible.

// keyring implements the ClientKeyring interface
type keyring struct {
        keys []*rsa.PrivateKey
}

func (k *keyring) Key(i int) (interface{}, error) {
        if i < 0 || i >= len(k.keys) {
                return nil, nil
        }
        return k.keys[i].PublicKey, nil
}

func (k *keyring) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
        hashFunc := crypto.SHA1
        h := hashFunc.New()
        h.Write(data)
        digest := h.Sum()
        return rsa.SignPKCS1v15(rand, k.keys[i], hashFunc, digest)
}

func (k *keyring) loadPEM(file string) error {
        buf, err := ioutil.ReadFile(file)
        if err != nil {
                return err
        }
        block, _ := pem.Decode(buf)
        if block == nil {
                return errors.New("ssh: no key found")
        }
        r, err := x509.ParsePKCS1PrivateKey(block.Bytes)
        if err != nil {
                return err
        }
        k.keys = append(k.keys, r)
        return nil
}

Because of the change to ClientAuth, if you want to use password authentication you will need to pass a type that implements ClientPassword.

// password implements the ClientPassword interface
type password string

func (p password) Password(user string) (string, error) {
        return string(p), nil
}

Tying it all together, Client authentication now looks like this:

func main() {
        k := new(keyring)
        err := k.LoadPEM("/path/to/your/privatekey")
        if err != nil { ... }
        config := &ssh.ClientConfig {
                User: "yourusername",
                Auth: []ssh.ClientAuth {
                        // ClientAuthPassword wraps a ClientPassword implementation
                        // in a type that implements ClientAuth.
                        ssh.ClientAuthPassword(password("yourpassword")),

                        // ClientAuthPublickey wraps a ClientKeyring implementation 
                        // in a type that implements ClientAuth.
                        ssh.ClientAuthPublickey(k),
                }
        }
        conn, err := ssh.Dial("tcp", "yourserver:22", config)
        if err != nil { ... }
}

Secondly, John Beisley has committed the first of a series of CLs that improves cipher handling in both the Client and Server. The commit includes support for AES and ARC4 ciphers and lays the groundwork for adding additional ciphers.

No changes are needed in client code to take advantage of these cipher improvements, the zero value for CryptoConfig in the ClientConfig struct defaults to a list of secure modern ciphers.

Finally, experimental support has been added to the ClientConn type for initiating direct-tcpip connections over SSH connections. The interface matches net.Dial and returns a net.Conn implementation. This allows the SSH clients, where supported, to tunnel TCP connections via the server.

// Dial an SSH server running on yourserver.com
c1, err := ssh.Dial("tcp", "yourserver.com:22", ... )
if err != nil { ... } 

// Dial news.yc via a tunnel to yourserver.com  
c2, err := c1.DialTCP("tcp", "news.ycombinator.org:80")
if err != nil { ... }

All of these are available in the current Go weekly, weekly.2011-11-18. Thanks to the intrepid souls who have already begun to explore the the exp/ssh package. I look forward to hearing about your adventures on golang-nuts.


But wait, there’s more. If you’re keen to live right on the bleeding +tip, this commit has made some improvements to the way interactive Sessions work. The goal is to follow the os/exec API, making Sessions more akin the to exec.Cmds. This features is very new, so I hope to post more as it solidifies after the next weekly.

Scratching my own itch, or how to publish multicast DNS records in Go

DHCP handles allocating IP addresses to the devices on my home network, but that leaves me with the problem of mapping IP addresses to names. The Macs and Linux hosts sort this out with Bonjour and Avahi, but annoyingly two devices, my router and my NAS don’t support it.

Now, I could hack my /etc/hosts file for those two hosts, but that doesn’t work well for embedded devices like iPad. Alternatively, I could install Avahi on my NAS, which is running Debian Sid armel, but space on it’s tiny root file system is always at a premium.

Fortunately, my NAS is also one of my Go development systems, so after some prodding from +Brian Ketelsen, I wrote a package to replicate the parts of Avahi that I needed. Here it is

https://github.com/davecheney/mdns/

Here is a simple example of how to use the package.

import (
        "net"
        "github.com/davecheney/mdns"
)

func main() {
        // Publish a SVR record for ssh running on port 22 for my home NAS.

        // Publish an A record for the host
        mdns.PublishA("stora.local.", 3600, net.IPv4(192, 168, 1, 200))

        // Publish a PTR record for the _ssh._tcp DNS-SD type
        mdns.PublishPTR("_ssh._tcp.local.", 3600, "stora._ssh._tcp.local.")

        // Publish a SRV record typing the _ssh._tcp record to an A record and a port.
        mdns.PublishSRV("stora._ssh._tcp.local.", 3600, "stora.local.", 22)

        // Most mDNS browsing tools expect a TXT record for the service even if there
        // are not records defined by RFC 2782.
        mdns.PublishTXT("stora._ssh._tcp.local.", 3600, "")

        select{}
}

So that’s it. This package has scratched my itch and I hope it is useful for others. I’d love to hear feedback and suggestions you’ve found it to be useful.

updated 16/10/2011 Thanks to @eneff for the select{} tip.

Simple extended attribute support for Go

This afternoon I sat down and polished up the extended attribute library I have been working on for a while. You can find the code and readme on Github.

https://github.com/davecheney/xattr

This has been tested on linux (should work under 5g, 6g and 8g) and darwin (tested under Snow Leopard).

Installation

goinstall github.com/davecheney/xattr

Documentation

godoc github.com/davecheney/xattr

Usage

A example program is provided with the source. The simplest way to compile and install it is

make -C $GOROOT/src/pkg/github.com/davecheney/xattr/example clean install

This will install it to your $GOBIN directory. If you have trouble running this example, make sure there isn’t another xattr somewhere higher in your $PATH.

Before you start

All extended attributes need a file to be associated with. In this example I’m going to create an empty file in my home directory.

touch ~/testfile

Setting an attribute

% $GOBIN/xattr -w username dave ~/testfile

Listing known attributes

% $GOBIN/xattr ~/testfile
username

Printing attribute values

% $GOBIN/xattr -p username ~/testfile
dave

Listing names and values

% $GOBIN/xattr -l ~/testfile
 username: dave

Netgear Stora as an ARM development platform

About a week ago I posted a request for recommendations for ARM based systems that could be used for Go development. There were some great responses, including the BeagleBoard and the Guru Plug. Being impatient, and in Australia, I ended up getting a Netgear Stora which has turned out to be a great home NAS, and a capable ARM5 development system. This is the same hardware, albeit with less RAM, that ships in the ShivaPlug.

axentraserver(~/go/src) % export MAKEFLAGS=-j1
axentraserver(~/go/src) % hg identify 
546b1fc95dcc+ tip
axentraserver(~/go/src) % time ./make.bash > /dev/null
hg not installed
conflicts: 3 shift/reduce

real    10m48.889s
user    9m15.380s
sys     0m52.480s

Not too shabby, my 8g host (2.8Ghz Celeron) turns around the same build in just under 12 minutes.

Pros

  • Very good value. For less thatn $200 AUD you get a 1.2Ghz Marvel ARM5 CPU, 128mb of ram and a 1Tb Seagate 3.5″ drive (and a slot for a second drive). Online Computer have the 1Tb units for $185.
  • Very hackable. SSH is enabled out of the box, if you know the magic suffix that Netgear, and all users created via the web interface are in /etc/sudoers. The fantastic ipkg system will close the gap between the slimmed down RedHat distribution that Netgear Axentra ship and a GNU buildchain that can bootstrap Go.

Cons

  • 128mb of ram, non expandable. This actually turns out to not be a big deal. The stock install has ~75mb of RAM free while running. Turing off a few options and trimming the daemons Netgear installs can get another 10-15mb back.

How to run godoc under launchd on OS X

godoc is an amazing reference utility. I use launchd to keep it running for me.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
   <key>Label</key>
   <string>org.golang.godoc</string>
   <key>ProgramArguments</key>
   <array>
      <!-- ensure this is the absolute path to your godoc install -->
      <string>/Users/dave/go/bin/godoc</string>
      <string>-http=127.0.0.1:6060</string>
   </array>
   <key>Sockets</key>
   <dict>
      <key>Listeners</key>
      <dict>
         <key>SockServiceName</key>
         <string>6060</string>
      </dict>
   </dict>
   <key>RunAtLoad</key>
   <false/>
   </dict>
</plist>

Place this file in ~/Library/LaunchAgents/org.golang.godoc.plist and edit the absolute path to your godoc binary. Then issue the command

$ launchctl load ~/Library/LaunchAgents/org.golang.godoc.plist

You can then browse to http://127.0.0.1:6060 to view the current documentation for your Go installation.

To stop godoc just issue a killall godoc and launchd will restart it when necessary. You can use the same command after updating to the latest release to ensure you’re viewing the most up to date documentation.

How to dial remote SSL/TLS services in Go

Go has wonderful support for server side TLS, but the client side takes a little bit of massaging to generate a correct Config struct. Check out this thread from Hans Stimer for more details on handling TLS on the server side.

package main

import (
	"crypto/tls"
	"io/ioutil"
	"net"
	"os"
	"time"
)

func loadRootCA(file string) (*tls.CASet, os.Error) {
	pemBytes, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, err
	}

	caset := tls.NewCASet()
	if caset.SetFromPEM(pemBytes) {
		return caset, nil
	}
	return nil, os.NewError("Unable to decode root CA set")
}

func newClientConfig(rootCAPath string) (*tls.Config, os.Error) {
	rootca, err := loadRootCA(rootCAPath)
	if err != nil {
		return nil, err
	}

	urandom, err := os.Open("/dev/urandom", os.O_RDONLY, 0)
	if err != nil {
		return nil, err
	}

	return &tls.Config{
		Rand:    urandom,
		Time:    time.Seconds,
		RootCAs: rootca,
	}, nil
}

func dialTLS(raddr *net.TCPAddr) (c *tls.Conn, err os.Error) {
	config, err := newClientConfig("ca-certificates.crt")
	if err != nil {
		return nil, err
	}

	conn, err := net.DialTCP("tcp", nil, raddr)
	if err != nil {
		return nil, err
	}

	c = tls.Client(conn, config)
	err = c.Handshake()
	if err == nil {
		return c, nil
	}
	c.Close()
	return nil, err
}