go-ethereum/vendor/github.com/huin/goupnp/httpu/httpu.go
Péter Szilágyi 289b30715d Godeps, vendor: convert dependency management to trash (#3198)
This commit converts the dependency management from Godeps to the vendor
folder, also switching the tool from godep to trash. Since the upstream tool
lacks a few features proposed via a few PRs, until those PRs are merged in
(if), use github.com/karalabe/trash.

You can update dependencies via trash --update.

All dependencies have been updated to their latest version.

Parts of the build system are reworked to drop old notions of Godeps and
invocation of the go vet command so that it doesn't run against the vendor
folder, as that will just blow up during vetting.

The conversion drops OpenCL (and hence GPU mining support) from ethash and our
codebase. The short reasoning is that there's noone to maintain and having
opencl libs in our deps messes up builds as go install ./... tries to build
them, failing with unsatisfied link errors for the C OpenCL deps.

golang.org/x/net/context is not vendored in. We expect it to be fetched by the
user (i.e. using go get). To keep ci.go builds reproducible the package is
"vendored" in build/_vendor.
2016-10-28 19:05:01 +02:00

133 lines
3.5 KiB
Go

package httpu
import (
"bufio"
"bytes"
"errors"
"fmt"
"log"
"net"
"net/http"
"sync"
"time"
)
// HTTPUClient is a client for dealing with HTTPU (HTTP over UDP). Its typical
// function is for HTTPMU, and particularly SSDP.
type HTTPUClient struct {
connLock sync.Mutex // Protects use of conn.
conn net.PacketConn
}
// NewHTTPUClient creates a new HTTPUClient, opening up a new UDP socket for the
// purpose.
func NewHTTPUClient() (*HTTPUClient, error) {
conn, err := net.ListenPacket("udp", ":0")
if err != nil {
return nil, err
}
return &HTTPUClient{conn: conn}, nil
}
// NewHTTPUClientAddr creates a new HTTPUClient which will broadcast packets
// from the specified address, opening up a new UDP socket for the purpose
func NewHTTPUClientAddr(addr string) (*HTTPUClient, error) {
ip := net.ParseIP(addr)
if ip == nil {
return nil, errors.New("Invalid listening address")
}
conn, err := net.ListenPacket("udp", ip.String()+":0")
if err != nil {
return nil, err
}
return &HTTPUClient{conn: conn}, nil
}
// Close shuts down the client. The client will no longer be useful following
// this.
func (httpu *HTTPUClient) Close() error {
httpu.connLock.Lock()
defer httpu.connLock.Unlock()
return httpu.conn.Close()
}
// Do performs a request. The timeout is how long to wait for before returning
// the responses that were received. An error is only returned for failing to
// send the request. Failures in receipt simply do not add to the resulting
// responses.
//
// Note that at present only one concurrent connection will happen per
// HTTPUClient.
func (httpu *HTTPUClient) Do(req *http.Request, timeout time.Duration, numSends int) ([]*http.Response, error) {
httpu.connLock.Lock()
defer httpu.connLock.Unlock()
// Create the request. This is a subset of what http.Request.Write does
// deliberately to avoid creating extra fields which may confuse some
// devices.
var requestBuf bytes.Buffer
method := req.Method
if method == "" {
method = "GET"
}
if _, err := fmt.Fprintf(&requestBuf, "%s %s HTTP/1.1\r\n", method, req.URL.RequestURI()); err != nil {
return nil, err
}
if err := req.Header.Write(&requestBuf); err != nil {
return nil, err
}
if _, err := requestBuf.Write([]byte{'\r', '\n'}); err != nil {
return nil, err
}
destAddr, err := net.ResolveUDPAddr("udp", req.Host)
if err != nil {
return nil, err
}
if err = httpu.conn.SetDeadline(time.Now().Add(timeout)); err != nil {
return nil, err
}
// Send request.
for i := 0; i < numSends; i++ {
if n, err := httpu.conn.WriteTo(requestBuf.Bytes(), destAddr); err != nil {
return nil, err
} else if n < len(requestBuf.Bytes()) {
return nil, fmt.Errorf("httpu: wrote %d bytes rather than full %d in request",
n, len(requestBuf.Bytes()))
}
time.Sleep(5 * time.Millisecond)
}
// Await responses until timeout.
var responses []*http.Response
responseBytes := make([]byte, 2048)
for {
// 2048 bytes should be sufficient for most networks.
n, _, err := httpu.conn.ReadFrom(responseBytes)
if err != nil {
if err, ok := err.(net.Error); ok {
if err.Timeout() {
break
}
if err.Temporary() {
// Sleep in case this is a persistent error to avoid pegging CPU until deadline.
time.Sleep(10 * time.Millisecond)
continue
}
}
return nil, err
}
// Parse response.
response, err := http.ReadResponse(bufio.NewReader(bytes.NewBuffer(responseBytes[:n])), req)
if err != nil {
log.Print("httpu: error while parsing response: %v", err)
continue
}
responses = append(responses, response)
}
return responses, err
}