GO: implementing syscall.Sockaddr - go

I am working on an embedded system that uses GO v1.13 on the build server. My goal is to make a CANbus manager using linux's socketCAN. Go has a can-go package that is perfect for this solution. However, the package uses the "golang.org/x/sys/" package that uses the unsafe.Slice that was added in Go v1.17. I am unable to upgrade my version to a supported go version.
To solve this issue, I am making my own package that is very similar to can-go but uses syscall.socket instead of unix.socket.
The issue that I have ran into is with the implementation of syscall.Sockaddr. I have implemented it identically to the can-go package but I am getting the following terminal output.
.\canSocket.go:91:42: cannot use &SockaddrCAN literal (type *SockaddrCAN) as type syscall.Sockaddr in argument to syscall.Bind:
*SockaddrCAN does not implement syscall.Sockaddr (missing syscall.sockaddr method)
have sockaddr() (unsafe.Pointer, int32, error)
want syscall.sockaddr() (unsafe.Pointer, int32, error)
I must be missing something very obvious as this looks to be the standard "you are incorrectly implementing an interface" message. I am very new to GO and am expecting that I have missed something fundamental. Can anyone see what I did wrong? Below is the relevant section of my code.
func DialRaw(device string) (net.Conn, error) {
var err error
defer func() {
if err != nil {
err = &net.OpError{Op: "dial", Net: canRawNetwork, Addr: &canRawAddr{device: device}, Err: err}
}
}()
ifi, err := net.InterfaceByName(device)
if err != nil {
return nil, fmt.Errorf("interface %s: %w", device, err)
}
fd, err := syscall.Socket(AF_CAN, SOCK_RAW, CAN_RAW)
if err != nil {
return nil, fmt.Errorf("socket: %w", err)
}
// put fd in non-blocking mode so the created file will be registered by the runtime poller (Go >= 1.12)
if err := syscall.SetNonblock(fd, true); err != nil {
return nil, fmt.Errorf("set nonblock: %w", err)
}
if err := syscall.Bind(fd, &SockaddrCAN{Ifindex: ifi.Index}); err != nil {
return nil, fmt.Errorf("bind: %w", err)
}
return &fileConn{ra: &canRawAddr{device: device}, f: os.NewFile(uintptr(fd), "can")}, nil
}
type RawSockaddrCAN struct {
Family uint16
Ifindex int32
Addr [16]byte
}
type SockaddrCAN struct {
Ifindex int
RxID uint32
TxID uint32
raw RawSockaddrCAN
}
func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, int32, error) {
if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
return nil, 0, EINVAL
}
sa.raw.Family = AF_CAN
sa.raw.Ifindex = int32(sa.Ifindex)
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
for i := 0; i < 4; i++ {
sa.raw.Addr[i] = rx[i]
}
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
for i := 0; i < 4; i++ {
sa.raw.Addr[i+4] = tx[i]
}
return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
}

Related

How to find server real IP

