buildlet: set TCP keep-alive timeouts, avoid fd leaks

Change-Id: Ia95dcf2d796846f9f0368a9672d3dc0d1f4c0d6f
Reviewed-on: https://go-review.googlesource.com/3770
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/buildlet/buildletclient.go b/buildlet/buildletclient.go
index 33792f5..f341224 100644
--- a/buildlet/buildletclient.go
+++ b/buildlet/buildletclient.go
@@ -11,6 +11,7 @@
 	"fmt"
 	"io"
 	"io/ioutil"
+	"net"
 	"net/http"
 	"net/url"
 	"strings"
@@ -27,12 +28,24 @@
 		password: kp.Password(),
 		httpClient: &http.Client{
 			Transport: &http.Transport{
+				Dial:    defaultDialer(),
 				DialTLS: kp.tlsDialer(),
 			},
 		},
 	}
 }
 
+// defaultDialer returns the net/http package's default Dial function.
+// Notably, this sets TCP keep-alive values, so when we kill VMs
+// (whose TCP stacks stop replying, forever), we don't leak file
+// descriptors for otherwise forever-stalled TCP connections.
+func defaultDialer() func(network, addr string) (net.Conn, error) {
+	if fn := http.DefaultTransport.(*http.Transport).Dial; fn != nil {
+		return fn
+	}
+	return net.Dial
+}
+
 // A Client interacts with a single buildlet.
 type Client struct {
 	ipPort     string