From 6a4cd9d8e72c7db7ab79f73b0a3b6b13defe1082 Mon Sep 17 00:00:00 2001 From: sago35 Date: Mon, 5 Jul 2021 18:21:33 +0900 Subject: [PATCH] rtl8720dn: add examples/rtl8720dn/webserver --- Makefile | 2 + examples/rtl8720dn/webserver/main.go | 162 ++++++ examples/rtl8720dn/webserver/wioterminal.go | 73 +++ go.mod | 1 + go.sum | 8 + net/http/driver.go | 15 + net/http/header.go | 259 +++++++++ net/http/http.go | 162 ++++++ net/http/request.go | 608 ++++++++++++++++++++ net/http/response.go | 112 ++++ net/http/server.go | 581 +++++++++++++++++++ net/http/status.go | 152 +++++ net/http/transefer.go | 34 ++ rtl8720dn/http.go | 236 ++++++++ rtl8720dn/netdriver.go | 17 +- rtl8720dn/rpc.go | 397 +++++++------ rtl8720dn/wifi.go | 2 +- 17 files changed, 2650 insertions(+), 171 deletions(-) create mode 100644 examples/rtl8720dn/webserver/main.go create mode 100644 examples/rtl8720dn/webserver/wioterminal.go create mode 100644 net/http/driver.go create mode 100644 net/http/header.go create mode 100644 net/http/http.go create mode 100644 net/http/request.go create mode 100644 net/http/response.go create mode 100644 net/http/server.go create mode 100644 net/http/status.go create mode 100644 net/http/transefer.go create mode 100644 rtl8720dn/http.go diff --git a/Makefile b/Makefile index b42d834..f3169a4 100644 --- a/Makefile +++ b/Makefile @@ -199,6 +199,8 @@ endif @md5sum ./build/test.hex tinygo build -size short -o ./build/test.hex -target=wioterminal ./examples/rtl8720dn/webclient/ @md5sum ./build/test.hex + tinygo build -size short -o ./build/test.hex -target=wioterminal ./examples/rtl8720dn/webserver/ + @md5sum ./build/test.hex DRIVERS = $(wildcard */) NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \ diff --git a/examples/rtl8720dn/webserver/main.go b/examples/rtl8720dn/webserver/main.go new file mode 100644 index 0000000..7c9adaf --- /dev/null +++ b/examples/rtl8720dn/webserver/main.go @@ -0,0 +1,162 @@ +package main + +import ( + "fmt" + "machine" + "strconv" + "time" + + "tinygo.org/x/drivers/net/http" +) + +// You can override the setting with the init() in another source code. +// func init() { +// ssid = "your-ssid" +// password = "your-password" +// debug = true +// } + +var ( + ssid string + password string + debug = false +) + +var led = machine.LED +var backlight = machine.LCD_BACKLIGHT + +func main() { + led.Configure(machine.PinConfig{Mode: machine.PinOutput}) + backlight.Configure(machine.PinConfig{Mode: machine.PinOutput}) + + err := run() + for err != nil { + fmt.Printf("error: %s\r\n", err.Error()) + time.Sleep(5 * time.Second) + } +} + +func run() error { + rtl, err := setupRTL8720DN() + if err != nil { + return err + } + http.UseDriver(rtl) + + err = rtl.ConnectToAP(ssid, password) + if err != nil { + return err + } + + ip, subnet, gateway, err := rtl.GetIP() + if err != nil { + return err + } + fmt.Printf("IP Address : %s\r\n", ip) + fmt.Printf("Mask : %s\r\n", subnet) + fmt.Printf("Gateway : %s\r\n", gateway) + + http.HandleFunc("/", root) + http.HandleFunc("/hello", hello) + http.HandleFunc("/cnt", cnt) + http.HandleFunc("/6", sixlines) + http.HandleFunc("/off", LED_OFF) + http.HandleFunc("/on", LED_ON) + if err := http.ListenAndServe(":80", nil); err != nil { + message(err.Error()) + } + return nil +} + +func root(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, ` + + + TinyGo HTTP Server + + + +
TinyGo HTTP Server
+ /hello
+ /6
+ +

+ LED
+ /on
+ /off
+

+ + +

+ /cnt
+ cnt:
+ incrCnt()
+

+ + +
+