How do I find the public IP address of the machine or server my program is running on?
Like when the program is executed it detect the public of the server and print for e.g.running at 123.45.67.89
The short answer is that there's no method guaranteed to return your "public" ip address.
The first question is, what is your public ip address? The address of your machine, as seen by the system to which you are connecting, may vary depending on how your local Internet service is configured and on the service to which you're connecting:
As I mentioned in a comment, in a typical home environment your machine doesn't have a public ip address. The public address is hosted by your router.
If you're accessing a service through a proxy or vpn, your machine's address may be entirely different from when you're directly connecting to a service.
On a system with multiple interfaces, the origin address selected may depend upon the address to which you are connecting: different addresses may have different routes.
You can try using a service like http://icanhazip.com/ to try to determine your public ip. This will be correct in many but not all situations.
public IP address is a vague notion, in practice, it might or might not be a static address. What do you know about that ? It is just a endpoint valid for a certain amount of time, which depends on many factors like which interface was used to issue the query.
We can use the mainline bittorrent dht to give us some indications.
The Go language provides the cool dht package written by anacrolix.
When querying nodes with a find_peers verb we receive a packet containing the remote ip address the peer has associated with our query. This is described in bep10.
If an UDP connection is not a good option, you might opt for a query to bittorent trackers as described in bep24
Consider that peers might be malicious, thus the more results, the better.
Below program outputs the list of external network addresses associated with the computer initiating the query from the POV of the cohort of nodes queried.
Addresses are scored by the numbers of response.
read also https://www.bittorrent.org/beps/bep_0005.html
found 9 bootstrap peers
found 6 peers
4 [2001:861:51c5:xxx:40d1:8061:1fe0:xxx]:9090
2 81.96.42.191:9090
4 peers told us that we were using [2001:861:51c5:xxx:40d1:8061:1fe0:xxx]:9090, we can infer this is ipv6.
2 of them told we were using 81.96.42.191:9090, the ipv4 interface.
package main
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"sort"
"sync"
"time"
"github.com/anacrolix/dht"
"github.com/anacrolix/dht/krpc"
"github.com/anacrolix/torrent/bencode"
)
var maxTimeout = time.Second * 5
func main() {
b, _ := ioutil.ReadFile("db.json")
var rawAddrs []string
json.Unmarshal(b, &rawAddrs)
defer func() {
if len(rawAddrs) < 1 {
return
}
if len(rawAddrs) > 30 {
rawAddrs = rawAddrs[:30]
}
buf, err := json.Marshal(rawAddrs)
if err != nil {
panic(err)
}
err = ioutil.WriteFile("db.json", buf, os.ModePerm)
if err != nil {
panic(err)
}
fmt.Fprintf(os.Stderr, "%v peers recorded\n", len(rawAddrs))
}()
bootstrap, err := parseAddrs(rawAddrs)
if err != nil {
bootstrap, err = globalBootstrapAddrs()
if err != nil {
panic(err)
}
}
findPeers := []byte(`d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456e1:q9:get_peers1:t2:aa1:y1:qe`)
local, err := net.ResolveUDPAddr("udp", "0.0.0.0:9090")
if err != nil {
panic(err)
}
ln, err := net.ListenUDP("udp", local)
if err != nil {
panic(err)
}
addrscores := map[string]int{}
var drain drain
defer drain.Wait()
fmt.Fprintf(os.Stderr, "found %v bootstrap peers\n", len(bootstrap))
res, errs := readResponses(ln, len(bootstrap), sendQuery(ln, bootstrap, findPeers))
drain.Errors(errs)
peers := []net.Addr{}
for d := range res {
if isValidAddr(d.IP.UDP()) {
addrscores[d.IP.String()]++
d.R.ForAllNodes(func(arg1 krpc.NodeInfo) {
peers = append(peers, arg1.Addr.UDP())
})
}
}
if len(peers) > 0 {
fmt.Fprintf(os.Stderr, "found %v peers\n", len(peers))
res, errs = readResponses(ln, len(peers), sendQuery(ln, peers, findPeers))
drain.Errors(errs)
for d := range res {
if isValidAddr(d.IP.UDP()) {
addrscores[d.IP.String()]++
}
}
}
for _, peer := range peers {
if isValidAddr(peer) {
rawAddrs = append(rawAddrs, peer.String())
}
}
addrs := make([]string, 0, len(addrscores))
for addr := range addrscores {
addrs = append(addrs, addr)
}
sort.Slice(addrs, func(i int, j int) bool {
return addrscores[addrs[i]] > addrscores[addrs[j]]
})
for _, addr := range addrs {
fmt.Printf("%-4v %v\n", addrscores[addr], addr)
}
}
type drain struct{ sync.WaitGroup }
func (d *drain) Errors(errs <-chan error) {
d.Add(1)
go func() {
defer d.Done()
for err := range errs {
fmt.Fprintln(os.Stderr, err)
}
}()
}
func parseAddrs(rawAddrs []string) (addrs []net.Addr, err error) {
for _, s := range rawAddrs {
host, port, err := net.SplitHostPort(s)
if err != nil {
panic(err)
}
ua, err := net.ResolveUDPAddr("udp", net.JoinHostPort(host, port))
if err != nil {
log.Printf("error resolving %q: %v", host, err)
continue
}
addrs = append(addrs, ua)
}
if len(addrs) == 0 {
err = errors.New("nothing resolved")
}
return
}
func globalBootstrapAddrs() (addrs []net.Addr, err error) {
bootstrap, err := dht.GlobalBootstrapAddrs("udp")
if err != nil {
return nil, err
}
for _, b := range bootstrap {
addrs = append(addrs, b.Raw())
}
return
}
func isValidAddr(addr net.Addr) bool { // so weird guys.
return addr.String() != "<nil>" && addr.String() != ":0"
}
func sendQuery(ln *net.UDPConn, peers []net.Addr, query []byte) chan error {
errs := make(chan error)
for _, addr := range peers {
go func(addr net.Addr) {
_, err := ln.WriteTo(query, addr)
if err != nil {
errs <- addressedError{Op: "send", error: err, Addr: addr}
}
}(addr)
}
return errs
}
func readResponses(ln *net.UDPConn, count int, errs chan error) (<-chan krpc.Msg, <-chan error) {
data := make(chan krpc.Msg)
var wg sync.WaitGroup
for i := 0; i < count; i++ {
wg.Add(1)
go func() {
defer wg.Done()
buf := make([]byte, 1000)
ln.SetReadDeadline(time.Now().Add(maxTimeout))
n, remoteAddr, err := ln.ReadFromUDP(buf)
if err != nil {
errs <- addressedError{Op: "rcv", error: err, Addr: remoteAddr}
return
}
var m krpc.Msg
err = bencode.Unmarshal(buf[:n], &m)
if err != nil {
errs <- addressedError{Op: "rcv", error: err, Addr: remoteAddr}
return
}
data <- m
}()
}
go func() {
wg.Wait()
close(errs)
close(data)
}()
return data, errs
}
type addressedError struct {
error
Op string
Addr net.Addr
}
func (a addressedError) Error() string {
if !isValidAddr(a.Addr) {
return fmt.Sprintf("%-5v %v", a.Op, a.error.Error())
}
return fmt.Sprintf("%-5v %v: %v", a.Op, a.Addr.String(), a.error.Error())
}