+ + + `) +} + +func sixlines(w http.ResponseWriter, r *http.Request) { + // https://fukuno.jig.jp/3267 + fmt.Fprint(w, ``) +} + +func LED_ON(w http.ResponseWriter, r *http.Request) { + led.High() + backlight.High() + w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`) + fmt.Fprintf(w, "led.High()") +} + +func LED_OFF(w http.ResponseWriter, r *http.Request) { + led.Low() + backlight.Low() + w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`) + fmt.Fprintf(w, "led.Low()") +} + +func hello(w http.ResponseWriter, r *http.Request) { + w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`) + fmt.Fprintf(w, "hello") +} + +var counter int + +func cnt(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + if r.Method == "POST" { + c := r.Form.Get("cnt") + if c != "" { + i64, _ := strconv.ParseInt(c, 0, 0) + counter = int(i64) + } + } + + w.Header().Set(`Content-Type`, `application/json`) + fmt.Fprintf(w, `{"cnt": %d}`, counter) +} + +func message(msg string) { + println(msg, "\r") +} diff --git a/examples/rtl8720dn/webserver/wioterminal.go b/examples/rtl8720dn/webserver/wioterminal.go new file mode 100644 index 0000000..9da045f --- /dev/null +++ b/examples/rtl8720dn/webserver/wioterminal.go @@ -0,0 +1,73 @@ +// +build wioterminal + +package main + +import ( + "device/sam" + "machine" + "runtime/interrupt" + "time" + + "tinygo.org/x/drivers/rtl8720dn" +) + +var ( + uart UARTx +) + +func handleInterrupt(interrupt.Interrupt) { + // should reset IRQ + uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF))) + uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INT_INTFLAG_RXC) +} + +func setupRTL8720DN() (*rtl8720dn.RTL8720DN, error) { + machine.RTL8720D_CHIP_PU.Configure(machine.PinConfig{Mode: machine.PinOutput}) + machine.RTL8720D_CHIP_PU.Low() + time.Sleep(100 * time.Millisecond) + machine.RTL8720D_CHIP_PU.High() + time.Sleep(1000 * time.Millisecond) + if debug { + waitSerial() + } + + uart = UARTx{ + UART: &machine.UART{ + Buffer: machine.NewRingBuffer(), + Bus: sam.SERCOM0_USART_INT, + SERCOM: 0, + }, + } + + uart.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, handleInterrupt) + uart.Configure(machine.UARTConfig{TX: machine.PB24, RX: machine.PC24, BaudRate: 614400}) + + rtl := rtl8720dn.New(uart) + rtl.Debug(debug) + + _, err := rtl.Rpc_tcpip_adapter_init() + if err != nil { + return nil, err + } + + return rtl, nil +} + +// Wait for user to open serial console +func waitSerial() { + for !machine.Serial.DTR() { + time.Sleep(100 * time.Millisecond) + } +} + +type UARTx struct { + *machine.UART +} + +func (u UARTx) Read(p []byte) (n int, err error) { + if u.Buffered() == 0 { + time.Sleep(1 * time.Millisecond) + return 0, nil + } + return u.UART.Read(p) +} diff --git a/go.mod b/go.mod index a3bff76..f6dcef2 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.15 require ( github.com/eclipse/paho.mqtt.golang v1.2.0 github.com/frankban/quicktest v1.10.2 + golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect tinygo.org/x/tinyfont v0.2.1 tinygo.org/x/tinyfs v0.1.0 tinygo.org/x/tinyterm v0.1.0 diff --git a/go.sum b/go.sum index c28f71e..6be0cea 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,14 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= tinygo.org/x/drivers v0.14.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI= diff --git a/net/http/driver.go b/net/http/driver.go new file mode 100644 index 0000000..d125939 --- /dev/null +++ b/net/http/driver.go @@ -0,0 +1,15 @@ +package http + +type DeviceDriver interface { + ListenAndServe(addr string, handler Handler) error +} + +var ActiveDevice DeviceDriver + +func UseDriver(driver DeviceDriver) { + // TODO: rethink and refactor this + if ActiveDevice != nil { + panic("net.ActiveDevice is already set") + } + ActiveDevice = driver +} diff --git a/net/http/header.go b/net/http/header.go new file mode 100644 index 0000000..0cc0e55 --- /dev/null +++ b/net/http/header.go @@ -0,0 +1,259 @@ +package http + +import ( + "io" + "net/http/httptrace" + "net/textproto" + "sort" + "strings" + "sync" + "time" +) + +// A Header represents the key-value pairs in an HTTP header. +// +// The keys should be in canonical form, as returned by +// CanonicalHeaderKey. +type Header map[string][]string + +// Add adds the key, value pair to the header. +// It appends to any existing values associated with key. +// The key is case insensitive; it is canonicalized by +// CanonicalHeaderKey. +func (h Header) Add(key, value string) { + textproto.MIMEHeader(h).Add(key, value) +} + +// Set sets the header entries associated with key to the +// single element value. It replaces any existing values +// associated with key. The key is case insensitive; it is +// canonicalized by textproto.CanonicalMIMEHeaderKey. +// To use non-canonical keys, assign to the map directly. +func (h Header) Set(key, value string) { + textproto.MIMEHeader(h).Set(key, value) +} + +// Get gets the first value associated with the given key. If +// there are no values associated with the key, Get returns "". +// It is case insensitive; textproto.CanonicalMIMEHeaderKey is +// used to canonicalize the provided key. To use non-canonical keys, +// access the map directly. +func (h Header) Get(key string) string { + return textproto.MIMEHeader(h).Get(key) +} + +// Values returns all values associated with the given key. +// It is case insensitive; textproto.CanonicalMIMEHeaderKey is +// used to canonicalize the provided key. To use non-canonical +// keys, access the map directly. +// The returned slice is not a copy. +func (h Header) Values(key string) []string { + return textproto.MIMEHeader(h).Values(key) +} + +// get is like Get, but key must already be in CanonicalHeaderKey form. +func (h Header) get(key string) string { + if v := h[key]; len(v) > 0 { + return v[0] + } + return "" +} + +// has reports whether h has the provided key defined, even if it's +// set to 0-length slice. +func (h Header) has(key string) bool { + _, ok := h[key] + return ok +} + +// Del deletes the values associated with key. +// The key is case insensitive; it is canonicalized by +// CanonicalHeaderKey. +func (h Header) Del(key string) { + textproto.MIMEHeader(h).Del(key) +} + +// Write writes a header in wire format. +func (h Header) Write(w io.Writer) error { + return h.write(w, nil) +} + +func (h Header) write(w io.Writer, trace *httptrace.ClientTrace) error { + return h.writeSubset(w, nil, trace) +} + +// Clone returns a copy of h or nil if h is nil. +func (h Header) Clone() Header { + if h == nil { + return nil + } + + // Find total number of values. + nv := 0 + for _, vv := range h { + nv += len(vv) + } + sv := make([]string, nv) // shared backing array for headers' values + h2 := make(Header, len(h)) + for k, vv := range h { + n := copy(sv, vv) + h2[k] = sv[:n:n] + sv = sv[n:] + } + return h2 +} + +var timeFormats = []string{ + TimeFormat, + time.RFC850, + time.ANSIC, +} + +// ParseTime parses a time header (such as the Date: header), +// trying each of the three formats allowed by HTTP/1.1: +// TimeFormat, time.RFC850, and time.ANSIC. +func ParseTime(text string) (t time.Time, err error) { + for _, layout := range timeFormats { + t, err = time.Parse(layout, text) + if err == nil { + return + } + } + return +} + +var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ") + +// stringWriter implements WriteString on a Writer. +type stringWriter struct { + w io.Writer +} + +func (w stringWriter) WriteString(s string) (n int, err error) { + return w.w.Write([]byte(s)) +} + +type keyValues struct { + key string + values []string +} + +// A headerSorter implements sort.Interface by sorting a []keyValues +// by key. It's used as a pointer, so it can fit in a sort.Interface +// interface value without allocation. +type headerSorter struct { + kvs []keyValues +} + +func (s *headerSorter) Len() int { return len(s.kvs) } +func (s *headerSorter) Swap(i, j int) { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] } +func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key } + +var headerSorterPool = sync.Pool{ + New: func() interface{} { return new(headerSorter) }, +} + +// sortedKeyValues returns h's keys sorted in the returned kvs +// slice. The headerSorter used to sort is also returned, for possible +// return to headerSorterCache. +func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *headerSorter) { + hs = headerSorterPool.Get().(*headerSorter) + if cap(hs.kvs) < len(h) { + hs.kvs = make([]keyValues, 0, len(h)) + } + kvs = hs.kvs[:0] + for k, vv := range h { + if !exclude[k] { + kvs = append(kvs, keyValues{k, vv}) + } + } + hs.kvs = kvs + sort.Sort(hs) + return kvs, hs +} + +// WriteSubset writes a header in wire format. +// If exclude is not nil, keys where exclude[key] == true are not written. +// Keys are not canonicalized before checking the exclude map. +func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error { + return h.writeSubset(w, exclude, nil) +} + +func (h Header) writeSubset(w io.Writer, exclude map[string]bool, trace *httptrace.ClientTrace) error { + ws, ok := w.(io.StringWriter) + if !ok { + ws = stringWriter{w} + } + kvs, sorter := h.sortedKeyValues(exclude) + var formattedVals []string + for _, kv := range kvs { + for _, v := range kv.values { + v = headerNewlineToSpace.Replace(v) + v = textproto.TrimString(v) + for _, s := range []string{kv.key, ": ", v, "\r\n"} { + if _, err := ws.WriteString(s); err != nil { + headerSorterPool.Put(sorter) + return err + } + } + if trace != nil && trace.WroteHeaderField != nil { + formattedVals = append(formattedVals, v) + } + } + if trace != nil && trace.WroteHeaderField != nil { + trace.WroteHeaderField(kv.key, formattedVals) + formattedVals = nil + } + } + headerSorterPool.Put(sorter) + return nil +} + +// CanonicalHeaderKey returns the canonical format of the +// header key s. The canonicalization converts the first +// letter and any letter following a hyphen to upper case; +// the rest are converted to lowercase. For example, the +// canonical key for "accept-encoding" is "Accept-Encoding". +// If s contains a space or invalid header field bytes, it is +// returned without modifications. +func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) } + +// hasToken reports whether token appears with v, ASCII +// case-insensitive, with space or comma boundaries. +// token must be all lowercase. +// v may contain mixed cased. +func hasToken(v, token string) bool { + if len(token) > len(v) || token == "" { + return false + } + if v == token { + return true + } + for sp := 0; sp <= len(v)-len(token); sp++ { + // Check that first character is good. + // The token is ASCII, so checking only a single byte + // is sufficient. We skip this potential starting + // position if both the first byte and its potential + // ASCII uppercase equivalent (b|0x20) don't match. + // False positives ('^' => '~') are caught by EqualFold. + if b := v[sp]; b != token[0] && b|0x20 != token[0] { + continue + } + // Check that start pos is on a valid token boundary. + if sp > 0 && !isTokenBoundary(v[sp-1]) { + continue + } + // Check that end pos is on a valid token boundary. + if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) { + continue + } + if strings.EqualFold(v[sp:sp+len(token)], token) { + return true + } + } + return false +} + +func isTokenBoundary(b byte) bool { + return b == ' ' || b == ',' || b == '\t' +} diff --git a/net/http/http.go b/net/http/http.go new file mode 100644 index 0000000..9268698 --- /dev/null +++ b/net/http/http.go @@ -0,0 +1,162 @@ +package http + +import ( + "io" + "strconv" + "strings" + "time" + "unicode/utf8" + + "golang.org/x/net/http/httpguts" +) + +// incomparable is a zero-width, non-comparable type. Adding it to a struct +// makes that struct also non-comparable, and generally doesn't add +// any size (as long as it's first). +type incomparable [0]func() + +// maxInt64 is the effective "infinite" value for the Server and +// Transport's byte-limiting readers. +const maxInt64 = 1<<63 - 1 + +// aLongTimeAgo is a non-zero time, far in the past, used for +// immediate cancellation of network operations. +var aLongTimeAgo = time.Unix(1, 0) + +// omitBundledHTTP2 is set by omithttp2.go when the nethttpomithttp2 +// build tag is set. That means h2_bundle.go isn't compiled in and we +// shouldn't try to use it. +var omitBundledHTTP2 bool + +// TODO(bradfitz): move common stuff here. The other files have accumulated +// generic http stuff in random places. + +// contextKey is a value for use with context.WithValue. It's used as +// a pointer so it fits in an interface{} without allocation. +type contextKey struct { + name string +} + +func (k *contextKey) String() string { return "net/http context value " + k.name } + +// Given a string of the form "host", "host:port", or "[ipv6::address]:port", +// return true if the string includes a port. +func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } + +// removeEmptyPort strips the empty port in ":port" to "" +// as mandated by RFC 3986 Section 6.2.3. +func removeEmptyPort(host string) string { + if hasPort(host) { + return strings.TrimSuffix(host, ":") + } + return host +} + +func isNotToken(r rune) bool { + return !httpguts.IsTokenRune(r) +} + +func isASCII(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] >= utf8.RuneSelf { + return false + } + } + return true +} + +// stringContainsCTLByte reports whether s contains any ASCII control character. +func stringContainsCTLByte(s string) bool { + for i := 0; i < len(s); i++ { + b := s[i] + if b < ' ' || b == 0x7f { + return true + } + } + return false +} + +func hexEscapeNonASCII(s string) string { + newLen := 0 + for i := 0; i < len(s); i++ { + if s[i] >= utf8.RuneSelf { + newLen += 3 + } else { + newLen++ + } + } + if newLen == len(s) { + return s + } + b := make([]byte, 0, newLen) + for i := 0; i < len(s); i++ { + if s[i] >= utf8.RuneSelf { + b = append(b, '%') + b = strconv.AppendInt(b, int64(s[i]), 16) + } else { + b = append(b, s[i]) + } + } + return string(b) +} + +// NoBody is an io.ReadCloser with no bytes. Read always returns EOF +// and Close always returns nil. It can be used in an outgoing client +// request to explicitly signal that a request has zero bytes. +// An alternative, however, is to simply set Request.Body to nil. +var NoBody = noBody{} + +type noBody struct{} + +func (noBody) Read([]byte) (int, error) { return 0, io.EOF } +func (noBody) Close() error { return nil } +func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } + +var ( + // verify that an io.Copy from NoBody won't require a buffer: + _ io.WriterTo = NoBody + _ io.ReadCloser = NoBody +) + +// PushOptions describes options for Pusher.Push. +type PushOptions struct { + // Method specifies the HTTP method for the promised request. + // If set, it must be "GET" or "HEAD". Empty means "GET". + Method string + + // Header specifies additional promised request headers. This cannot + // include HTTP/2 pseudo header fields like ":path" and ":scheme", + // which will be added automatically. + Header Header +} + +// Pusher is the interface implemented by ResponseWriters that support +// HTTP/2 server push. For more background, see +// https://tools.ietf.org/html/rfc7540#section-8.2. +type Pusher interface { + // Push initiates an HTTP/2 server push. This constructs a synthetic + // request using the given target and options, serializes that request + // into a PUSH_PROMISE frame, then dispatches that request using the + // server's request handler. If opts is nil, default options are used. + // + // The target must either be an absolute path (like "/path") or an absolute + // URL that contains a valid host and the same scheme as the parent request. + // If the target is a path, it will inherit the scheme and host of the + // parent request. + // + // The HTTP/2 spec disallows recursive pushes and cross-authority pushes. + // Push may or may not detect these invalid pushes; however, invalid + // pushes will be detected and canceled by conforming clients. + // + // Handlers that wish to push URL X should call Push before sending any + // data that may trigger a request for URL X. This avoids a race where the + // client issues requests for X before receiving the PUSH_PROMISE for X. + // + // Push will run in a separate goroutine making the order of arrival + // non-deterministic. Any required synchronization needs to be implemented + // by the caller. + // + // Push returns ErrNotSupported if the client has disabled push or if push + // is not supported on the underlying connection. + Push(target string, opts *PushOptions) error +} diff --git a/net/http/request.go b/net/http/request.go new file mode 100644 index 0000000..58756ea --- /dev/null +++ b/net/http/request.go @@ -0,0 +1,608 @@ +package http + +import ( + "bufio" + "context" + "crypto/tls" + "errors" + "fmt" + "io" + "mime" + "mime/multipart" + "net/textproto" + "net/url" + "strconv" + "strings" + "sync" +) + +func badStringError(what, val string) error { return fmt.Errorf("%s %q", what, val) } + +type Request struct { + // Method specifies the HTTP method (GET, POST, PUT, etc.). + // For client requests, an empty string means GET. + // + // Go's HTTP client does not support sending a request with + // the CONNECT method. See the documentation on Transport for + // details. + Method string + + // URL specifies either the URI being requested (for server + // requests) or the URL to access (for client requests). + // + // For server requests, the URL is parsed from the URI + // supplied on the Request-Line as stored in RequestURI. For + // most requests, fields other than Path and RawQuery will be + // empty. (See RFC 7230, Section 5.3) + // + // For client requests, the URL's Host specifies the server to + // connect to, while the Request's Host field optionally + // specifies the Host header value to send in the HTTP + // request. + URL *url.URL + + // The protocol version for incoming server requests. + // + // For client requests, these fields are ignored. The HTTP + // client code always uses either HTTP/1.1 or HTTP/2. + // See the docs on Transport for details. + Proto string // "HTTP/1.0" + ProtoMajor int // 1 + ProtoMinor int // 0 + + // Header contains the request header fields either received + // by the server or to be sent by the client. + // + // If a server received a request with header lines, + // + // Host: example.com + // accept-encoding: gzip, deflate + // Accept-Language: en-us + // fOO: Bar + // foo: two + // + // then + // + // Header = map[string][]string{ + // "Accept-Encoding": {"gzip, deflate"}, + // "Accept-Language": {"en-us"}, + // "Foo": {"Bar", "two"}, + // } + // + // For incoming requests, the Host header is promoted to the + // Request.Host field and removed from the Header map. + // + // HTTP defines that header names are case-insensitive. The + // request parser implements this by using CanonicalHeaderKey, + // making the first character and any characters following a + // hyphen uppercase and the rest lowercase. + // + // For client requests, certain headers such as Content-Length + // and Connection are automatically written when needed and + // values in Header may be ignored. See the documentation + // for the Request.Write method. + Header Header + + // Body is the request's body. + // + // For client requests, a nil body means the request has no + // body, such as a GET request. The HTTP Client's Transport + // is responsible for calling the Close method. + // + // For server requests, the Request Body is always non-nil + // but will return EOF immediately when no body is present. + // The Server will close the request body. The ServeHTTP + // Handler does not need to. + // + // Body must allow Read to be called concurrently with Close. + // In particular, calling Close should unblock a Read waiting + // for input. + Body io.ReadCloser + + // GetBody defines an optional func to return a new copy of + // Body. It is used for client requests when a redirect requires + // reading the body more than once. Use of GetBody still + // requires setting Body. + // + // For server requests, it is unused. + GetBody func() (io.ReadCloser, error) + + // ContentLength records the length of the associated content. + // The value -1 indicates that the length is unknown. + // Values >= 0 indicate that the given number of bytes may + // be read from Body. + // + // For client requests, a value of 0 with a non-nil Body is + // also treated as unknown. + ContentLength int64 + + // TransferEncoding lists the transfer encodings from outermost to + // innermost. An empty list denotes the "identity" encoding. + // TransferEncoding can usually be ignored; chunked encoding is + // automatically added and removed as necessary when sending and + // receiving requests. + TransferEncoding []string + + // Close indicates whether to close the connection after + // replying to this request (for servers) or after sending this + // request and reading its response (for clients). + // + // For server requests, the HTTP server handles this automatically + // and this field is not needed by Handlers. + // + // For client requests, setting this field prevents re-use of + // TCP connections between requests to the same hosts, as if + // Transport.DisableKeepAlives were set. + Close bool + + // For server requests, Host specifies the host on which the + // URL is sought. For HTTP/1 (per RFC 7230, section 5.4), this + // is either the value of the "Host" header or the host name + // given in the URL itself. For HTTP/2, it is the value of the + // ":authority" pseudo-header field. + // It may be of the form "host:port". For international domain + // names, Host may be in Punycode or Unicode form. Use + // golang.org/x/net/idna to convert it to either format if + // needed. + // To prevent DNS rebinding attacks, server Handlers should + // validate that the Host header has a value for which the + // Handler considers itself authoritative. The included + // ServeMux supports patterns registered to particular host + // names and thus protects its registered Handlers. + // + // For client requests, Host optionally overrides the Host + // header to send. If empty, the Request.Write method uses + // the value of URL.Host. Host may contain an international + // domain name. + Host string + + // Form contains the parsed form data, including both the URL + // field's query parameters and the PATCH, POST, or PUT form data. + // This field is only available after ParseForm is called. + // The HTTP client ignores Form and uses Body instead. + Form url.Values + + // PostForm contains the parsed form data from PATCH, POST + // or PUT body parameters. + // + // This field is only available after ParseForm is called. + // The HTTP client ignores PostForm and uses Body instead. + PostForm url.Values + + // MultipartForm is the parsed multipart form, including file uploads. + // This field is only available after ParseMultipartForm is called. + // The HTTP client ignores MultipartForm and uses Body instead. + MultipartForm *multipart.Form + + // Trailer specifies additional headers that are sent after the request + // body. + // + // For server requests, the Trailer map initially contains only the + // trailer keys, with nil values. (The client declares which trailers it + // will later send.) While the handler is reading from Body, it must + // not reference Trailer. After reading from Body returns EOF, Trailer + // can be read again and will contain non-nil values, if they were sent + // by the client. + // + // For client requests, Trailer must be initialized to a map containing + // the trailer keys to later send. The values may be nil or their final + // values. The ContentLength must be 0 or -1, to send a chunked request. + // After the HTTP request is sent the map values can be updated while + // the request body is read. Once the body returns EOF, the caller must + // not mutate Trailer. + // + // Few HTTP clients, servers, or proxies support HTTP trailers. + Trailer Header + + // RemoteAddr allows HTTP servers and other software to record + // the network address that sent the request, usually for + // logging. This field is not filled in by ReadRequest and + // has no defined format. The HTTP server in this package + // sets RemoteAddr to an "IP:port" address before invoking a + // handler. + // This field is ignored by the HTTP client. + RemoteAddr string + + // RequestURI is the unmodified request-target of the + // Request-Line (RFC 7230, Section 3.1.1) as sent by the client + // to a server. Usually the URL field should be used instead. + // It is an error to set this field in an HTTP client request. + RequestURI string + + // TLS allows HTTP servers and other software to record + // information about the TLS connection on which the request + // was received. This field is not filled in by ReadRequest. + // The HTTP server in this package sets the field for + // TLS-enabled connections before invoking a handler; + // otherwise it leaves the field nil. + // This field is ignored by the HTTP client. + TLS *tls.ConnectionState + + // Cancel is an optional channel whose closure indicates that the client + // request should be regarded as canceled. Not all implementations of + // RoundTripper may support Cancel. + // + // For server requests, this field is not applicable. + // + // Deprecated: Set the Request's context with NewRequestWithContext + // instead. If a Request's Cancel field and context are both + // set, it is undefined whether Cancel is respected. + Cancel <-chan struct{} + + // Response is the redirect response which caused this request + // to be created. This field is only populated during client + // redirects. + Response *Response + + // ctx is either the client or server context. It should only + // be modified via copying the whole Request using WithContext. + // It is unexported to prevent people from using Context wrong + // and mutating the contexts held by callers of the same request. + ctx context.Context +} + +// ProtoAtLeast reports whether the HTTP protocol used +// in the request is at least major.minor. +func (r *Request) ProtoAtLeast(major, minor int) bool { + return r.ProtoMajor > major || + r.ProtoMajor == major && r.ProtoMinor >= minor +} + +// isH2Upgrade reports whether r represents the http2 "client preface" +// magic string. +func (r *Request) isH2Upgrade() bool { + return r.Method == "PRI" && len(r.Header) == 0 && r.URL.Path == "*" && r.Proto == "HTTP/2.0" +} + +// ParseHTTPVersion parses an HTTP version string. +// "HTTP/1.0" returns (1, 0, true). +func ParseHTTPVersion(vers string) (major, minor int, ok bool) { + const Big = 1000000 // arbitrary upper bound + switch vers { + case "HTTP/1.1": + return 1, 1, true + case "HTTP/1.0": + return 1, 0, true + } + if !strings.HasPrefix(vers, "HTTP/") { + return 0, 0, false + } + dot := strings.Index(vers, ".") + if dot < 0 { + return 0, 0, false + } + major, err := strconv.Atoi(vers[5:dot]) + if err != nil || major < 0 || major > Big { + return 0, 0, false + } + minor, err = strconv.Atoi(vers[dot+1:]) + if err != nil || minor < 0 || minor > Big { + return 0, 0, false + } + return major, minor, true +} + +func validMethod(method string) bool { + /* + Method = "OPTIONS" ; Section 9.2 + | "GET" ; Section 9.3 + | "HEAD" ; Section 9.4 + | "POST" ; Section 9.5 + | "PUT" ; Section 9.6 + | "DELETE" ; Section 9.7 + | "TRACE" ; Section 9.8 + | "CONNECT" ; Section 9.9 + | extension-method + extension-method = token + token = 1* + */ + return len(method) > 0 && strings.IndexFunc(method, isNotToken) == -1 +} + +// parseRequestLine parses "GET /foo HTTP/1.1" into its three parts. +func parseRequestLine(line string) (method, requestURI, proto string, ok bool) { + s1 := strings.Index(line, " ") + s2 := strings.Index(line[s1+1:], " ") + if s1 < 0 || s2 < 0 { + return + } + s2 += s1 + 1 + return line[:s1], line[s1+1 : s2], line[s2+1:], true +} + +var textprotoReaderPool sync.Pool + +func newTextprotoReader(br *bufio.Reader) *textproto.Reader { + if v := textprotoReaderPool.Get(); v != nil { + tr := v.(*textproto.Reader) + tr.R = br + return tr + } + return textproto.NewReader(br) +} + +func putTextprotoReader(r *textproto.Reader) { + r.R = nil + textprotoReaderPool.Put(r) +} + +// ReadRequest reads and parses an incoming request from b. +// +// ReadRequest is a low-level function and should only be used for +// specialized applications; most code should use the Server to read +// requests and handle them via the Handler interface. ReadRequest +// only supports HTTP/1.x requests. For HTTP/2, use golang.org/x/net/http2. +func ReadRequest(b *bufio.Reader) (*Request, error) { + return readRequest(b, deleteHostHeader) +} + +// Constants for readRequest's deleteHostHeader parameter. +const ( + deleteHostHeader = true + keepHostHeader = false +) + +func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err error) { + tp := newTextprotoReader(b) + req = new(Request) + + // First line: GET /index.html HTTP/1.0 + var s string + if s, err = tp.ReadLine(); err != nil { + return nil, err + } + defer func() { + putTextprotoReader(tp) + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + var ok bool + req.Method, req.RequestURI, req.Proto, ok = parseRequestLine(s) + if !ok { + return nil, badStringError("malformed HTTP request", s) + } + if !validMethod(req.Method) { + return nil, badStringError("invalid method", req.Method) + } + rawurl := req.RequestURI + if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok { + return nil, badStringError("malformed HTTP version", req.Proto) + } + + // CONNECT requests are used two different ways, and neither uses a full URL: + // The standard use is to tunnel HTTPS through an HTTP proxy. + // It looks like "CONNECT www.google.com:443 HTTP/1.1", and the parameter is + // just the authority section of a URL. This information should go in req.URL.Host. + // + // The net/rpc package also uses CONNECT, but there the parameter is a path + // that starts with a slash. It can be parsed with the regular URL parser, + // and the path will end up in req.URL.Path, where it needs to be in order for + // RPC to work. + justAuthority := req.Method == "CONNECT" && !strings.HasPrefix(rawurl, "/") + if justAuthority { + rawurl = "http://" + rawurl + } + + if req.URL, err = url.ParseRequestURI(rawurl); err != nil { + return nil, err + } + + if justAuthority { + // Strip the bogus "http://" back off. + req.URL.Scheme = "" + } + + // Subsequent lines: Key: value. + mimeHeader, err := tp.ReadMIMEHeader() + if err != nil { + return nil, err + } + req.Header = Header(mimeHeader) + + // RFC 7230, section 5.3: Must treat + // GET /index.html HTTP/1.1 + // Host: www.google.com + // and + // GET http://www.google.com/index.html HTTP/1.1 + // Host: doesntmatter + // the same. In the second case, any Host line is ignored. + req.Host = req.URL.Host + if req.Host == "" { + req.Host = req.Header.get("Host") + } + if deleteHostHeader { + delete(req.Header, "Host") + } + + fixPragmaCacheControl(req.Header) + + req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false) + + err = readTransfer(req, b) + if err != nil { + return nil, err + } + + if req.isH2Upgrade() { + // Because it's neither chunked, nor declared: + req.ContentLength = -1 + + // We want to give handlers a chance to hijack the + // connection, but we need to prevent the Server from + // dealing with the connection further if it's not + // hijacked. Set Close to ensure that: + req.Close = true + } + return req, nil +} + +// MaxBytesReader is similar to io.LimitReader but is intended for +// limiting the size of incoming request bodies. In contrast to +// io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a +// non-EOF error for a Read beyond the limit, and closes the +// underlying reader when its Close method is called. +// +// MaxBytesReader prevents clients from accidentally or maliciously +// sending a large request and wasting server resources. +func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser { + return &maxBytesReader{w: w, r: r, n: n} +} + +type maxBytesReader struct { + w ResponseWriter + r io.ReadCloser // underlying reader + n int64 // max bytes remaining + err error // sticky error +} + +func (l *maxBytesReader) Read(p []byte) (n int, err error) { + if l.err != nil { + return 0, l.err + } + if len(p) == 0 { + return 0, nil + } + // If they asked for a 32KB byte read but only 5 bytes are + // remaining, no need to read 32KB. 6 bytes will answer the + // question of the whether we hit the limit or go past it. + if int64(len(p)) > l.n+1 { + p = p[:l.n+1] + } + n, err = l.r.Read(p) + + if int64(n) <= l.n { + l.n -= int64(n) + l.err = err + return n, err + } + + n = int(l.n) + l.n = 0 + + // The server code and client code both use + // maxBytesReader. This "requestTooLarge" check is + // only used by the server code. To prevent binaries + // which only using the HTTP Client code (such as + // cmd/go) from also linking in the HTTP server, don't + // use a static type assertion to the server + // "*response" type. Check this interface instead: + type requestTooLarger interface { + requestTooLarge() + } + if res, ok := l.w.(requestTooLarger); ok { + res.requestTooLarge() + } + l.err = errors.New("http: request body too large") + return n, l.err +} + +func (l *maxBytesReader) Close() error { + return l.r.Close() +} + +func copyValues(dst, src url.Values) { + for k, vs := range src { + dst[k] = append(dst[k], vs...) + } +} + +func parsePostForm(r *Request) (vs url.Values, err error) { + if r.Body == nil { + err = errors.New("missing form body") + return + } + ct := r.Header.Get("Content-Type") + // RFC 7231, section 3.1.1.5 - empty type + // MAY be treated as application/octet-stream + if ct == "" { + ct = "application/octet-stream" + } + ct, _, err = mime.ParseMediaType(ct) + switch { + case ct == "application/x-www-form-urlencoded": + var reader io.Reader = r.Body + maxFormSize := int64(1<<63 - 1) + if _, ok := r.Body.(*maxBytesReader); !ok { + maxFormSize = int64(10 << 20) // 10 MB is a lot of text. + reader = io.LimitReader(r.Body, maxFormSize+1) + } + b, e := io.ReadAll(reader) + if e != nil { + if err == nil { + err = e + } + break + } + if int64(len(b)) > maxFormSize { + err = errors.New("http: POST too large") + return + } + vs, e = url.ParseQuery(string(b)) + if err == nil { + err = e + } + case ct == "multipart/form-data": + // handled by ParseMultipartForm (which is calling us, or should be) + // TODO(bradfitz): there are too many possible + // orders to call too many functions here. + // Clean this up and write more tests. + // request_test.go contains the start of this, + // in TestParseMultipartFormOrder and others. + } + return +} + +// ParseForm populates r.Form and r.PostForm. +// +// For all requests, ParseForm parses the raw query from the URL and updates +// r.Form. +// +// For POST, PUT, and PATCH requests, it also reads the request body, parses it +// as a form and puts the results into both r.PostForm and r.Form. Request body +// parameters take precedence over URL query string values in r.Form. +// +// If the request Body's size has not already been limited by MaxBytesReader, +// the size is capped at 10MB. +// +// For other HTTP methods, or when the Content-Type is not +// application/x-www-form-urlencoded, the request Body is not read, and +// r.PostForm is initialized to a non-nil, empty value. +// +// ParseMultipartForm calls ParseForm automatically. +// ParseForm is idempotent. +func (r *Request) ParseForm() error { + var err error + if r.PostForm == nil { + if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" { + r.PostForm, err = parsePostForm(r) + } + if r.PostForm == nil { + r.PostForm = make(url.Values) + } + } + if r.Form == nil { + if len(r.PostForm) > 0 { + r.Form = make(url.Values) + copyValues(r.Form, r.PostForm) + } + var newValues url.Values + if r.URL != nil { + var e error + newValues, e = url.ParseQuery(r.URL.RawQuery) + if err == nil { + err = e + } + } + if newValues == nil { + newValues = make(url.Values) + } + if r.Form == nil { + r.Form = newValues + } else { + copyValues(r.Form, newValues) + } + } + return err +} diff --git a/net/http/response.go b/net/http/response.go new file mode 100644 index 0000000..508ae39 --- /dev/null +++ b/net/http/response.go @@ -0,0 +1,112 @@ +package http + +import ( + "crypto/tls" + "io" +) + +// Response represents the response from an HTTP request. +// +// The Client and Transport return Responses from servers once +// the response headers have been received. The response body +// is streamed on demand as the Body field is read. +type Response struct { + Status string // e.g. "200 OK" + StatusCode int // e.g. 200 + Proto string // e.g. "HTTP/1.0" + ProtoMajor int // e.g. 1 + ProtoMinor int // e.g. 0 + + // Header maps header keys to values. If the response had multiple + // headers with the same key, they may be concatenated, with comma + // delimiters. (RFC 7230, section 3.2.2 requires that multiple headers + // be semantically equivalent to a comma-delimited sequence.) When + // Header values are duplicated by other fields in this struct (e.g., + // ContentLength, TransferEncoding, Trailer), the field values are + // authoritative. + // + // Keys in the map are canonicalized (see CanonicalHeaderKey). + Header Header + + // Body represents the response body. + // + // The response body is streamed on demand as the Body field + // is read. If the network connection fails or the server + // terminates the response, Body.Read calls return an error. + // + // The http Client and Transport guarantee that Body is always + // non-nil, even on responses without a body or responses with + // a zero-length body. It is the caller's responsibility to + // close Body. The default HTTP client's Transport may not + // reuse HTTP/1.x "keep-alive" TCP connections if the Body is + // not read to completion and closed. + // + // The Body is automatically dechunked if the server replied + // with a "chunked" Transfer-Encoding. + // + // As of Go 1.12, the Body will also implement io.Writer + // on a successful "101 Switching Protocols" response, + // as used by WebSockets and HTTP/2's "h2c" mode. + Body io.ReadCloser + + // ContentLength records the length of the associated content. The + // value -1 indicates that the length is unknown. Unless Request.Method + // is "HEAD", values >= 0 indicate that the given number of bytes may + // be read from Body. + ContentLength int64 + + // Contains transfer encodings from outer-most to inner-most. Value is + // nil, means that "identity" encoding is used. + TransferEncoding []string + + // Close records whether the header directed that the connection be + // closed after reading Body. The value is advice for clients: neither + // ReadResponse nor Response.Write ever closes a connection. + Close bool + + // Uncompressed reports whether the response was sent compressed but + // was decompressed by the http package. When true, reading from + // Body yields the uncompressed content instead of the compressed + // content actually set from the server, ContentLength is set to -1, + // and the "Content-Length" and "Content-Encoding" fields are deleted + // from the responseHeader. To get the original response from + // the server, set Transport.DisableCompression to true. + Uncompressed bool + + // Trailer maps trailer keys to values in the same + // format as Header. + // + // The Trailer initially contains only nil values, one for + // each key specified in the server's "Trailer" header + // value. Those values are not added to Header. + // + // Trailer must not be accessed concurrently with Read calls + // on the Body. + // + // After Body.Read has returned io.EOF, Trailer will contain + // any trailer values sent by the server. + Trailer Header + + // Request is the request that was sent to obtain this Response. + // Request's Body is nil (having already been consumed). + // This is only populated for Client requests. + Request *Request + + // TLS contains information about the TLS connection on which the + // response was received. It is nil for unencrypted responses. + // The pointer is shared between responses and should not be + // modified. + TLS *tls.ConnectionState +} + +// RFC 7234, section 5.4: Should treat +// Pragma: no-cache +// like +// Cache-Control: no-cache +func fixPragmaCacheControl(header Header) { + if hp, ok := header["Pragma"]; ok && len(hp) > 0 && hp[0] == "no-cache" { + if _, presentcc := header["Cache-Control"]; !presentcc { + header["Cache-Control"] = []string{"no-cache"} + } + } +} diff --git a/net/http/server.go b/net/http/server.go new file mode 100644 index 0000000..f497901 --- /dev/null +++ b/net/http/server.go @@ -0,0 +1,581 @@ +package http + +import ( + "fmt" + "net" + "net/url" + urlpkg "net/url" + "path" + "sort" + "strings" + "sync" +) + +// A Handler responds to an HTTP request. +// +// ServeHTTP should write reply headers and data to the ResponseWriter +// and then return. Returning signals that the request is finished; it +// is not valid to use the ResponseWriter or read from the +// Request.Body after or concurrently with the completion of the +// ServeHTTP call. +// +// Depending on the HTTP client software, HTTP protocol version, and +// any intermediaries between the client and the Go server, it may not +// be possible to read from the Request.Body after writing to the +// ResponseWriter. Cautious handlers should read the Request.Body +// first, and then reply. +// +// Except for reading the body, handlers should not modify the +// provided Request. +// +// If ServeHTTP panics, the server (the caller of ServeHTTP) assumes +// that the effect of the panic was isolated to the active request. +// It recovers the panic, logs a stack trace to the server error log, +// and either closes the network connection or sends an HTTP/2 +// RST_STREAM, depending on the HTTP protocol. To abort a handler so +// the client sees an interrupted response but the server doesn't log +// an error, panic with the value ErrAbortHandler. +type Handler interface { + ServeHTTP(ResponseWriter, *Request) +} + +// A ResponseWriter interface is used by an HTTP handler to +// construct an HTTP response. +// +// A ResponseWriter may not be used after the Handler.ServeHTTP method +// has returned. +type ResponseWriter interface { + // Header returns the header map that will be sent by + // WriteHeader. The Header map also is the mechanism with which + // Handlers can set HTTP trailers. + // + // Changing the header map after a call to WriteHeader (or + // Write) has no effect unless the modified headers are + // trailers. + // + // There are two ways to set Trailers. The preferred way is to + // predeclare in the headers which trailers you will later + // send by setting the "Trailer" header to the names of the + // trailer keys which will come later. In this case, those + // keys of the Header map are treated as if they were + // trailers. See the example. The second way, for trailer + // keys not known to the Handler until after the first Write, + // is to prefix the Header map keys with the TrailerPrefix + // constant value. See TrailerPrefix. + // + // To suppress automatic response headers (such as "Date"), set + // their value to nil. + Header() Header + + // Write writes the data to the connection as part of an HTTP reply. + // + // If WriteHeader has not yet been called, Write calls + // WriteHeader(http.StatusOK) before writing the data. If the Header + // does not contain a Content-Type line, Write adds a Content-Type set + // to the result of passing the initial 512 bytes of written data to + // DetectContentType. Additionally, if the total size of all written + // data is under a few KB and there are no Flush calls, the + // Content-Length header is added automatically. + // + // Depending on the HTTP protocol version and the client, calling + // Write or WriteHeader may prevent future reads on the + // Request.Body. For HTTP/1.x requests, handlers should read any + // needed request body data before writing the response. Once the + // headers have been flushed (due to either an explicit Flusher.Flush + // call or writing enough data to trigger a flush), the request body + // may be unavailable. For HTTP/2 requests, the Go HTTP server permits + // handlers to continue to read the request body while concurrently + // writing the response. However, such behavior may not be supported + // by all HTTP/2 clients. Handlers should read before writing if + // possible to maximize compatibility. + Write([]byte) (int, error) + + // WriteHeader sends an HTTP response header with the provided + // status code. + // + // If WriteHeader is not called explicitly, the first call to Write + // will trigger an implicit WriteHeader(http.StatusOK). + // Thus explicit calls to WriteHeader are mainly used to + // send error codes. + // + // The provided code must be a valid HTTP 1xx-5xx status code. + // Only one header may be written. Go does not currently + // support sending user-defined 1xx informational headers, + // with the exception of 100-continue response header that the + // Server sends automatically when the Request.Body is read. + WriteHeader(statusCode int) +} + +// TimeFormat is the time format to use when generating times in HTTP +// headers. It is like time.RFC1123 but hard-codes GMT as the time +// zone. The time being formatted must be in UTC for Format to +// generate the correct format. +// +// For parsing this time format, see ParseTime. +const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" + +// The HandlerFunc type is an adapter to allow the use of +// ordinary functions as HTTP handlers. If f is a function +// with the appropriate signature, HandlerFunc(f) is a +// Handler that calls f. +type HandlerFunc func(ResponseWriter, *Request) + +// ServeHTTP calls f(w, r). +func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { + f(w, r) +} + +// Helper handlers + +// Error replies to the request with the specified error message and HTTP code. +// It does not otherwise end the request; the caller should ensure no further +// writes are done to w. +// The error message should be plain text. +func Error(w ResponseWriter, error string, code int) { + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("X-Content-Type-Options", "nosniff") + w.WriteHeader(code) + fmt.Fprintln(w, error) +} + +// NotFound replies to the request with an HTTP 404 not found error. +func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) } + +// NotFoundHandler returns a simple request handler +// that replies to each request with a ``404 page not found'' reply. +func NotFoundHandler() Handler { return HandlerFunc(NotFound) } + +// StripPrefix returns a handler that serves HTTP requests by removing the +// given prefix from the request URL's Path (and RawPath if set) and invoking +// the handler h. StripPrefix handles a request for a path that doesn't begin +// with prefix by replying with an HTTP 404 not found error. The prefix must +// match exactly: if the prefix in the request contains escaped characters +// the reply is also an HTTP 404 not found error. +func StripPrefix(prefix string, h Handler) Handler { + if prefix == "" { + return h + } + return HandlerFunc(func(w ResponseWriter, r *Request) { + p := strings.TrimPrefix(r.URL.Path, prefix) + rp := strings.TrimPrefix(r.URL.RawPath, prefix) + if len(p) < len(r.URL.Path) && (r.URL.RawPath == "" || len(rp) < len(r.URL.RawPath)) { + r2 := new(Request) + *r2 = *r + r2.URL = new(url.URL) + *r2.URL = *r.URL + r2.URL.Path = p + r2.URL.RawPath = rp + h.ServeHTTP(w, r2) + } else { + NotFound(w, r) + } + }) +} + +// Redirect replies to the request with a redirect to url, +// which may be a path relative to the request path. +// +// The provided code should be in the 3xx range and is usually +// StatusMovedPermanently, StatusFound or StatusSeeOther. +// +// If the Content-Type header has not been set, Redirect sets it +// to "text/html; charset=utf-8" and writes a small HTML body. +// Setting the Content-Type header to any value, including nil, +// disables that behavior. +func Redirect(w ResponseWriter, r *Request, url string, code int) { + if u, err := urlpkg.Parse(url); err == nil { + // If url was relative, make its path absolute by + // combining with request path. + // The client would probably do this for us, + // but doing it ourselves is more reliable. + // See RFC 7231, section 7.1.2 + if u.Scheme == "" && u.Host == "" { + oldpath := r.URL.Path + if oldpath == "" { // should not happen, but avoid a crash if it does + oldpath = "/" + } + + // no leading http://server + if url == "" || url[0] != '/' { + // make relative path absolute + olddir, _ := path.Split(oldpath) + url = olddir + url + } + + var query string + if i := strings.Index(url, "?"); i != -1 { + url, query = url[:i], url[i:] + } + + // clean up but preserve trailing slash + trailing := strings.HasSuffix(url, "/") + url = path.Clean(url) + if trailing && !strings.HasSuffix(url, "/") { + url += "/" + } + url += query + } + } + + h := w.Header() + + // RFC 7231 notes that a short HTML body is usually included in + // the response because older user agents may not understand 301/307. + // Do it only if the request didn't already have a Content-Type header. + _, hadCT := h["Content-Type"] + + h.Set("Location", hexEscapeNonASCII(url)) + if !hadCT && (r.Method == "GET" || r.Method == "HEAD") { + h.Set("Content-Type", "text/html; charset=utf-8") + } + w.WriteHeader(code) + + // Shouldn't send the body for POST or HEAD; that leaves GET. + if !hadCT && r.Method == "GET" { + body := "" + statusText[code] + ".\n" + fmt.Fprintln(w, body) + } +} + +var htmlReplacer = strings.NewReplacer( + "&", "&", + "<", "<", + ">", ">", + // """ is shorter than """. + `"`, """, + // "'" is shorter than "'" and apos was not in HTML until HTML5. + "'", "'", +) + +func htmlEscape(s string) string { + return htmlReplacer.Replace(s) +} + +// Redirect to a fixed URL +type redirectHandler struct { + url string + code int +} + +func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) { + Redirect(w, r, rh.url, rh.code) +} + +// RedirectHandler returns a request handler that redirects +// each request it receives to the given url using the given +// status code. +// +// The provided code should be in the 3xx range and is usually +// StatusMovedPermanently, StatusFound or StatusSeeOther. +func RedirectHandler(url string, code int) Handler { + return &redirectHandler{url, code} +} + +// ServeMux is an HTTP request multiplexer. +// It matches the URL of each incoming request against a list of registered +// patterns and calls the handler for the pattern that +// most closely matches the URL. +// +// Patterns name fixed, rooted paths, like "/favicon.ico", +// or rooted subtrees, like "/images/" (note the trailing slash). +// Longer patterns take precedence over shorter ones, so that +// if there are handlers registered for both "/images/" +// and "/images/thumbnails/", the latter handler will be +// called for paths beginning "/images/thumbnails/" and the +// former will receive requests for any other paths in the +// "/images/" subtree. +// +// Note that since a pattern ending in a slash names a rooted subtree, +// the pattern "/" matches all paths not matched by other registered +// patterns, not just the URL with Path == "/". +// +// If a subtree has been registered and a request is received naming the +// subtree root without its trailing slash, ServeMux redirects that +// request to the subtree root (adding the trailing slash). This behavior can +// be overridden with a separate registration for the path without +// the trailing slash. For example, registering "/images/" causes ServeMux +// to redirect a request for "/images" to "/images/", unless "/images" has +// been registered separately. +// +// Patterns may optionally begin with a host name, restricting matches to +// URLs on that host only. Host-specific patterns take precedence over +// general patterns, so that a handler might register for the two patterns +// "/codesearch" and "codesearch.google.com/" without also taking over +// requests for "http://www.google.com/". +// +// ServeMux also takes care of sanitizing the URL request path and the Host +// header, stripping the port number and redirecting any request containing . or +// .. elements or repeated slashes to an equivalent, cleaner URL. +type ServeMux struct { + mu sync.RWMutex + m map[string]muxEntry + es []muxEntry // slice of entries sorted from longest to shortest. + hosts bool // whether any patterns contain hostnames +} + +type muxEntry struct { + h Handler + pattern string +} + +// NewServeMux allocates and returns a new ServeMux. +func NewServeMux() *ServeMux { return new(ServeMux) } + +// DefaultServeMux is the default ServeMux used by Serve. +var DefaultServeMux = &defaultServeMux + +var defaultServeMux ServeMux + +// cleanPath returns the canonical path for p, eliminating . and .. elements. +func cleanPath(p string) string { + if p == "" { + return "/" + } + if p[0] != '/' { + p = "/" + p + } + np := path.Clean(p) + // path.Clean removes trailing slash except for root; + // put the trailing slash back if necessary. + if p[len(p)-1] == '/' && np != "/" { + // Fast path for common case of p being the string we want: + if len(p) == len(np)+1 && strings.HasPrefix(p, np) { + np = p + } else { + np += "/" + } + } + return np +} + +// stripHostPort returns h without any trailing ":". +func stripHostPort(h string) string { + // If no port on host, return unchanged + if strings.IndexByte(h, ':') == -1 { + return h + } + host, _, err := net.SplitHostPort(h) + if err != nil { + return h // on error, return unchanged + } + return host +} + +// Find a handler on a handler map given a path string. +// Most-specific (longest) pattern wins. +func (mux *ServeMux) match(path string) (h Handler, pattern string) { + // Check for exact match first. + v, ok := mux.m[path] + if ok { + return v.h, v.pattern + } + + // Check for longest valid match. mux.es contains all patterns + // that end in / sorted from longest to shortest. + for _, e := range mux.es { + if strings.HasPrefix(path, e.pattern) { + return e.h, e.pattern + } + } + return nil, "" +} + +// redirectToPathSlash determines if the given path needs appending "/" to it. +// This occurs when a handler for path + "/" was already registered, but +// not for path itself. If the path needs appending to, it creates a new +// URL, setting the path to u.Path + "/" and returning true to indicate so. +func (mux *ServeMux) redirectToPathSlash(host, path string, u *url.URL) (*url.URL, bool) { + mux.mu.RLock() + shouldRedirect := mux.shouldRedirectRLocked(host, path) + mux.mu.RUnlock() + if !shouldRedirect { + return u, false + } + path = path + "/" + u = &url.URL{Path: path, RawQuery: u.RawQuery} + return u, true +} + +// shouldRedirectRLocked reports whether the given path and host should be redirected to +// path+"/". This should happen if a handler is registered for path+"/" but +// not path -- see comments at ServeMux. +func (mux *ServeMux) shouldRedirectRLocked(host, path string) bool { + p := []string{path, host + path} + + for _, c := range p { + if _, exist := mux.m[c]; exist { + return false + } + } + + n := len(path) + if n == 0 { + return false + } + for _, c := range p { + if _, exist := mux.m[c+"/"]; exist { + return path[n-1] != '/' + } + } + + return false +} + +// Handler returns the handler to use for the given request, +// consulting r.Method, r.Host, and r.URL.Path. It always returns +// a non-nil handler. If the path is not in its canonical form, the +// handler will be an internally-generated handler that redirects +// to the canonical path. If the host contains a port, it is ignored +// when matching handlers. +// +// The path and host are used unchanged for CONNECT requests. +// +// Handler also returns the registered pattern that matches the +// request or, in the case of internally-generated redirects, +// the pattern that will match after following the redirect. +// +// If there is no registered handler that applies to the request, +// Handler returns a ``page not found'' handler and an empty pattern. +func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { + + // CONNECT requests are not canonicalized. + if r.Method == "CONNECT" { + // If r.URL.Path is /tree and its handler is not registered, + // the /tree -> /tree/ redirect applies to CONNECT requests + // but the path canonicalization does not. + if u, ok := mux.redirectToPathSlash(r.URL.Host, r.URL.Path, r.URL); ok { + return RedirectHandler(u.String(), StatusMovedPermanently), u.Path + } + + return mux.handler(r.Host, r.URL.Path) + } + + // All other requests have any port stripped and path cleaned + // before passing to mux.handler. + host := stripHostPort(r.Host) + path := cleanPath(r.URL.Path) + + // If the given path is /tree and its handler is not registered, + // redirect for /tree/. + if u, ok := mux.redirectToPathSlash(host, path, r.URL); ok { + return RedirectHandler(u.String(), StatusMovedPermanently), u.Path + } + + if path != r.URL.Path { + _, pattern = mux.handler(host, path) + url := *r.URL + url.Path = path + return RedirectHandler(url.String(), StatusMovedPermanently), pattern + } + + return mux.handler(host, r.URL.Path) +} + +// handler is the main implementation of Handler. +// The path is known to be in canonical form, except for CONNECT methods. +func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { + mux.mu.RLock() + defer mux.mu.RUnlock() + + // Host-specific pattern takes precedence over generic ones + if mux.hosts { + h, pattern = mux.match(host + path) + } + if h == nil { + h, pattern = mux.match(path) + } + if h == nil { + h, pattern = NotFoundHandler(), "" + } + return +} + +// ServeHTTP dispatches the request to the handler whose +// pattern most closely matches the request URL. +func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { + if r.RequestURI == "*" { + if r.ProtoAtLeast(1, 1) { + w.Header().Set("Connection", "close") + } + w.WriteHeader(StatusBadRequest) + return + } + h, _ := mux.Handler(r) + h.ServeHTTP(w, r) +} + +// Handle registers the handler for the given pattern. +// If a handler already exists for pattern, Handle panics. +func (mux *ServeMux) Handle(pattern string, handler Handler) { + mux.mu.Lock() + defer mux.mu.Unlock() + + if pattern == "" { + panic("http: invalid pattern") + } + if handler == nil { + panic("http: nil handler") + } + if _, exist := mux.m[pattern]; exist { + panic("http: multiple registrations for " + pattern) + } + + if mux.m == nil { + mux.m = make(map[string]muxEntry) + } + e := muxEntry{h: handler, pattern: pattern} + mux.m[pattern] = e + if pattern[len(pattern)-1] == '/' { + mux.es = appendSorted(mux.es, e) + } + + if pattern[0] != '/' { + mux.hosts = true + } +} + +func appendSorted(es []muxEntry, e muxEntry) []muxEntry { + n := len(es) + i := sort.Search(n, func(i int) bool { + return len(es[i].pattern) < len(e.pattern) + }) + if i == n { + return append(es, e) + } + // we now know that i points at where we want to insert + es = append(es, muxEntry{}) // try to grow the slice in place, any entry works. + copy(es[i+1:], es[i:]) // Move shorter entries down + es[i] = e + return es +} + +// HandleFunc registers the handler function for the given pattern. +func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { + if handler == nil { + panic("http: nil handler") + } + mux.Handle(pattern, HandlerFunc(handler)) +} + +// Handle registers the handler for the given pattern +// in the DefaultServeMux. +// The documentation for ServeMux explains how patterns are matched. +func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) } + +// HandleFunc registers the handler function for the given pattern +// in the DefaultServeMux. +// The documentation for ServeMux explains how patterns are matched. +func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { + DefaultServeMux.HandleFunc(pattern, handler) +} + +// ListenAndServe listens on the TCP network address addr and then calls +// Serve with handler to handle requests on incoming connections. +// Accepted connections are configured to enable TCP keep-alives. +// +// The handler is typically nil, in which case the DefaultServeMux is used. +// +// ListenAndServe always returns a non-nil error. +func ListenAndServe(addr string, handler Handler) error { + return ActiveDevice.ListenAndServe(addr, handler) +} diff --git a/net/http/status.go b/net/http/status.go new file mode 100644 index 0000000..286315f --- /dev/null +++ b/net/http/status.go @@ -0,0 +1,152 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http + +// HTTP status codes as registered with IANA. +// See: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml +const ( + StatusContinue = 100 // RFC 7231, 6.2.1 + StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2 + StatusProcessing = 102 // RFC 2518, 10.1 + StatusEarlyHints = 103 // RFC 8297 + + StatusOK = 200 // RFC 7231, 6.3.1 + StatusCreated = 201 // RFC 7231, 6.3.2 + StatusAccepted = 202 // RFC 7231, 6.3.3 + StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4 + StatusNoContent = 204 // RFC 7231, 6.3.5 + StatusResetContent = 205 // RFC 7231, 6.3.6 + StatusPartialContent = 206 // RFC 7233, 4.1 + StatusMultiStatus = 207 // RFC 4918, 11.1 + StatusAlreadyReported = 208 // RFC 5842, 7.1 + StatusIMUsed = 226 // RFC 3229, 10.4.1 + + StatusMultipleChoices = 300 // RFC 7231, 6.4.1 + StatusMovedPermanently = 301 // RFC 7231, 6.4.2 + StatusFound = 302 // RFC 7231, 6.4.3 + StatusSeeOther = 303 // RFC 7231, 6.4.4 + StatusNotModified = 304 // RFC 7232, 4.1 + StatusUseProxy = 305 // RFC 7231, 6.4.5 + _ = 306 // RFC 7231, 6.4.6 (Unused) + StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7 + StatusPermanentRedirect = 308 // RFC 7538, 3 + + StatusBadRequest = 400 // RFC 7231, 6.5.1 + StatusUnauthorized = 401 // RFC 7235, 3.1 + StatusPaymentRequired = 402 // RFC 7231, 6.5.2 + StatusForbidden = 403 // RFC 7231, 6.5.3 + StatusNotFound = 404 // RFC 7231, 6.5.4 + StatusMethodNotAllowed = 405 // RFC 7231, 6.5.5 + StatusNotAcceptable = 406 // RFC 7231, 6.5.6 + StatusProxyAuthRequired = 407 // RFC 7235, 3.2 + StatusRequestTimeout = 408 // RFC 7231, 6.5.7 + StatusConflict = 409 // RFC 7231, 6.5.8 + StatusGone = 410 // RFC 7231, 6.5.9 + StatusLengthRequired = 411 // RFC 7231, 6.5.10 + StatusPreconditionFailed = 412 // RFC 7232, 4.2 + StatusRequestEntityTooLarge = 413 // RFC 7231, 6.5.11 + StatusRequestURITooLong = 414 // RFC 7231, 6.5.12 + StatusUnsupportedMediaType = 415 // RFC 7231, 6.5.13 + StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4 + StatusExpectationFailed = 417 // RFC 7231, 6.5.14 + StatusTeapot = 418 // RFC 7168, 2.3.3 + StatusMisdirectedRequest = 421 // RFC 7540, 9.1.2 + StatusUnprocessableEntity = 422 // RFC 4918, 11.2 + StatusLocked = 423 // RFC 4918, 11.3 + StatusFailedDependency = 424 // RFC 4918, 11.4 + StatusTooEarly = 425 // RFC 8470, 5.2. + StatusUpgradeRequired = 426 // RFC 7231, 6.5.15 + StatusPreconditionRequired = 428 // RFC 6585, 3 + StatusTooManyRequests = 429 // RFC 6585, 4 + StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5 + StatusUnavailableForLegalReasons = 451 // RFC 7725, 3 + + StatusInternalServerError = 500 // RFC 7231, 6.6.1 + StatusNotImplemented = 501 // RFC 7231, 6.6.2 + StatusBadGateway = 502 // RFC 7231, 6.6.3 + StatusServiceUnavailable = 503 // RFC 7231, 6.6.4 + StatusGatewayTimeout = 504 // RFC 7231, 6.6.5 + StatusHTTPVersionNotSupported = 505 // RFC 7231, 6.6.6 + StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1 + StatusInsufficientStorage = 507 // RFC 4918, 11.5 + StatusLoopDetected = 508 // RFC 5842, 7.2 + StatusNotExtended = 510 // RFC 2774, 7 + StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6 +) + +var statusText = map[int]string{ + StatusContinue: "Continue", + StatusSwitchingProtocols: "Switching Protocols", + StatusProcessing: "Processing", + StatusEarlyHints: "Early Hints", + + StatusOK: "OK", + StatusCreated: "Created", + StatusAccepted: "Accepted", + StatusNonAuthoritativeInfo: "Non-Authoritative Information", + StatusNoContent: "No Content", + StatusResetContent: "Reset Content", + StatusPartialContent: "Partial Content", + StatusMultiStatus: "Multi-Status", + StatusAlreadyReported: "Already Reported", + StatusIMUsed: "IM Used", + + StatusMultipleChoices: "Multiple Choices", + StatusMovedPermanently: "Moved Permanently", + StatusFound: "Found", + StatusSeeOther: "See Other", + StatusNotModified: "Not Modified", + StatusUseProxy: "Use Proxy", + StatusTemporaryRedirect: "Temporary Redirect", + StatusPermanentRedirect: "Permanent Redirect", + + StatusBadRequest: "Bad Request", + StatusUnauthorized: "Unauthorized", + StatusPaymentRequired: "Payment Required", + StatusForbidden: "Forbidden", + StatusNotFound: "Not Found", + StatusMethodNotAllowed: "Method Not Allowed", + StatusNotAcceptable: "Not Acceptable", + StatusProxyAuthRequired: "Proxy Authentication Required", + StatusRequestTimeout: "Request Timeout", + StatusConflict: "Conflict", + StatusGone: "Gone", + StatusLengthRequired: "Length Required", + StatusPreconditionFailed: "Precondition Failed", + StatusRequestEntityTooLarge: "Request Entity Too Large", + StatusRequestURITooLong: "Request URI Too Long", + StatusUnsupportedMediaType: "Unsupported Media Type", + StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable", + StatusExpectationFailed: "Expectation Failed", + StatusTeapot: "I'm a teapot", + StatusMisdirectedRequest: "Misdirected Request", + StatusUnprocessableEntity: "Unprocessable Entity", + StatusLocked: "Locked", + StatusFailedDependency: "Failed Dependency", + StatusTooEarly: "Too Early", + StatusUpgradeRequired: "Upgrade Required", + StatusPreconditionRequired: "Precondition Required", + StatusTooManyRequests: "Too Many Requests", + StatusRequestHeaderFieldsTooLarge: "Request Header Fields Too Large", + StatusUnavailableForLegalReasons: "Unavailable For Legal Reasons", + + StatusInternalServerError: "Internal Server Error", + StatusNotImplemented: "Not Implemented", + StatusBadGateway: "Bad Gateway", + StatusServiceUnavailable: "Service Unavailable", + StatusGatewayTimeout: "Gateway Timeout", + StatusHTTPVersionNotSupported: "HTTP Version Not Supported", + StatusVariantAlsoNegotiates: "Variant Also Negotiates", + StatusInsufficientStorage: "Insufficient Storage", + StatusLoopDetected: "Loop Detected", + StatusNotExtended: "Not Extended", + StatusNetworkAuthenticationRequired: "Network Authentication Required", +} + +// StatusText returns a text for the HTTP status code. It returns the empty +// string if the code is unknown. +func StatusText(code int) string { + return statusText[code] +} diff --git a/net/http/transefer.go b/net/http/transefer.go new file mode 100644 index 0000000..d9a4406 --- /dev/null +++ b/net/http/transefer.go @@ -0,0 +1,34 @@ +package http + +import ( + "bufio" + + "golang.org/x/net/http/httpguts" +) + +// msg is *Request or *Response. +func readTransfer(msg *Request, r *bufio.Reader) (err error) { + // TODO: + return nil +} + +// Determine whether to hang up after sending a request and body, or +// receiving a response and body +// 'header' is the request headers +func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool { + if major < 1 { + return true + } + + conv := header["Connection"] + hasClose := httpguts.HeaderValuesContainsToken(conv, "close") + if major == 1 && minor == 0 { + return hasClose || !httpguts.HeaderValuesContainsToken(conv, "keep-alive") + } + + if hasClose && removeCloseHeader { + header.Del("Connection") + } + + return hasClose +} diff --git a/rtl8720dn/http.go b/rtl8720dn/http.go new file mode 100644 index 0000000..921ee9d --- /dev/null +++ b/rtl8720dn/http.go @@ -0,0 +1,236 @@ +package rtl8720dn + +import ( + "bufio" + "bytes" + "fmt" + "io" + "time" + + "tinygo.org/x/drivers/net/http" +) + +func (rtl *RTL8720DN) setupHTTPServer() error { + _, err := rtl.Rpc_lwip_close(-1) + if err != nil { + return err + } + + _, err = rtl.Rpc_lwip_socket(0x00000002, 0x00000001, 0x00000000) + if err != nil { + return err + } + + name := []byte{0x00, 0x02, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x42, 0x00, 0x00, 0xC7, 0x61, 0x01, 0x00} + _, err = rtl.Rpc_lwip_bind(0, name, uint32(len(name))) + if err != nil { + return err + } + + _, err = rtl.Rpc_lwip_listen(0, 4) + if err != nil { + return err + } + + _, err = rtl.Rpc_lwip_fcntl(0, 4, 1) + if err != nil { + return err + } + + return nil +} + +func (rtl *RTL8720DN) accept() (bool, error) { + addr := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xD7, 0x00, 0x20, 0x00, 0xD8, 0x00, 0x20} + length := uint32(len(addr)) + ret, err := rtl.Rpc_lwip_accept(0, addr, &length) + if err != nil { + return false, err + } + + return ret == 1, nil +} + +func (rtl *RTL8720DN) handleHTTP() error { + socket := int32(1) + optval := []byte{0x01, 0x00, 0x00, 0x00} + _, err := rtl.Rpc_lwip_setsockopt(socket, 0x00000FFF, 8, optval, uint32(len(optval))) + if err != nil { + return nil + } + + _, err = rtl.Rpc_lwip_setsockopt(socket, 6, 1, optval, uint32(len(optval))) + if err != nil { + return nil + } + + buf := make([]byte, 4096) + for { + _, err = rtl.Rpc_lwip_recv(socket, &buf, uint32(len(buf)), 8, 0) + if err != nil { + return nil + } + if len(buf) > 0 { + break + } + + _, err = rtl.Rpc_lwip_errno() + if err != nil { + return nil + } + + time.Sleep(100 * time.Millisecond) + } + + buf2 := make([]byte, 4096) + result, err := rtl.Rpc_lwip_recv(socket, &buf2, uint32(len(buf2)), 8, 0) + if err != nil { + return nil + } + if result != -1 && result != 0 { + return fmt.Errorf("Rpc_lwip_recv error") + } + + result, err = rtl.Rpc_lwip_errno() + if err != nil { + return nil + } + if result != 11 { + return fmt.Errorf("Rpc_lwip_errno error") + } + + b := bufio.NewReader(bytes.NewReader(buf)) + req, err := http.ReadRequest(b) + if err != nil { + return err + } + if rtl.debug { + fmt.Printf("%s %s %s\r\n", req.Method, req.RequestURI, req.Proto) + } + + pos := bytes.Index(buf, []byte("\r\n\r\n")) + if pos > 0 { + body := bytes.NewReader(buf[pos+4:]) + req.Body = io.NopCloser(body) + } + + handler, _ := http.DefaultServeMux.Handler(req) + rwx := responseWriter{ + header: http.Header{}, + statusCode: 200, + } + rwx.header.Add(`Content-Type`, `text/html; charset=UTF-8`) + rwx.header.Add(`Connection`, `close`) + handler.ServeHTTP(&rwx, req) + rwx.header.Add(`Content-Length`, fmt.Sprintf("%d", len(rwx.Buf))) + + optval = []byte{0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0xA5, 0xA5, 0xA5} + _, err = rtl.Rpc_lwip_setsockopt(socket, 0x00000FFF, 0x1006, optval, uint32(len(optval))) + if err != nil { + return nil + } + + optval = []byte{0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0xA5, 0xA5, 0xA5} + _, err = rtl.Rpc_lwip_setsockopt(socket, 0x00000FFF, 0x1005, optval, uint32(len(optval))) + if err != nil { + return nil + } + + maxfdp1 := int32(2) + writeset := []byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + timeout := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0F, 0x00, 0x0A, 0x00, 0x00, 0x00} + _, err = rtl.Rpc_lwip_select(maxfdp1, []byte{}, writeset, []byte{}, timeout) + if err != nil { + return nil + } + + msg := rwx.Buf + hb := bytes.Buffer{} + err = rwx.header.Write(&hb) + if err != nil { + return err + } + + data := []byte(fmt.Sprintf("HTTP/1.1 %d OK\n", rwx.statusCode)) + data = append(data, hb.Bytes()...) + data = append(data, byte('\n')) + + _, err = rtl.Rpc_lwip_send(socket, data, 8) + if err != nil { + return nil + } + + if len(msg) > 0 { + timeout = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0F, 0x00, 0x54, 0x00, 0x00, 0x00} + _, err = rtl.Rpc_lwip_select(maxfdp1, []byte{}, writeset, []byte{}, timeout) + if err != nil { + return nil + } + + _, err = rtl.Rpc_lwip_send(socket, msg, 8) + if err != nil { + return nil + } + } + + for i := 0; i < 4; i++ { + buf := make([]byte, 4096) + _, err = rtl.Rpc_lwip_recv(socket, &buf, uint32(len(buf)), 8, 0) + if err != nil { + return nil + } + + _, err = rtl.Rpc_lwip_errno() + if err != nil { + return nil + } + } + + _, err = rtl.Rpc_lwip_close(socket) + if err != nil { + return nil + } + return nil +} + +func (rtl *RTL8720DN) ListenAndServe(addr string, handler http.Handler) error { + err := rtl.setupHTTPServer() + if err != nil { + return err + } + + for { + connected, err := rtl.accept() + if err != nil { + return err + } + + if connected { + err := rtl.handleHTTP() + if err != nil { + return err + } + } + + time.Sleep(100 * time.Millisecond) + } +} + +type responseWriter struct { + Buf []byte + header http.Header + statusCode int +} + +func (r *responseWriter) Header() http.Header { + return r.header +} + +func (r *responseWriter) Write(b []byte) (int, error) { + r.Buf = append(r.Buf, b...) + return len(b), nil +} + +func (r *responseWriter) WriteHeader(statusCode int) { + r.statusCode = statusCode +} diff --git a/rtl8720dn/netdriver.go b/rtl8720dn/netdriver.go index 56f438d..f646cdc 100644 --- a/rtl8720dn/netdriver.go +++ b/rtl8720dn/netdriver.go @@ -12,8 +12,8 @@ func (r *RTL8720DN) GetDNS(domain string) (string, error) { fmt.Printf("GetDNS(%q)\r\n", domain) } - ipaddr := [4]byte{} - _, err := r.Rpc_netconn_gethostbyname(domain, ipaddr[:]) + ipaddr := make([]byte, 4) + _, err := r.Rpc_netconn_gethostbyname(domain, &ipaddr) if err != nil { return "", err } @@ -31,8 +31,8 @@ func (r *RTL8720DN) ConnectTCPSocket(addr, port string) error { fmt.Printf("ConnectTCPSocket(%q, %q)\r\n", addr, port) } - ipaddr := [4]byte{} - _, err := r.Rpc_netconn_gethostbyname(addr, ipaddr[:]) + ipaddr := make([]byte, 4) + _, err := r.Rpc_netconn_gethostbyname(addr, &ipaddr) if err != nil { return err } @@ -81,8 +81,9 @@ func (r *RTL8720DN) ConnectTCPSocket(addr, port string) error { return err } - optlen := uint32(4) - _, err = r.Rpc_lwip_getsockopt(socket, 0x00000FFF, 0x00001007, []byte{0xA5, 0xA5, 0xA5, 0xA5}, nil, optlen) + optval := make([]byte, 4) + optlen := uint32(len(optval)) + _, err = r.Rpc_lwip_getsockopt(socket, 0x00000FFF, 0x00001007, []byte{0xA5, 0xA5, 0xA5, 0xA5}, &optval, &optlen) if err != nil { return err } @@ -225,7 +226,7 @@ func (r *RTL8720DN) ReadSocket(b []byte) (n int, err error) { switch r.connectionType { case ConnectionTypeTCP: - nn, err := r.Rpc_lwip_recv(r.socket, b, uint32(len(b)), 0x00000008, 0x00002800) + nn, err := r.Rpc_lwip_recv(r.socket, &b, uint32(len(b)), 0x00000008, 0x00002800) if err != nil { return 0, err } @@ -245,7 +246,7 @@ func (r *RTL8720DN) ReadSocket(b []byte) (n int, err error) { } n = int(nn) case ConnectionTypeTLS: - nn, err := r.Rpc_wifi_get_ssl_receive(r.client, b, int32(len(b))) + nn, err := r.Rpc_wifi_get_ssl_receive(r.client, &b, int32(len(b))) if err != nil { return 0, err } diff --git a/rtl8720dn/rpc.go b/rtl8720dn/rpc.go index 5d31294..a8a137a 100644 --- a/rtl8720dn/rpc.go +++ b/rtl8720dn/rpc.go @@ -138,7 +138,7 @@ func (r *RTL8720DN) Rpc_gap_set_param(param RPC_T_GAP_PARAM_TYPE, value []byte) return result, err } -func (r *RTL8720DN) Rpc_gap_get_param(param RPC_T_GAP_PARAM_TYPE, value []byte) (RPC_T_GAP_CAUSE, error) { +func (r *RTL8720DN) Rpc_gap_get_param(param RPC_T_GAP_PARAM_TYPE, value *[]byte) (RPC_T_GAP_CAUSE, error) { if r.debug { fmt.Printf("rpc_gap_get_param()\r\n") } @@ -161,9 +161,10 @@ func (r *RTL8720DN) Rpc_gap_get_param(param RPC_T_GAP_PARAM_TYPE, value []byte) value_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if value_length > 0 { - copy(value, payload[widx:widx+int(value_length)]) + copy(*value, payload[widx:widx+int(value_length)]) widx += int(value_length) } + *value = (*value)[:value_length] var result RPC_T_GAP_CAUSE result = RPC_T_GAP_CAUSE(binary.LittleEndian.Uint32(payload[widx:])) @@ -222,7 +223,7 @@ func (r *RTL8720DN) Rpc_le_bond_set_param(param RPC_T_LE_BOND_PARAM_TYPE, value return result, err } -func (r *RTL8720DN) Rpc_le_bond_get_param(param RPC_T_LE_BOND_PARAM_TYPE, value []byte) (RPC_T_GAP_CAUSE, error) { +func (r *RTL8720DN) Rpc_le_bond_get_param(param RPC_T_LE_BOND_PARAM_TYPE, value *[]byte) (RPC_T_GAP_CAUSE, error) { if r.debug { fmt.Printf("rpc_le_bond_get_param()\r\n") } @@ -245,9 +246,10 @@ func (r *RTL8720DN) Rpc_le_bond_get_param(param RPC_T_LE_BOND_PARAM_TYPE, value value_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if value_length > 0 { - copy(value, payload[widx:widx+int(value_length)]) + copy(*value, payload[widx:widx+int(value_length)]) widx += int(value_length) } + *value = (*value)[:value_length] var result RPC_T_GAP_CAUSE result = RPC_T_GAP_CAUSE(binary.LittleEndian.Uint32(payload[widx:])) @@ -280,7 +282,7 @@ func (r *RTL8720DN) Rpc_le_bond_pair(conn_id uint8) (RPC_T_GAP_CAUSE, error) { return result, err } -func (r *RTL8720DN) Rpc_le_bond_get_display_key(conn_id uint8, key uint32) (RPC_T_GAP_CAUSE, error) { +func (r *RTL8720DN) Rpc_le_bond_get_display_key(conn_id uint8, key *uint32) (RPC_T_GAP_CAUSE, error) { if r.debug { fmt.Printf("rpc_le_bond_get_display_key()\r\n") } @@ -297,7 +299,8 @@ func (r *RTL8720DN) Rpc_le_bond_get_display_key(conn_id uint8, key uint32) (RPC_ <-r.received widx := 8 // key : out uint32 - // not impl + *key = binary.LittleEndian.Uint32(payload[widx:]) + widx += 4 var result RPC_T_GAP_CAUSE result = RPC_T_GAP_CAUSE(binary.LittleEndian.Uint32(payload[widx:])) @@ -569,7 +572,7 @@ func (r *RTL8720DN) Rpc_le_bond_get_sec_level(conn_id uint8, sec_type RPC_T_GAP_ <-r.received widx := 8 // sec_type : out RPC_T_GAP_SEC_LEVEL - // not impl + // not impl (a.Size() > 0) var result RPC_T_GAP_CAUSE result = RPC_T_GAP_CAUSE(binary.LittleEndian.Uint32(payload[widx:])) @@ -676,7 +679,7 @@ func (r *RTL8720DN) Rpc_le_set_gap_param(param RPC_T_GAP_LE_PARAM_TYPE, value [] return result, err } -func (r *RTL8720DN) Rpc_le_get_gap_param(param RPC_T_GAP_LE_PARAM_TYPE, value []byte) (RPC_T_GAP_CAUSE, error) { +func (r *RTL8720DN) Rpc_le_get_gap_param(param RPC_T_GAP_LE_PARAM_TYPE, value *[]byte) (RPC_T_GAP_CAUSE, error) { if r.debug { fmt.Printf("rpc_le_get_gap_param()\r\n") } @@ -699,9 +702,10 @@ func (r *RTL8720DN) Rpc_le_get_gap_param(param RPC_T_GAP_LE_PARAM_TYPE, value [] value_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if value_length > 0 { - copy(value, payload[widx:widx+int(value_length)]) + copy(*value, payload[widx:widx+int(value_length)]) widx += int(value_length) } + *value = (*value)[:value_length] var result RPC_T_GAP_CAUSE result = RPC_T_GAP_CAUSE(binary.LittleEndian.Uint32(payload[widx:])) @@ -744,7 +748,7 @@ func (r *RTL8720DN) Rpc_le_modify_white_list(operation RPC_T_GAP_WHITE_LIST_OP, return result, err } -func (r *RTL8720DN) Rpc_le_gen_rand_addr(rand_addr_type RPC_T_GAP_RAND_ADDR_TYPE, random_bd uint8) (RPC_T_GAP_CAUSE, error) { +func (r *RTL8720DN) Rpc_le_gen_rand_addr(rand_addr_type RPC_T_GAP_RAND_ADDR_TYPE, random_bd *uint8) (RPC_T_GAP_CAUSE, error) { if r.debug { fmt.Printf("rpc_le_gen_rand_addr()\r\n") } @@ -764,7 +768,8 @@ func (r *RTL8720DN) Rpc_le_gen_rand_addr(rand_addr_type RPC_T_GAP_RAND_ADDR_TYPE <-r.received widx := 8 // random_bd : out uint8 - // not impl + *random_bd = payload[widx] + widx += 1 var result RPC_T_GAP_CAUSE result = RPC_T_GAP_CAUSE(binary.LittleEndian.Uint32(payload[widx:])) @@ -1095,7 +1100,7 @@ func (r *RTL8720DN) Rpc_le_adv_set_param(param RPC_T_LE_ADV_PARAM_TYPE, value [] return result, err } -func (r *RTL8720DN) Rpc_le_adv_get_param(param RPC_T_LE_ADV_PARAM_TYPE, value []byte) (RPC_T_GAP_CAUSE, error) { +func (r *RTL8720DN) Rpc_le_adv_get_param(param RPC_T_LE_ADV_PARAM_TYPE, value *[]byte) (RPC_T_GAP_CAUSE, error) { if r.debug { fmt.Printf("rpc_le_adv_get_param()\r\n") } @@ -1118,9 +1123,10 @@ func (r *RTL8720DN) Rpc_le_adv_get_param(param RPC_T_LE_ADV_PARAM_TYPE, value [] value_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if value_length > 0 { - copy(value, payload[widx:widx+int(value_length)]) + copy(*value, payload[widx:widx+int(value_length)]) widx += int(value_length) } + *value = (*value)[:value_length] var result RPC_T_GAP_CAUSE result = RPC_T_GAP_CAUSE(binary.LittleEndian.Uint32(payload[widx:])) @@ -1219,7 +1225,7 @@ func (r *RTL8720DN) Rpc_le_scan_set_param(param RPC_T_LE_SCAN_PARAM_TYPE, value return result, err } -func (r *RTL8720DN) Rpc_le_scan_get_param(param RPC_T_LE_SCAN_PARAM_TYPE, value []byte) (RPC_T_GAP_CAUSE, error) { +func (r *RTL8720DN) Rpc_le_scan_get_param(param RPC_T_LE_SCAN_PARAM_TYPE, value *[]byte) (RPC_T_GAP_CAUSE, error) { if r.debug { fmt.Printf("rpc_le_scan_get_param()\r\n") } @@ -1242,9 +1248,10 @@ func (r *RTL8720DN) Rpc_le_scan_get_param(param RPC_T_LE_SCAN_PARAM_TYPE, value value_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if value_length > 0 { - copy(value, payload[widx:widx+int(value_length)]) + copy(*value, payload[widx:widx+int(value_length)]) widx += int(value_length) } + *value = (*value)[:value_length] var result RPC_T_GAP_CAUSE result = RPC_T_GAP_CAUSE(binary.LittleEndian.Uint32(payload[widx:])) @@ -1354,7 +1361,7 @@ func (r *RTL8720DN) Rpc_le_scan_info_filter(enable bool, offset uint8, length ui return result, err } -func (r *RTL8720DN) Rpc_le_get_conn_param(param RPC_T_LE_CONN_PARAM_TYPE, value []byte, conn_id uint8) (RPC_T_GAP_CAUSE, error) { +func (r *RTL8720DN) Rpc_le_get_conn_param(param RPC_T_LE_CONN_PARAM_TYPE, value *[]byte, conn_id uint8) (RPC_T_GAP_CAUSE, error) { if r.debug { fmt.Printf("rpc_le_get_conn_param()\r\n") } @@ -1379,9 +1386,10 @@ func (r *RTL8720DN) Rpc_le_get_conn_param(param RPC_T_LE_CONN_PARAM_TYPE, value value_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if value_length > 0 { - copy(value, payload[widx:widx+int(value_length)]) + copy(*value, payload[widx:widx+int(value_length)]) widx += int(value_length) } + *value = (*value)[:value_length] var result RPC_T_GAP_CAUSE result = RPC_T_GAP_CAUSE(binary.LittleEndian.Uint32(payload[widx:])) @@ -1407,7 +1415,7 @@ func (r *RTL8720DN) Rpc_le_get_conn_info(conn_id uint8, p_conn_info RPC_T_GAP_CO <-r.received widx := 8 // p_conn_info : out RPC_T_GAP_CONN_INFO - // not impl + // not impl (a.Size() > 0) var result bool result = binary.LittleEndian.Uint32(payload[widx:]) == 1 @@ -1416,7 +1424,7 @@ func (r *RTL8720DN) Rpc_le_get_conn_info(conn_id uint8, p_conn_info RPC_T_GAP_CO return result, err } -func (r *RTL8720DN) Rpc_le_get_conn_addr(conn_id uint8, bd_addr uint8, bd_type uint8) (bool, error) { +func (r *RTL8720DN) Rpc_le_get_conn_addr(conn_id uint8, bd_addr *uint8, bd_type *uint8) (bool, error) { if r.debug { fmt.Printf("rpc_le_get_conn_addr()\r\n") } @@ -1433,9 +1441,11 @@ func (r *RTL8720DN) Rpc_le_get_conn_addr(conn_id uint8, bd_addr uint8, bd_type u <-r.received widx := 8 // bd_addr : out uint8 - // not impl + *bd_addr = payload[widx] + widx += 1 // bd_type : out uint8 - // not impl + *bd_type = payload[widx] + widx += 1 var result bool result = binary.LittleEndian.Uint32(payload[widx:]) == 1 @@ -1444,7 +1454,7 @@ func (r *RTL8720DN) Rpc_le_get_conn_addr(conn_id uint8, bd_addr uint8, bd_type u return result, err } -func (r *RTL8720DN) Rpc_le_get_conn_id(bd_addr uint8, bd_type uint8, p_conn_id uint8) (bool, error) { +func (r *RTL8720DN) Rpc_le_get_conn_id(bd_addr uint8, bd_type uint8, p_conn_id *uint8) (bool, error) { if r.debug { fmt.Printf("rpc_le_get_conn_id()\r\n") } @@ -1463,7 +1473,8 @@ func (r *RTL8720DN) Rpc_le_get_conn_id(bd_addr uint8, bd_type uint8, p_conn_id u <-r.received widx := 8 // p_conn_id : out uint8 - // not impl + *p_conn_id = payload[widx] + widx += 1 var result bool result = binary.LittleEndian.Uint32(payload[widx:]) == 1 @@ -1779,7 +1790,7 @@ func (r *RTL8720DN) Rpc_flash_load_local_name(p_data RPC_T_LOCAL_NAME) (uint32, <-r.received widx := 8 // p_data : out RPC_T_LOCAL_NAME - // not impl + // not impl (a.Size() > 0) var result uint32 result = uint32(binary.LittleEndian.Uint32(payload[widx:])) @@ -1829,7 +1840,7 @@ func (r *RTL8720DN) Rpc_flash_load_local_appearance(p_data RPC_T_LOCAL_APPEARANC <-r.received widx := 8 // p_data : out RPC_T_LOCAL_APPEARANCE - // not impl + // not impl (a.Size() > 0) var result uint32 result = uint32(binary.LittleEndian.Uint32(payload[widx:])) @@ -1980,7 +1991,7 @@ func (r *RTL8720DN) Rpc_le_set_high_priority_bond(bd_addr uint8, bd_type RPC_T_G return result, err } -func (r *RTL8720DN) Rpc_le_resolve_random_address(unresolved_addr uint8, resolved_addr uint8, resolved_addr_type RPC_T_GAP_IDENT_ADDR_TYPE) (bool, error) { +func (r *RTL8720DN) Rpc_le_resolve_random_address(unresolved_addr uint8, resolved_addr *uint8, resolved_addr_type RPC_T_GAP_IDENT_ADDR_TYPE) (bool, error) { if r.debug { fmt.Printf("rpc_le_resolve_random_address()\r\n") } @@ -1989,7 +2000,7 @@ func (r *RTL8720DN) Rpc_le_resolve_random_address(unresolved_addr uint8, resolve // unresolved_addr : in uint8 msg = append(msg, byte(unresolved_addr>>0)) // resolved_addr : inout uint8 - msg = append(msg, byte(resolved_addr>>0)) + msg = append(msg, byte(*resolved_addr>>0)) // resolved_addr_type : inout RPC_T_GAP_IDENT_ADDR_TYPE msg = append(msg, byte(resolved_addr_type>>0)) msg = append(msg, byte(resolved_addr_type>>8)) @@ -2004,9 +2015,10 @@ func (r *RTL8720DN) Rpc_le_resolve_random_address(unresolved_addr uint8, resolve <-r.received widx := 8 // resolved_addr : inout uint8 - // not impl + *resolved_addr = payload[widx] + widx += 1 // resolved_addr_type : inout RPC_T_GAP_IDENT_ADDR_TYPE - // not impl + // not impl (a.Size() > 0) var result bool result = binary.LittleEndian.Uint32(payload[widx:]) == 1 @@ -2035,7 +2047,7 @@ func (r *RTL8720DN) Rpc_le_get_cccd_data(p_entry RPC_T_LE_KEY_ENTRY, p_data RPC_ <-r.received widx := 8 // p_data : out RPC_T_LE_CCCD - // not impl + // not impl (a.Size() > 0) var result bool result = binary.LittleEndian.Uint32(payload[widx:]) == 1 @@ -2111,7 +2123,7 @@ func (r *RTL8720DN) Rpc_le_get_dev_bond_info_len() (uint16, error) { return result, err } -func (r *RTL8720DN) Rpc_le_set_dev_bond_info(p_data []byte, exist bool) (RPC_T_LE_KEY_ENTRY, error) { +func (r *RTL8720DN) Rpc_le_set_dev_bond_info(p_data []byte, exist *bool) (RPC_T_LE_KEY_ENTRY, error) { if r.debug { fmt.Printf("rpc_le_set_dev_bond_info()\r\n") } @@ -2129,7 +2141,8 @@ func (r *RTL8720DN) Rpc_le_set_dev_bond_info(p_data []byte, exist bool) (RPC_T_L <-r.received widx := 8 // exist : out bool - // not impl + *exist = payload[widx] != 0 + widx += 1 var result RPC_T_LE_KEY_ENTRY result = RPC_T_LE_KEY_ENTRY(binary.LittleEndian.Uint32(payload[widx:])) @@ -2138,7 +2151,7 @@ func (r *RTL8720DN) Rpc_le_set_dev_bond_info(p_data []byte, exist bool) (RPC_T_L return result, err } -func (r *RTL8720DN) Rpc_le_get_dev_bond_info(p_entry RPC_T_LE_KEY_ENTRY, p_data []byte) (bool, error) { +func (r *RTL8720DN) Rpc_le_get_dev_bond_info(p_entry RPC_T_LE_KEY_ENTRY, p_data *[]byte) (bool, error) { if r.debug { fmt.Printf("rpc_le_get_dev_bond_info()\r\n") } @@ -2161,9 +2174,10 @@ func (r *RTL8720DN) Rpc_le_get_dev_bond_info(p_entry RPC_T_LE_KEY_ENTRY, p_data p_data_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if p_data_length > 0 { - copy(p_data, payload[widx:widx+int(p_data_length)]) + copy(*p_data, payload[widx:widx+int(p_data_length)]) widx += int(p_data_length) } + *p_data = (*p_data)[:p_data_length] var result bool result = binary.LittleEndian.Uint32(payload[widx:]) == 1 @@ -3080,7 +3094,7 @@ func (r *RTL8720DN) Rpc_ble_gattc_callback(gatt_if uint8, conn_id uint8, cb_data return result, err } -func (r *RTL8720DN) Rpc_ble_gatts_callback(gatt_if uint8, conn_id uint8, attrib_index uint16, event RPC_T_SERVICE_CALLBACK_TYPE, property uint16, read_cb_data []byte, write_cb_data []byte, app_cb_data []byte) (RPC_T_APP_RESULT, error) { +func (r *RTL8720DN) Rpc_ble_gatts_callback(gatt_if uint8, conn_id uint8, attrib_index uint16, event RPC_T_SERVICE_CALLBACK_TYPE, property uint16, read_cb_data *[]byte, write_cb_data []byte, app_cb_data []byte) (RPC_T_APP_RESULT, error) { if r.debug { fmt.Printf("rpc_ble_gatts_callback()\r\n") } @@ -3133,9 +3147,10 @@ func (r *RTL8720DN) Rpc_ble_gatts_callback(gatt_if uint8, conn_id uint8, attrib_ widx += 4 } if read_cb_data_length > 0 { - copy(read_cb_data, payload[widx:widx+int(read_cb_data_length)]) + copy(*read_cb_data, payload[widx:widx+int(read_cb_data_length)]) widx += int(read_cb_data_length) } + *read_cb_data = (*read_cb_data)[:read_cb_data_length] var result RPC_T_APP_RESULT result = RPC_T_APP_RESULT(binary.LittleEndian.Uint32(payload[widx:])) @@ -3404,7 +3419,7 @@ func (r *RTL8720DN) Rpc_wifi_set_mac_address(mac []byte) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_wifi_get_mac_address(mac uint8) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_mac_address(mac *uint8) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_mac_address()\r\n") } @@ -3418,7 +3433,8 @@ func (r *RTL8720DN) Rpc_wifi_get_mac_address(mac uint8) (int32, error) { <-r.received widx := 8 // mac : out uint8 - // not impl + *mac = payload[widx] + widx += 1 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -3545,7 +3561,7 @@ func (r *RTL8720DN) Rpc_wifi_btcoex_set_bt_off() error { return err } -func (r *RTL8720DN) Rpc_wifi_get_associated_client_list(client_list_buffer []byte, buffer_length uint16) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_associated_client_list(client_list_buffer *[]byte, buffer_length uint16) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_associated_client_list()\r\n") } @@ -3566,9 +3582,10 @@ func (r *RTL8720DN) Rpc_wifi_get_associated_client_list(client_list_buffer []byt client_list_buffer_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if client_list_buffer_length > 0 { - copy(client_list_buffer, payload[widx:widx+int(client_list_buffer_length)]) + copy(*client_list_buffer, payload[widx:widx+int(client_list_buffer_length)]) widx += int(client_list_buffer_length) } + *client_list_buffer = (*client_list_buffer)[:client_list_buffer_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -3583,7 +3600,7 @@ func (r *RTL8720DN) Rpc_wifi_get_associated_client_list(client_list_buffer []byt return result, err } -func (r *RTL8720DN) Rpc_wifi_get_ap_bssid(bssid uint8) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_ap_bssid(bssid *uint8) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_ap_bssid()\r\n") } @@ -3597,7 +3614,8 @@ func (r *RTL8720DN) Rpc_wifi_get_ap_bssid(bssid uint8) (int32, error) { <-r.received widx := 8 // bssid : out uint8 - // not impl + *bssid = payload[widx] + widx += 1 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -3612,7 +3630,7 @@ func (r *RTL8720DN) Rpc_wifi_get_ap_bssid(bssid uint8) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_wifi_get_ap_info(ap_info []byte, security uint32) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_ap_info(ap_info *[]byte, security *uint32) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_ap_info()\r\n") } @@ -3629,11 +3647,13 @@ func (r *RTL8720DN) Rpc_wifi_get_ap_info(ap_info []byte, security uint32) (int32 ap_info_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if ap_info_length > 0 { - copy(ap_info, payload[widx:widx+int(ap_info_length)]) + copy(*ap_info, payload[widx:widx+int(ap_info_length)]) widx += int(ap_info_length) } + *ap_info = (*ap_info)[:ap_info_length] // security : out uint32 - // not impl + *security = binary.LittleEndian.Uint32(payload[widx:]) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -3681,7 +3701,7 @@ func (r *RTL8720DN) Rpc_wifi_set_country(country_code uint32) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_wifi_get_sta_max_data_rate(inidata_rate uint8) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_sta_max_data_rate(inidata_rate *uint8) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_sta_max_data_rate()\r\n") } @@ -3695,7 +3715,8 @@ func (r *RTL8720DN) Rpc_wifi_get_sta_max_data_rate(inidata_rate uint8) (int32, e <-r.received widx := 8 // inidata_rate : out uint8 - // not impl + *inidata_rate = payload[widx] + widx += 1 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -3710,7 +3731,7 @@ func (r *RTL8720DN) Rpc_wifi_get_sta_max_data_rate(inidata_rate uint8) (int32, e return result, err } -func (r *RTL8720DN) Rpc_wifi_get_rssi(pRSSI int32) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_rssi(pRSSI *int32) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_rssi()\r\n") } @@ -3724,7 +3745,8 @@ func (r *RTL8720DN) Rpc_wifi_get_rssi(pRSSI int32) (int32, error) { <-r.received widx := 8 // pRSSI : out int32 - // not impl + *pRSSI = int32(binary.LittleEndian.Uint32(payload[widx:])) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -3772,7 +3794,7 @@ func (r *RTL8720DN) Rpc_wifi_set_channel(channel int32) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_wifi_get_channel(channel int32) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_channel(channel *int32) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_channel()\r\n") } @@ -3786,7 +3808,8 @@ func (r *RTL8720DN) Rpc_wifi_get_channel(channel int32) (int32, error) { <-r.received widx := 8 // channel : out int32 - // not impl + *channel = int32(binary.LittleEndian.Uint32(payload[widx:])) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -4159,7 +4182,7 @@ func (r *RTL8720DN) Rpc_wifi_set_lps_dtim(dtim uint8) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_wifi_get_lps_dtim(dtim uint8) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_lps_dtim(dtim *uint8) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_lps_dtim()\r\n") } @@ -4173,7 +4196,8 @@ func (r *RTL8720DN) Rpc_wifi_get_lps_dtim(dtim uint8) (int32, error) { <-r.received widx := 8 // dtim : out uint8 - // not impl + *dtim = payload[widx] + widx += 1 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -4409,7 +4433,7 @@ func (r *RTL8720DN) Rpc_wifi_set_pscan_chan(channel_list []byte, pscan_config ui return result, err } -func (r *RTL8720DN) Rpc_wifi_get_setting(ifname string, pSetting []byte) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_setting(ifname string, pSetting *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_setting()\r\n") } @@ -4430,9 +4454,10 @@ func (r *RTL8720DN) Rpc_wifi_get_setting(ifname string, pSetting []byte) (int32, pSetting_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pSetting_length > 0 { - copy(pSetting, payload[widx:widx+int(pSetting_length)]) + copy(*pSetting, payload[widx:widx+int(pSetting_length)]) widx += int(pSetting_length) } + *pSetting = (*pSetting)[:pSetting_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -4480,7 +4505,7 @@ func (r *RTL8720DN) Rpc_wifi_set_network_mode(mode uint32) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_wifi_get_network_mode(pmode uint32) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_network_mode(pmode *uint32) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_network_mode()\r\n") } @@ -4494,7 +4519,8 @@ func (r *RTL8720DN) Rpc_wifi_get_network_mode(pmode uint32) (int32, error) { <-r.received widx := 8 // pmode : out uint32 - // not impl + *pmode = binary.LittleEndian.Uint32(payload[widx:]) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -4648,7 +4674,7 @@ func (r *RTL8720DN) Rpc_wifi_set_autoreconnect(mode uint8) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_wifi_get_autoreconnect(mode uint8) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_autoreconnect(mode *uint8) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_autoreconnect()\r\n") } @@ -4662,7 +4688,8 @@ func (r *RTL8720DN) Rpc_wifi_get_autoreconnect(mode uint8) (int32, error) { <-r.received widx := 8 // mode : out uint8 - // not impl + *mode = payload[widx] + widx += 1 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -4819,7 +4846,7 @@ func (r *RTL8720DN) Rpc_wifi_set_indicate_mgnt(enable int32) error { return err } -func (r *RTL8720DN) Rpc_wifi_get_drv_ability(ability uint32) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_drv_ability(ability *uint32) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_drv_ability()\r\n") } @@ -4833,7 +4860,8 @@ func (r *RTL8720DN) Rpc_wifi_get_drv_ability(ability uint32) (int32, error) { <-r.received widx := 8 // ability : out uint32 - // not impl + *ability = binary.LittleEndian.Uint32(payload[widx:]) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -4878,7 +4906,7 @@ func (r *RTL8720DN) Rpc_wifi_set_channel_plan(channel_plan uint8) (int32, error) return result, err } -func (r *RTL8720DN) Rpc_wifi_get_channel_plan(channel_plan uint8) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_channel_plan(channel_plan *uint8) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_channel_plan()\r\n") } @@ -4892,7 +4920,8 @@ func (r *RTL8720DN) Rpc_wifi_get_channel_plan(channel_plan uint8) (int32, error) <-r.received widx := 8 // channel_plan : out uint8 - // not impl + *channel_plan = payload[widx] + widx += 1 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -5042,7 +5071,7 @@ func (r *RTL8720DN) Rpc_wifi_set_tx_pause_data(NewState uint32) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_wifi_get_reconnect_data(wifi_info []byte) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_reconnect_data(wifi_info *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_reconnect_data()\r\n") } @@ -5059,9 +5088,10 @@ func (r *RTL8720DN) Rpc_wifi_get_reconnect_data(wifi_info []byte) (int32, error) wifi_info_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if wifi_info_length > 0 { - copy(wifi_info, payload[widx:widx+int(wifi_info_length)]) + copy(*wifi_info, payload[widx:widx+int(wifi_info_length)]) widx += int(wifi_info_length) } + *wifi_info = (*wifi_info)[:wifi_info_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -5148,7 +5178,7 @@ func (r *RTL8720DN) Rpc_wifi_is_scaning() (bool, error) { return result, err } -func (r *RTL8720DN) Rpc_wifi_scan_get_ap_records(number uint16, _scanResult []byte) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_scan_get_ap_records(number uint16, _scanResult *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_scan_get_ap_records()\r\n") } @@ -5169,9 +5199,10 @@ func (r *RTL8720DN) Rpc_wifi_scan_get_ap_records(number uint16, _scanResult []by _scanResult_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if _scanResult_length > 0 { - copy(_scanResult, payload[widx:widx+int(_scanResult_length)]) + copy(*_scanResult, payload[widx:widx+int(_scanResult_length)]) widx += int(_scanResult_length) } + *_scanResult = (*_scanResult)[:_scanResult_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -5399,7 +5430,7 @@ func (r *RTL8720DN) Rpc_tcpip_adapter_down(tcpip_if uint32) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_tcpip_adapter_get_ip_info(tcpip_if uint32, ip_info []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcpip_adapter_get_ip_info(tcpip_if uint32, ip_info *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcpip_adapter_get_ip_info()\r\n") } @@ -5422,9 +5453,10 @@ func (r *RTL8720DN) Rpc_tcpip_adapter_get_ip_info(tcpip_if uint32, ip_info []byt ip_info_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if ip_info_length > 0 { - copy(ip_info, payload[widx:widx+int(ip_info_length)]) + copy(*ip_info, payload[widx:widx+int(ip_info_length)]) widx += int(ip_info_length) } + *ip_info = (*ip_info)[:ip_info_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -5516,7 +5548,7 @@ func (r *RTL8720DN) Rpc_tcpip_adapter_set_dns_info(tcpip_if uint32, dns_type uin return result, err } -func (r *RTL8720DN) Rpc_tcpip_adapter_get_dns_info(tcpip_if uint32, dns_type uint32, dns []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcpip_adapter_get_dns_info(tcpip_if uint32, dns_type uint32, dns *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcpip_adapter_get_dns_info()\r\n") } @@ -5544,9 +5576,10 @@ func (r *RTL8720DN) Rpc_tcpip_adapter_get_dns_info(tcpip_if uint32, dns_type uin dns_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if dns_length > 0 { - copy(dns, payload[widx:widx+int(dns_length)]) + copy(*dns, payload[widx:widx+int(dns_length)]) widx += int(dns_length) } + *dns = (*dns)[:dns_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -5755,6 +5788,7 @@ func (r *RTL8720DN) Rpc_tcpip_adapter_get_hostname(tcpip_if uint32, hostname str hostname = string(payload[widx : widx+int(hostname_length)]) widx += int(hostname_length) } + hostname = (hostname)[:hostname_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -5769,7 +5803,7 @@ func (r *RTL8720DN) Rpc_tcpip_adapter_get_hostname(tcpip_if uint32, hostname str return result, err } -func (r *RTL8720DN) Rpc_tcpip_adapter_get_mac(tcpip_if uint32, mac []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcpip_adapter_get_mac(tcpip_if uint32, mac *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcpip_adapter_get_mac()\r\n") } @@ -5792,9 +5826,10 @@ func (r *RTL8720DN) Rpc_tcpip_adapter_get_mac(tcpip_if uint32, mac []byte) (int3 mac_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if mac_length > 0 { - copy(mac, payload[widx:widx+int(mac_length)]) + copy(*mac, payload[widx:widx+int(mac_length)]) widx += int(mac_length) } + *mac = (*mac)[:mac_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -5879,7 +5914,7 @@ func (r *RTL8720DN) Rpc_tcpip_api_call(fn []byte, call []byte) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_tcp_connect(pcb_in []byte, pcb_out []byte, ipaddr []byte, port uint16, connected []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_connect(pcb_in []byte, pcb_out *[]byte, ipaddr []byte, port uint16, connected []byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_connect()\r\n") } @@ -5909,9 +5944,10 @@ func (r *RTL8720DN) Rpc_tcp_connect(pcb_in []byte, pcb_out []byte, ipaddr []byte pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -5926,7 +5962,7 @@ func (r *RTL8720DN) Rpc_tcp_connect(pcb_in []byte, pcb_out []byte, ipaddr []byte return result, err } -func (r *RTL8720DN) Rpc_tcp_recved(pcb_in []byte, pcb_out []byte, length uint16) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_recved(pcb_in []byte, pcb_out *[]byte, length uint16) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_recved()\r\n") } @@ -5950,9 +5986,10 @@ func (r *RTL8720DN) Rpc_tcp_recved(pcb_in []byte, pcb_out []byte, length uint16) pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -5967,7 +6004,7 @@ func (r *RTL8720DN) Rpc_tcp_recved(pcb_in []byte, pcb_out []byte, length uint16) return result, err } -func (r *RTL8720DN) Rpc_tcp_abort(pcb_in []byte, pcb_out []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_abort(pcb_in []byte, pcb_out *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_abort()\r\n") } @@ -5988,9 +6025,10 @@ func (r *RTL8720DN) Rpc_tcp_abort(pcb_in []byte, pcb_out []byte) (int32, error) pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6005,7 +6043,7 @@ func (r *RTL8720DN) Rpc_tcp_abort(pcb_in []byte, pcb_out []byte) (int32, error) return result, err } -func (r *RTL8720DN) Rpc_tcp_write(pcb_in []byte, pcb_out []byte, data []byte, apiflags uint8) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_write(pcb_in []byte, pcb_out *[]byte, data []byte, apiflags uint8) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_write()\r\n") } @@ -6031,9 +6069,10 @@ func (r *RTL8720DN) Rpc_tcp_write(pcb_in []byte, pcb_out []byte, data []byte, ap pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6048,7 +6087,7 @@ func (r *RTL8720DN) Rpc_tcp_write(pcb_in []byte, pcb_out []byte, data []byte, ap return result, err } -func (r *RTL8720DN) Rpc_tcp_output(pcb_in []byte, pcb_out []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_output(pcb_in []byte, pcb_out *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_output()\r\n") } @@ -6069,9 +6108,10 @@ func (r *RTL8720DN) Rpc_tcp_output(pcb_in []byte, pcb_out []byte) (int32, error) pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6086,7 +6126,7 @@ func (r *RTL8720DN) Rpc_tcp_output(pcb_in []byte, pcb_out []byte) (int32, error) return result, err } -func (r *RTL8720DN) Rpc_tcp_close(pcb_in []byte, pcb_out []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_close(pcb_in []byte, pcb_out *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_close()\r\n") } @@ -6107,9 +6147,10 @@ func (r *RTL8720DN) Rpc_tcp_close(pcb_in []byte, pcb_out []byte) (int32, error) pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6124,7 +6165,7 @@ func (r *RTL8720DN) Rpc_tcp_close(pcb_in []byte, pcb_out []byte) (int32, error) return result, err } -func (r *RTL8720DN) Rpc_tcp_bind(pcb_in []byte, pcb_out []byte, ipaddr []byte, port uint16) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_bind(pcb_in []byte, pcb_out *[]byte, ipaddr []byte, port uint16) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_bind()\r\n") } @@ -6151,9 +6192,10 @@ func (r *RTL8720DN) Rpc_tcp_bind(pcb_in []byte, pcb_out []byte, ipaddr []byte, p pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6168,7 +6210,7 @@ func (r *RTL8720DN) Rpc_tcp_bind(pcb_in []byte, pcb_out []byte, ipaddr []byte, p return result, err } -func (r *RTL8720DN) Rpc_tcp_new_ip_type(ip_type uint8, pcb_out []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_new_ip_type(ip_type uint8, pcb_out *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_new_ip_type()\r\n") } @@ -6188,9 +6230,10 @@ func (r *RTL8720DN) Rpc_tcp_new_ip_type(ip_type uint8, pcb_out []byte) (int32, e pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6205,7 +6248,7 @@ func (r *RTL8720DN) Rpc_tcp_new_ip_type(ip_type uint8, pcb_out []byte) (int32, e return result, err } -func (r *RTL8720DN) Rpc_tcp_arg(pcb_in []byte, pcb_out []byte, func_arg []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_arg(pcb_in []byte, pcb_out *[]byte, func_arg []byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_arg()\r\n") } @@ -6229,9 +6272,10 @@ func (r *RTL8720DN) Rpc_tcp_arg(pcb_in []byte, pcb_out []byte, func_arg []byte) pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6246,7 +6290,7 @@ func (r *RTL8720DN) Rpc_tcp_arg(pcb_in []byte, pcb_out []byte, func_arg []byte) return result, err } -func (r *RTL8720DN) Rpc_tcp_err(pcb_in []byte, pcb_out []byte, func_err []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_err(pcb_in []byte, pcb_out *[]byte, func_err []byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_err()\r\n") } @@ -6270,9 +6314,10 @@ func (r *RTL8720DN) Rpc_tcp_err(pcb_in []byte, pcb_out []byte, func_err []byte) pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6287,7 +6332,7 @@ func (r *RTL8720DN) Rpc_tcp_err(pcb_in []byte, pcb_out []byte, func_err []byte) return result, err } -func (r *RTL8720DN) Rpc_tcp_recv(pcb_in []byte, pcb_out []byte, func_recv []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_recv(pcb_in []byte, pcb_out *[]byte, func_recv []byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_recv()\r\n") } @@ -6311,9 +6356,10 @@ func (r *RTL8720DN) Rpc_tcp_recv(pcb_in []byte, pcb_out []byte, func_recv []byte pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6328,7 +6374,7 @@ func (r *RTL8720DN) Rpc_tcp_recv(pcb_in []byte, pcb_out []byte, func_recv []byte return result, err } -func (r *RTL8720DN) Rpc_tcp_sent(pcb_in []byte, pcb_out []byte, func_sent []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_sent(pcb_in []byte, pcb_out *[]byte, func_sent []byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_sent()\r\n") } @@ -6352,9 +6398,10 @@ func (r *RTL8720DN) Rpc_tcp_sent(pcb_in []byte, pcb_out []byte, func_sent []byte pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6369,7 +6416,7 @@ func (r *RTL8720DN) Rpc_tcp_sent(pcb_in []byte, pcb_out []byte, func_sent []byte return result, err } -func (r *RTL8720DN) Rpc_tcp_accept(pcb_in []byte, pcb_out []byte, func_accept []byte) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_accept(pcb_in []byte, pcb_out *[]byte, func_accept []byte) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_accept()\r\n") } @@ -6393,9 +6440,10 @@ func (r *RTL8720DN) Rpc_tcp_accept(pcb_in []byte, pcb_out []byte, func_accept [] pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6410,7 +6458,7 @@ func (r *RTL8720DN) Rpc_tcp_accept(pcb_in []byte, pcb_out []byte, func_accept [] return result, err } -func (r *RTL8720DN) Rpc_tcp_poll(pcb_in []byte, pcb_out []byte, func_poll []byte, interval uint8) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_poll(pcb_in []byte, pcb_out *[]byte, func_poll []byte, interval uint8) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_poll()\r\n") } @@ -6436,9 +6484,10 @@ func (r *RTL8720DN) Rpc_tcp_poll(pcb_in []byte, pcb_out []byte, func_poll []byte pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6453,7 +6502,7 @@ func (r *RTL8720DN) Rpc_tcp_poll(pcb_in []byte, pcb_out []byte, func_poll []byte return result, err } -func (r *RTL8720DN) Rpc_tcp_listen_with_backlog(pcb_in []byte, pcb_out []byte, backlog uint8) (int32, error) { +func (r *RTL8720DN) Rpc_tcp_listen_with_backlog(pcb_in []byte, pcb_out *[]byte, backlog uint8) (int32, error) { if r.debug { fmt.Printf("rpc_tcp_listen_with_backlog()\r\n") } @@ -6476,9 +6525,10 @@ func (r *RTL8720DN) Rpc_tcp_listen_with_backlog(pcb_in []byte, pcb_out []byte, b pcb_out_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if pcb_out_length > 0 { - copy(pcb_out, payload[widx:widx+int(pcb_out_length)]) + copy(*pcb_out, payload[widx:widx+int(pcb_out_length)]) widx += int(pcb_out_length) } + *pcb_out = (*pcb_out)[:pcb_out_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6576,7 +6626,7 @@ func (r *RTL8720DN) Rpc_inet_chksum(dataptr_in []byte) (uint16, error) { return result, err } -func (r *RTL8720DN) Rpc_lwip_accept(s int32, addr []byte, addrlen uint32) (int32, error) { +func (r *RTL8720DN) Rpc_lwip_accept(s int32, addr []byte, addrlen *uint32) (int32, error) { if r.debug { fmt.Printf("rpc_lwip_accept()\r\n") } @@ -6591,10 +6641,10 @@ func (r *RTL8720DN) Rpc_lwip_accept(s int32, addr []byte, addrlen uint32) (int32 msg = append(msg, byte(len(addr)), byte(len(addr)>>8), byte(len(addr)>>16), byte(len(addr)>>24)) msg = append(msg, []byte(addr)...) // addrlen : inout uint32 - msg = append(msg, byte(addrlen>>0)) - msg = append(msg, byte(addrlen>>8)) - msg = append(msg, byte(addrlen>>16)) - msg = append(msg, byte(addrlen>>24)) + msg = append(msg, byte(*addrlen>>0)) + msg = append(msg, byte(*addrlen>>8)) + msg = append(msg, byte(*addrlen>>16)) + msg = append(msg, byte(*addrlen>>24)) err := r.performRequest(msg) if err != nil { @@ -6604,7 +6654,8 @@ func (r *RTL8720DN) Rpc_lwip_accept(s int32, addr []byte, addrlen uint32) (int32 <-r.received widx := 8 // addrlen : inout uint32 - // not impl + *addrlen = binary.LittleEndian.Uint32(payload[widx:]) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6698,7 +6749,7 @@ func (r *RTL8720DN) Rpc_lwip_shutdown(s int32, how int32) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_lwip_getpeername(s int32, name []byte, namelen uint32) (int32, error) { +func (r *RTL8720DN) Rpc_lwip_getpeername(s int32, name *[]byte, namelen *uint32) (int32, error) { if r.debug { fmt.Printf("rpc_lwip_getpeername()\r\n") } @@ -6710,10 +6761,10 @@ func (r *RTL8720DN) Rpc_lwip_getpeername(s int32, name []byte, namelen uint32) ( msg = append(msg, byte(s>>16)) msg = append(msg, byte(s>>24)) // namelen : inout uint32 - msg = append(msg, byte(namelen>>0)) - msg = append(msg, byte(namelen>>8)) - msg = append(msg, byte(namelen>>16)) - msg = append(msg, byte(namelen>>24)) + msg = append(msg, byte(*namelen>>0)) + msg = append(msg, byte(*namelen>>8)) + msg = append(msg, byte(*namelen>>16)) + msg = append(msg, byte(*namelen>>24)) err := r.performRequest(msg) if err != nil { @@ -6726,11 +6777,13 @@ func (r *RTL8720DN) Rpc_lwip_getpeername(s int32, name []byte, namelen uint32) ( name_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if name_length > 0 { - copy(name, payload[widx:widx+int(name_length)]) + copy(*name, payload[widx:widx+int(name_length)]) widx += int(name_length) } + *name = (*name)[:name_length] // namelen : inout uint32 - // not impl + *namelen = binary.LittleEndian.Uint32(payload[widx:]) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6745,7 +6798,7 @@ func (r *RTL8720DN) Rpc_lwip_getpeername(s int32, name []byte, namelen uint32) ( return result, err } -func (r *RTL8720DN) Rpc_lwip_getsockname(s int32, name []byte, namelen uint32) (int32, error) { +func (r *RTL8720DN) Rpc_lwip_getsockname(s int32, name *[]byte, namelen *uint32) (int32, error) { if r.debug { fmt.Printf("rpc_lwip_getsockname()\r\n") } @@ -6757,10 +6810,10 @@ func (r *RTL8720DN) Rpc_lwip_getsockname(s int32, name []byte, namelen uint32) ( msg = append(msg, byte(s>>16)) msg = append(msg, byte(s>>24)) // namelen : inout uint32 - msg = append(msg, byte(namelen>>0)) - msg = append(msg, byte(namelen>>8)) - msg = append(msg, byte(namelen>>16)) - msg = append(msg, byte(namelen>>24)) + msg = append(msg, byte(*namelen>>0)) + msg = append(msg, byte(*namelen>>8)) + msg = append(msg, byte(*namelen>>16)) + msg = append(msg, byte(*namelen>>24)) err := r.performRequest(msg) if err != nil { @@ -6773,11 +6826,13 @@ func (r *RTL8720DN) Rpc_lwip_getsockname(s int32, name []byte, namelen uint32) ( name_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if name_length > 0 { - copy(name, payload[widx:widx+int(name_length)]) + copy(*name, payload[widx:widx+int(name_length)]) widx += int(name_length) } + *name = (*name)[:name_length] // namelen : inout uint32 - // not impl + *namelen = binary.LittleEndian.Uint32(payload[widx:]) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -6792,7 +6847,7 @@ func (r *RTL8720DN) Rpc_lwip_getsockname(s int32, name []byte, namelen uint32) ( return result, err } -func (r *RTL8720DN) Rpc_lwip_getsockopt(s int32, level int32, optname int32, in_optval []byte, out_optval []byte, optlen uint32) (int32, error) { +func (r *RTL8720DN) Rpc_lwip_getsockopt(s int32, level int32, optname int32, in_optval []byte, out_optval *[]byte, optlen *uint32) (int32, error) { if r.debug { fmt.Printf("rpc_lwip_getsockopt()\r\n") } @@ -6817,10 +6872,10 @@ func (r *RTL8720DN) Rpc_lwip_getsockopt(s int32, level int32, optname int32, in_ msg = append(msg, byte(len(in_optval)), byte(len(in_optval)>>8), byte(len(in_optval)>>16), byte(len(in_optval)>>24)) msg = append(msg, []byte(in_optval)...) // optlen : inout uint32 - msg = append(msg, byte(optlen>>0)) - msg = append(msg, byte(optlen>>8)) - msg = append(msg, byte(optlen>>16)) - msg = append(msg, byte(optlen>>24)) + msg = append(msg, byte(*optlen>>0)) + msg = append(msg, byte(*optlen>>8)) + msg = append(msg, byte(*optlen>>16)) + msg = append(msg, byte(*optlen>>24)) err := r.performRequest(msg) if err != nil { @@ -6833,11 +6888,13 @@ func (r *RTL8720DN) Rpc_lwip_getsockopt(s int32, level int32, optname int32, in_ out_optval_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if out_optval_length > 0 { - copy(out_optval, payload[widx:widx+int(out_optval_length)]) + copy(*out_optval, payload[widx:widx+int(out_optval_length)]) widx += int(out_optval_length) } + *out_optval = (*out_optval)[:out_optval_length] // optlen : inout uint32 - // not impl + *optlen = binary.LittleEndian.Uint32(payload[widx:]) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -7048,7 +7105,7 @@ func (r *RTL8720DN) Rpc_lwip_available(s int32) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_lwip_recv(s int32, mem []byte, length uint32, flags int32, timeout uint32) (int32, error) { +func (r *RTL8720DN) Rpc_lwip_recv(s int32, mem *[]byte, length uint32, flags int32, timeout uint32) (int32, error) { if r.debug { fmt.Printf("rpc_lwip_recv()\r\n") } @@ -7086,9 +7143,10 @@ func (r *RTL8720DN) Rpc_lwip_recv(s int32, mem []byte, length uint32, flags int3 mem_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if mem_length > 0 { - copy(mem, payload[widx:widx+int(mem_length)]) + copy(*mem, payload[widx:widx+int(mem_length)]) widx += int(mem_length) } + *mem = (*mem)[:mem_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -7103,7 +7161,7 @@ func (r *RTL8720DN) Rpc_lwip_recv(s int32, mem []byte, length uint32, flags int3 return result, err } -func (r *RTL8720DN) Rpc_lwip_read(s int32, mem []byte, length uint32, timeout uint32) (int32, error) { +func (r *RTL8720DN) Rpc_lwip_read(s int32, mem *[]byte, length uint32, timeout uint32) (int32, error) { if r.debug { fmt.Printf("rpc_lwip_read()\r\n") } @@ -7136,9 +7194,10 @@ func (r *RTL8720DN) Rpc_lwip_read(s int32, mem []byte, length uint32, timeout ui mem_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if mem_length > 0 { - copy(mem, payload[widx:widx+int(mem_length)]) + copy(*mem, payload[widx:widx+int(mem_length)]) widx += int(mem_length) } + *mem = (*mem)[:mem_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -7153,7 +7212,7 @@ func (r *RTL8720DN) Rpc_lwip_read(s int32, mem []byte, length uint32, timeout ui return result, err } -func (r *RTL8720DN) Rpc_lwip_recvfrom(s int32, mem []byte, length uint32, flags int32, from []byte, fromlen uint32, timeout uint32) (int32, error) { +func (r *RTL8720DN) Rpc_lwip_recvfrom(s int32, mem *[]byte, length uint32, flags int32, from *[]byte, fromlen *uint32, timeout uint32) (int32, error) { if r.debug { fmt.Printf("rpc_lwip_recvfrom()\r\n") } @@ -7175,10 +7234,10 @@ func (r *RTL8720DN) Rpc_lwip_recvfrom(s int32, mem []byte, length uint32, flags msg = append(msg, byte(flags>>16)) msg = append(msg, byte(flags>>24)) // fromlen : inout uint32 - msg = append(msg, byte(fromlen>>0)) - msg = append(msg, byte(fromlen>>8)) - msg = append(msg, byte(fromlen>>16)) - msg = append(msg, byte(fromlen>>24)) + msg = append(msg, byte(*fromlen>>0)) + msg = append(msg, byte(*fromlen>>8)) + msg = append(msg, byte(*fromlen>>16)) + msg = append(msg, byte(*fromlen>>24)) // timeout : in uint32 msg = append(msg, byte(timeout>>0)) msg = append(msg, byte(timeout>>8)) @@ -7196,18 +7255,21 @@ func (r *RTL8720DN) Rpc_lwip_recvfrom(s int32, mem []byte, length uint32, flags mem_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if mem_length > 0 { - copy(mem, payload[widx:widx+int(mem_length)]) + copy(*mem, payload[widx:widx+int(mem_length)]) widx += int(mem_length) } + *mem = (*mem)[:mem_length] // from : out []byte from_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if from_length > 0 { - copy(from, payload[widx:widx+int(from_length)]) + copy(*from, payload[widx:widx+int(from_length)]) widx += int(from_length) } + *from = (*from)[:from_length] // fromlen : inout uint32 - // not impl + *fromlen = binary.LittleEndian.Uint32(payload[widx:]) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -7554,7 +7616,7 @@ func (r *RTL8720DN) Rpc_lwip_select(maxfdp1 int32, readset []byte, writeset []by return result, err } -func (r *RTL8720DN) Rpc_lwip_ioctl(s int32, cmd uint32, in_argp []byte, out_argp []byte) (int32, error) { +func (r *RTL8720DN) Rpc_lwip_ioctl(s int32, cmd uint32, in_argp []byte, out_argp *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_lwip_ioctl()\r\n") } @@ -7585,9 +7647,10 @@ func (r *RTL8720DN) Rpc_lwip_ioctl(s int32, cmd uint32, in_argp []byte, out_argp out_argp_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if out_argp_length > 0 { - copy(out_argp, payload[widx:widx+int(out_argp_length)]) + copy(*out_argp, payload[widx:widx+int(out_argp_length)]) widx += int(out_argp_length) } + *out_argp = (*out_argp)[:out_argp_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -7671,7 +7734,7 @@ func (r *RTL8720DN) Rpc_lwip_errno() (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_netconn_gethostbyname(name string, addr []byte) (int8, error) { +func (r *RTL8720DN) Rpc_netconn_gethostbyname(name string, addr *[]byte) (int8, error) { if r.debug { fmt.Printf("rpc_netconn_gethostbyname()\r\n") } @@ -7692,9 +7755,10 @@ func (r *RTL8720DN) Rpc_netconn_gethostbyname(name string, addr []byte) (int8, e addr_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if addr_length > 0 { - copy(addr, payload[widx:widx+int(addr_length)]) + copy(*addr, payload[widx:widx+int(addr_length)]) widx += int(addr_length) } + *addr = (*addr)[:addr_length] var result int8 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -7709,7 +7773,7 @@ func (r *RTL8720DN) Rpc_netconn_gethostbyname(name string, addr []byte) (int8, e return result, err } -func (r *RTL8720DN) Rpc_dns_gethostbyname_addrtype(hostname string, addr []byte, found uint32, callback_arg []byte, dns_addrtype uint8) (int8, error) { +func (r *RTL8720DN) Rpc_dns_gethostbyname_addrtype(hostname string, addr *[]byte, found uint32, callback_arg []byte, dns_addrtype uint8) (int8, error) { if r.debug { fmt.Printf("rpc_dns_gethostbyname_addrtype()\r\n") } @@ -7745,9 +7809,10 @@ func (r *RTL8720DN) Rpc_dns_gethostbyname_addrtype(hostname string, addr []byte, addr_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if addr_length > 0 { - copy(addr, payload[widx:widx+int(addr_length)]) + copy(*addr, payload[widx:widx+int(addr_length)]) widx += int(addr_length) } + *addr = (*addr)[:addr_length] var result int8 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -8004,6 +8069,7 @@ func (r *RTL8720DN) Rpc_wifi_ssl_get_rootCA(ssl_client uint32, rootCABuff string rootCABuff = string(payload[widx : widx+int(rootCABuff_length)]) widx += int(rootCABuff_length) } + rootCABuff = (rootCABuff)[:rootCABuff_length] var result uint32 result = uint32(binary.LittleEndian.Uint32(payload[widx:])) @@ -8418,7 +8484,7 @@ func (r *RTL8720DN) Rpc_wifi_send_ssl_data(ssl_client uint32, data []byte, lengt return result, err } -func (r *RTL8720DN) Rpc_wifi_get_ssl_receive(ssl_client uint32, data []byte, length int32) (int32, error) { +func (r *RTL8720DN) Rpc_wifi_get_ssl_receive(ssl_client uint32, data *[]byte, length int32) (int32, error) { if r.debug { fmt.Printf("rpc_wifi_get_ssl_receive()\r\n") } @@ -8446,9 +8512,10 @@ func (r *RTL8720DN) Rpc_wifi_get_ssl_receive(ssl_client uint32, data []byte, len data_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if data_length > 0 { - copy(data, payload[widx:widx+int(data_length)]) + copy(*data, payload[widx:widx+int(data_length)]) widx += int(data_length) } + *data = (*data)[:data_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -8526,7 +8593,7 @@ func (r *RTL8720DN) Rpc_wifi_verify_ssl_dn(ssl_client uint32, domain_name string return result, err } -func (r *RTL8720DN) Rpc_wifi_ssl_strerror(errnum int32, buffer []byte, buflen uint32) error { +func (r *RTL8720DN) Rpc_wifi_ssl_strerror(errnum int32, buffer *[]byte, buflen uint32) error { if r.debug { fmt.Printf("rpc_wifi_ssl_strerror()\r\n") } @@ -8554,9 +8621,10 @@ func (r *RTL8720DN) Rpc_wifi_ssl_strerror(errnum int32, buffer []byte, buflen ui buffer_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if buffer_length > 0 { - copy(buffer, payload[widx:widx+int(buffer_length)]) + copy(*buffer, payload[widx:widx+int(buffer_length)]) widx += int(buffer_length) } + *buffer = (*buffer)[:buffer_length] r.seq++ return err @@ -8827,7 +8895,7 @@ func (r *RTL8720DN) Rpc_mdns_hostname_set(hostname string) (int32, error) { return result, err } -func (r *RTL8720DN) Rpc_mdns_query_a(host_name string, timeout uint32, addr []byte) (int32, error) { +func (r *RTL8720DN) Rpc_mdns_query_a(host_name string, timeout uint32, addr *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_mdns_query_a()\r\n") } @@ -8853,9 +8921,10 @@ func (r *RTL8720DN) Rpc_mdns_query_a(host_name string, timeout uint32, addr []by addr_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if addr_length > 0 { - copy(addr, payload[widx:widx+int(addr_length)]) + copy(*addr, payload[widx:widx+int(addr_length)]) widx += int(addr_length) } + *addr = (*addr)[:addr_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -8870,7 +8939,7 @@ func (r *RTL8720DN) Rpc_mdns_query_a(host_name string, timeout uint32, addr []by return result, err } -func (r *RTL8720DN) Rpc_mdns_query_ptr(service_type string, proto string, timeout uint32, max_results int32, result_total int32) (int32, error) { +func (r *RTL8720DN) Rpc_mdns_query_ptr(service_type string, proto string, timeout uint32, max_results int32, result_total *int32) (int32, error) { if r.debug { fmt.Printf("rpc_mdns_query_ptr()\r\n") } @@ -8901,7 +8970,8 @@ func (r *RTL8720DN) Rpc_mdns_query_ptr(service_type string, proto string, timeou <-r.received widx := 8 // result_total : out int32 - // not impl + *result_total = int32(binary.LittleEndian.Uint32(payload[widx:])) + widx += 4 var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -8916,7 +8986,7 @@ func (r *RTL8720DN) Rpc_mdns_query_ptr(service_type string, proto string, timeou return result, err } -func (r *RTL8720DN) Rpc_mdns_query_ptr_result_basic(result_target int32, scan_result []byte) (int32, error) { +func (r *RTL8720DN) Rpc_mdns_query_ptr_result_basic(result_target int32, scan_result *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_mdns_query_ptr_result_basic()\r\n") } @@ -8939,9 +9009,10 @@ func (r *RTL8720DN) Rpc_mdns_query_ptr_result_basic(result_target int32, scan_re scan_result_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if scan_result_length > 0 { - copy(scan_result, payload[widx:widx+int(scan_result_length)]) + copy(*scan_result, payload[widx:widx+int(scan_result_length)]) widx += int(scan_result_length) } + *scan_result = (*scan_result)[:scan_result_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -8956,7 +9027,7 @@ func (r *RTL8720DN) Rpc_mdns_query_ptr_result_basic(result_target int32, scan_re return result, err } -func (r *RTL8720DN) Rpc_mdns_query_ptr_result_txt(result_target int32, txt_target int32, txt []byte) (int32, error) { +func (r *RTL8720DN) Rpc_mdns_query_ptr_result_txt(result_target int32, txt_target int32, txt *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_mdns_query_ptr_result_txt()\r\n") } @@ -8984,9 +9055,10 @@ func (r *RTL8720DN) Rpc_mdns_query_ptr_result_txt(result_target int32, txt_targe txt_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if txt_length > 0 { - copy(txt, payload[widx:widx+int(txt_length)]) + copy(*txt, payload[widx:widx+int(txt_length)]) widx += int(txt_length) } + *txt = (*txt)[:txt_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) @@ -9001,7 +9073,7 @@ func (r *RTL8720DN) Rpc_mdns_query_ptr_result_txt(result_target int32, txt_targe return result, err } -func (r *RTL8720DN) Rpc_mdns_query_ptr_result_addr(result_target int32, addr_target int32, addr []byte) (int32, error) { +func (r *RTL8720DN) Rpc_mdns_query_ptr_result_addr(result_target int32, addr_target int32, addr *[]byte) (int32, error) { if r.debug { fmt.Printf("rpc_mdns_query_ptr_result_addr()\r\n") } @@ -9029,9 +9101,10 @@ func (r *RTL8720DN) Rpc_mdns_query_ptr_result_addr(result_target int32, addr_tar addr_length := binary.LittleEndian.Uint32(payload[widx:]) widx += 4 if addr_length > 0 { - copy(addr, payload[widx:widx+int(addr_length)]) + copy(*addr, payload[widx:widx+int(addr_length)]) widx += int(addr_length) } + *addr = (*addr)[:addr_length] var result int32 x := binary.LittleEndian.Uint32(payload[widx:]) diff --git a/rtl8720dn/wifi.go b/rtl8720dn/wifi.go index 9329b4a..cfd7fb8 100644 --- a/rtl8720dn/wifi.go +++ b/rtl8720dn/wifi.go @@ -59,7 +59,7 @@ func (r *RTL8720DN) ConnectToAP(ssid string, password string) error { func (r *RTL8720DN) GetIP() (ip, subnet, gateway IPAddress, err error) { ip_info := make([]byte, 12) - _, err = r.Rpc_tcpip_adapter_get_ip_info(0, ip_info) + _, err = r.Rpc_tcpip_adapter_get_ip_info(0, &ip_info) if err != nil { return nil, nil, nil, err }