Golang unexpected EOF

Here's my code, I'm new to Go.
I tried googling the issue, but I can't quite put my finger on it.
I think it has something to do with the Read() method.
package main
import (
...
)
type compressor struct {
content []byte
}
func (r *compressor) compress() []byte {
...
}
func (r *compressor) decompress() []byte {
var buffer bytes.Buffer
dc := flate.NewReader(&buffer)
_, err := dc.Read(r.content)
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
}
return buffer.Bytes()
}
func main() {
fileName := os.Args[1]
fmt.Println(os.Args)
contents, err := ioutil.ReadFile(fileName)
if err != nil {
log.Fatal(err)
}
fmt.Print("Uncompressed data: ")
fmt.Println(len(contents))
comp := compressor{contents}
buffer := comp.decompress()
fmt.Print("Uncompressed data: ")
fmt.Println(len(comp.decompress()))
err = ioutil.WriteFile(fileName+".decjc", buffer, 0644)
if err != nil {
log.Fatal(err)
}
}
Here's the output
dylan#skynet:~/Documents/EXP/jc$ ./jc data.txt.jc
[./jc data.txt.jc]
Uncompressed data: 2364480
2018/06/29 21:41:35 unexpected EOF
After doing a trace on the particular code in question I have come to the following answer.
/src/bytes/reader.go 70
func (r *Reader) ReadByte() (byte, error) {
...
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
....
}
There are four functions in bytes/reader that can return io.EOF, and zero functions that can return io.ErrUnexpectedEOF. The four functions that can return io.EOF are:
Read(b []byte)
ReadAt(b []byte, off int64)
ReadByte()
ReadRune()
/src/compress/flate/inflate.go 698
func (f *decompressor) moreBits() error {
c, err := f.r.ReadByte()
if err != nil {
return noEOF(err)
}
...
}
Of the four functions that can return io.EOF, only one function in flate/inflate.go calls any of them: moreBits() calls ReadByte()
/src/compress/flate/inflate.go 690
func noEOF(e error) error {
if e == io.EOF {
return io.ErrUnexpectedEOF
}
...
}
When moreBits() receives an error it calls noEOF(), which checks if it had received an io.EOF. If this was the case then io.ErrUnexpectedEOF is returned backed. Everything seems to be working as intended, and it appears that it is the user's responsibility to be on the look out for this particular case. A suggested edit to the code above to handle what appears to be defined behavior is:
func (r *compressor) decompress() []byte {
dc := flate.NewReader(bytes.NewReader(r.content))
defer dc.Close()
rb, err := ioutil.ReadAll(dc)
if err != nil {
if err != io.EOF && err != io.ErrUnexpectedEOF {
log.Fatalf("Err %v\n read %v", err, rb)
}
}
return rb
}
This was checked under go1.12.9
You got the in and outputs mixed up.
flate.NewReader takes the compressed input as an io.Reader and it returns a io.ReadCloser that can be used to get the uncompressed output:
func (r *compressor) decompress() []byte {
dc := flate.NewReader(bytes.NewReader(r.content))
defer dc.Close()
rb, err := ioutil.ReadAll(dc)
if err != nil {
if err != io.EOF {
log.Fatalf("Err %v\n read %v", err, rb)
}
}
return rb
}

How to gob encode struct with unexported pointer?

I have a struct that I can successfully gob encode and decode as follows:
type Node struct {
Value int
Next *Node
}
myNode := Node{
Value: 1,
Next: &Node{
Value: 2,
},
}
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
dec := gob.NewDecoder(&buf)
if err := enc.Encode(&myNode); err != nil {
panic(err)
}
var decodedNode Node
if err := dec.Decode(&decodedNode); err != nil {
panic(err)
}
I'd like to now hide the fields of Node:
type Node struct {
value int
next *Node
}
Because the fields are no longer exported I have to now write custom GobEncode and GobDecode functions:
func (d *Node) GobEncode() ([]byte, error) {
var buf bytes.Buffer
encoder := gob.NewEncoder(&buf)
if err := encoder.Encode(d.value); err != nil {
return nil, err
}
if err := encoder.Encode(d.next); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (d *Node) GobDecode(b []byte) error {
buf := bytes.NewBuffer(b)
decoder := gob.NewDecoder(buf)
if err := decoder.Decode(&d.value); err != nil {
return err
}
if err := decoder.Decode(&d.next); err != nil {
return err
}
return nil
}
This doesn't work because of a nil value in Node.next:
panic: gob: cannot encode nil pointer of type *main.Node [recovered]
panic: gob: cannot encode nil pointer of type *main.Node [recovered]
panic: gob: cannot encode nil pointer of type *main.Node
I'm re-using gob.NewEncoder inside my custom function because I'm trying to re-use as much of the encode package as possible.
Any suggestions for getting this working?

Go: Reading and writing compressed gob to file

This does not appear to work correctly and I'm not sure what I'm doing wrong. I'm attempting to convert a map into a gob, gzip the binary and save it to a file, then later read it back.
type Object struct {
mystruct map[string][]scorer
}
type scorer struct {
category int
score float64
}
func (t *Object) Load(filename string) error {
fi, err := os.Open(filename)
if err !=nil {
return err
}
defer fi.Close()
fz, err := gzip.NewReader(fi)
if err !=nil {
return err
}
defer fz.Close()
decoder := gob.NewDecoder(fz)
err = decoder.Decode(&t.mystruct)
if err !=nil {
return err
}
return nil
}
func (t *Object) Save(filename string) error {
fi, err := os.Create(filename)
if err !=nil {
return err
}
defer fi.Close()
fz := gzip.NewWriter(fi)
defer fz.Close()
encoder := gob.NewEncoder(fz)
err = encoder.Encode(t.mystruct)
if err !=nil {
return err
}
return nil
}
Something is saved to a file and the gzip appears to be valid, but it is either saving nothing or not loading it back again.
I'm also not sure if I'm doing this correctly as I'm new to Go and I'm finding it difficult to get my head around the readers and writers, since I'm coming from PHP and not used to that.
Any ideas?
Your problem has nothing to do with Readers and Writers: You just cannot encode/decode fields which are un-exported and all your fields are unexported (lowercase). You'll have to use Mystruct, Categoryand Score or write your own BinaryMarshal/BinaryUnmarshal as explained in http://golang.org/pkg/encoding/gob/#example__encodeDecode

pass interface pointer and assignment value

I want to write a file cache in Go. I am using gob encoding, and saving to a file, but my get function has some problem:
package main
import (
"encoding/gob"
"fmt"
"os"
)
var (
file = "tmp.txt"
)
type Data struct {
Expire int64
D interface{}
}
type User struct {
Id int
Name string
}
func main() {
user := User{
Id: 1,
Name: "lei",
}
err := set(file, user, 10)
if err != nil {
fmt.Println(err)
return
}
user = User{}
err = get(file, &user)
if err != nil {
fmt.Println(err)
return
}
//user not change.
fmt.Println(user)
}
func set(file string, v interface{}, expire int64) error {
f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
if err != nil {
return err
}
defer f.Close()
//wrapper data
//save v in data.D
data := Data{
Expire: expire,
D: v,
}
gob.Register(v)
enc := gob.NewEncoder(f)
err = enc.Encode(data)
if err != nil {
return err
}
return nil
}
func get(file string, v interface{}) error {
f, err := os.OpenFile(file, os.O_RDONLY, 0600)
if err != nil {
return err
}
defer f.Close()
var data Data
dec := gob.NewDecoder(f)
err = dec.Decode(&data)
if err != nil {
return err
}
//get v
v = data.D
fmt.Println(v)
return nil
}
The get function passes interface type and I want to change the value, but not change.
http://play.golang.org/p/wV7rBH028o
In order to insert an unknown value into v of type interface{}, you need to use reflection. This is somewhat involved, but if you want to support this in full, you can see how its done by walking through the decoding process in some of the encoding packages (json, gob).
To get you started, here's a basic version of your get function using reflection. This skips a number of checks, and will only decode something that was encoded as a pointer.
func get(file string, v interface{}) error {
f, err := os.OpenFile(file, os.O_RDONLY, 0600)
if err != nil {
return err
}
defer f.Close()
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
panic("need a non nil pointer")
}
var data Data
dec := gob.NewDecoder(f)
err = dec.Decode(&data)
if err != nil {
return err
}
dv := reflect.ValueOf(data.D)
if dv.Kind() != reflect.Ptr {
panic("didn't decode a pointer")
}
rv.Elem().Set(dv.Elem())
return nil
}
I would actually suggest an easier way to handle this in your own code, which is to have the Get function return an interface{}. Since you will know what the possible types are at that point, you can use a type switch to assert the correct value.
An alternative approach is to return directly the value from the file:
func get(file string) (interface{}, error) {
f, err := os.OpenFile(file, os.O_RDONLY, 0600)
if err != nil {
return nil, err
}
defer f.Close()
var data Data
dec := gob.NewDecoder(f)
err = dec.Decode(&data)
if err != nil {
return nil,err
}
fmt.Println(data.D)
return data.D,nil
}
full working example: http://play.golang.org/p/178U_LVC5y

Resources