I'm trying to open an RFCOMM socket from Go. I have a test setup where the client connects to an echo server. The part that I'm stuck on is setting up the Bluetooth address. In C you have str2ba, which converts the MAC string to a byte array of six elements. In Go it appears it expects the device to be a uint16. I'm not sure how this would work.
package main
import (
"fmt"
"log"
"syscall"
"golang.org/x/sys/unix"
)
func main() {
fd, err := unix.Socket(syscall.AF_BLUETOOTH, syscall.SOCK_STREAM, unix.BTPROTO_RFCOMM)
if err != nil {
log.Fatalf("%v\n", err)
}
addr := unix.SockaddrHCI{Dev: 1, Channel: 1}
unix.Connect(fd, addr)
unix.Write(fd, []byte("Hello"))
var data []byte
unix.Read(fd, data)
fmt.Printf("Received: %v\n", string(data))
}
The Dev member in unix.SockaddrHCI is a uint16 and I think this is to represent the Bluetooth MAC. Is this correct?
Thanks.
I think that topicstarter already doesn't need this answer, but I needed it yesterday )) Kinda found right answer, so let me share the code that worked in my case (it was a HC06 bluetooth module for Arduino). I assume that module already was bt discovered and paired (e.g by means of bluetoothctl).
package main
import (
"strconv"
"strings"
"syscall"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
func main() {
mac := str2ba("00:19:10:08:FE:08") // YOUR BLUETOOTH MAC ADDRESS HERE
fd, err := unix.Socket(syscall.AF_BLUETOOTH, syscall.SOCK_STREAM, unix.BTPROTO_RFCOMM)
check(err)
addr := &unix.SockaddrRFCOMM{Addr: mac, Channel: 1}
var data = make([]byte, 50)
logrus.Print("connecting...")
err = unix.Connect(fd, addr)
check(err)
defer unix.Close(fd)
logrus.Println("done")
for {
n, err := unix.Read(fd, data)
check(err)
if n > 0 {
logrus.Infof("Received: %v\n", string(data[:n]))
}
}
}
func check(err error) {
if err != nil {
logrus.Fatal(err)
}
}
// str2ba converts MAC address string representation to little-endian byte array
func str2ba(addr string) [6]byte {
a := strings.Split(addr, ":")
var b [6]byte
for i, tmp := range a {
u, _ := strconv.ParseUint(tmp, 16, 8)
b[len(b)-1-i] = byte(u)
}
return b
}
Related
I've accidentally spotted a bug when parts of a message from previous connection go to the next message.
I have a basic server with client. I have removed all the error handling to avoid bloating the examples too much.
Also I've replaced some Printf's with time.Sleep since I just don't have a chance to break the connection in time to reproduce the bug because it reads the data too fast.
The "package" is a simple structure, where the first 4 bytes is the length and then goes the content.
Client code:
package main
import (
"encoding/binary"
"fmt"
"net"
)
func main() {
conn, _ := net.Dial("tcp", "0.0.0.0:8081")
defer conn.Close()
str := "msadsakdjsajdklsajdklsajdk"
// Creating a package
buf := make([]byte, len(str)+4)
copy(buf[4:], str)
binary.LittleEndian.PutUint32(buf[:4], uint32(len(str)))
for {
_, err := conn.Write(buf)
if err != nil {
fmt.Println(err)
return
}
}
}
Server code:
package main
import (
"encoding/binary"
"fmt"
"net"
"sync"
"time"
)
func ReadConnection(conn net.Conn, buf []byte) (err error) {
maxLen := cap(buf)
readSize := 0
for readSize < maxLen {
// instead of Printf
time.Sleep(time.Nanosecond * 10)
readN, err := conn.Read(buf[readSize:])
if err != nil {
return err
}
readSize += readN
}
return nil
}
func handleConnection(conn net.Conn, waitGroup *sync.WaitGroup) {
waitGroup.Add(1)
defer conn.Close()
defer waitGroup.Done()
fmt.Printf("Serving %s\n", conn.RemoteAddr().String())
var packageSize int32 = 0
int32Buf := make([]byte, 4)
for {
// read the length
conn.Read(int32Buf)
packageSize = int32(binary.LittleEndian.Uint32(int32Buf))
// assuming the length should be 26
if packageSize > 26 {
fmt.Println("Package size error")
return
}
// read the content
packageBuf := make([]byte, packageSize)
if err := ReadConnection(conn, packageBuf); err != nil {
fmt.Printf("ERR: %s\n", err)
return
}
// instead of Printf
time.Sleep(time.Nanosecond * 100)
}
}
func main() {
//establish connection
listener, _ := net.Listen("tcp", "0.0.0.0:8081")
defer listener.Close()
waitGroup := sync.WaitGroup{}
for {
conn, err := listener.Accept()
if err != nil {
break
}
go handleConnection(conn, &waitGroup)
}
waitGroup.Wait()
}
So for some reason, int32Buf receives the last 2 bytes from a previous message (d, k) and the first 2 bytes of the length, resulting in [107, 100, 26, 0] bytes slice, when it should be [26, 0, 0, 0].
And of course, the rest of the data contains remaining two zeroes:
conn.Read(int32Buf)
You need to check the return value of conn.Read and compare it against your expectations. You are assuming in your code that conn.Read will always completely fill the given buffer of 4 bytes.
This assumption is wrong, i.e. it might actually read less data. Specifically it might read only 2 bytes in which case you'll end up with \x1a\x00\x00\x00 in your buffer which still translates to a message length of 26. Only, the first 2 bytes of the message will actually be the last 2 bytes of the length which were not included in the last read. This means after reading the 26 bytes it will not have read the full message. 2 bytes are legt and will be included into the next message - this is what you observed.
To be sure that the exact size of the buffer is read check the return values of conn.Read or use io.ReadFull. After you've done this it works as expected (from the comment):
Ok, now it works perfect
So why does this happened only in context of a new connection? Maybe because the additional load due to another connection changed the behavior slightly but significantly enough. Still, these are not the data read from a different connection but data from the current one contrary to the description in the question. This could be easily checked by using different messages with different clients.
I am new to programming Golang Sockets. When I try to send one message from client to server, it is working perfectly. However, when I try to send 10 consecutive messages, I get an error. Any clues/keywords to search for. Please find enclosed a sample code.
Server.go
package main
import (
"encoding/gob"
"fmt"
"net"
"os"
)
func main() {
tcpAddr, err := net.ResolveTCPAddr("tcp4", ":5555")
checkError("ResolveTCPAddr", err)
listener, err := net.ListenTCP("tcp", tcpAddr)
checkError("ListenTCP", err)
conn, err := listener.Accept()
checkError("Accept", err)
for i := 0; i < 10; i++ {
var s string
dec := gob.NewDecoder(conn)
err = dec.Decode(&s)
checkError("Decode", err)
fmt.Println(s)
}
}
func checkError(info string, err error) {
if err != nil {
fmt.Fprintf(os.Stderr, info+": Run - Fatal error: %s\n", err.Error())
os.Exit(1)
}
}
Client.go
package main
import (
"encoding/gob"
"fmt"
"net"
"os"
)
func main() {
tcpAddr, err := net.ResolveTCPAddr("tcp4", ":5555")
checkError("ResolveTCPAddr", err)
conn, err := net.DialTCP("tcp", nil, tcpAddr)
checkError("DialTCP", err)
for i := 0; i < 10; i++ {
enc := gob.NewEncoder(conn)
err = enc.Encode("test")
checkError("Encode", err)
}
}
func checkError(info string, err error) {
if err != nil {
fmt.Fprintf(os.Stderr, info+": Run - Fatal error: %s\n", err.Error())
os.Exit(1)
}
}
SCREEN:
test
test
test
test
test
Decode: Run - Fatal error: EOF
exit status 1
The problem is that a decoder buffers data from the underlying reader and that buffered data can include data from a later message in the stream. The buffered data is discarded when the application discards the decoder. A later decoder returns an error because it is reading an incomplete message.
There's an easy fix to this problem. The gob package is designed to read and write streams of values. Create the encoder and decoder outside of the loop and let the package handle the message framing.
enc := gob.NewEncoder(conn)
for i := 0; i < 10; i++ {
err = enc.Encode("test")
checkError("Encode", err)
}
dec := gob.NewDecoder(conn)
for i := 0; i < 10; i++ {
var s string
err = dec.Decode(&s)
checkError("Decode", err)
fmt.Println(s)
}
If for some reason you must create the encoder and decoder inside the loop, then the application must implement message framing to prevent the decoder from reading more than a single value. One way to frame the messages is to have the client write a length prefix before the gob encoded value. The server reads the length and then limits the decoder to reading that number of bytes.
I've dived into the call stack of both os.OpenFile and net.Listen to see if I can make a UNIX domain socket using os.OpenFile. Below is my attempt. But, after tracing both call stacks (os.OpenFile's and net.Listen's) I'm still confused. The below code doesn't read from the file, apparently, and stores the data to the filesystem.
How can I implement a UNIX domain socket using os.OpenFile?
What is the purpose of os.ModeSocket if it's not to be used with os.OpenFile to create a UNIX socket?
package main
import (
"fmt"
"log"
"os"
)
func main() {
sock, err := os.OpenFile("f.sock", os.O_RDWR|os.O_CREATE, os.ModeSocket|os.ModePerm)
defer sock.Close()
if err != nil {
log.Panic(err)
}
n, err := sock.WriteString("hello\n")
if err != nil {
fmt.Println(err)
} else {
fmt.Println(n)
}
b := make([]byte, 10)
n, err = sock.Read(b)
fmt.Println(n)
if err != nil {
fmt.Println("error reading: ", err)
}
fmt.Println(b)
}
No. OpenFile is a generalized api for opening file, use net.Listen("unixpacket", "f.sock") or net.Dial("unixpacket", "f.sock") if you wanna work with unix socket
os.ModeSocket is just a *nix registered flag for socket fd, use when you want to filter fd types
I'm developing a fast dns client in go just to mess around with But I'm facing troubles at the time of reading from server responses cause it never arrives and I know it actually did because I have WireShark open and it read the packet.
Here is the code sample(8.8.8.8 is Google DNS and the hex msg is a valid DNS query):
package main
import (
"fmt"
"net"
"encoding/hex"
"bufio"
)
func CheckError(err error) {
if err != nil {
fmt.Println("Error: " , err)
}
}
func main() {
Conn, err := net.Dial("udp", "8.8.8.8:53")
CheckError(err)
defer Conn.Close()
msg, _ := hex.DecodeString("5ab9010000010000000000001072312d2d2d736e2d68357137646e65650b676f6f676c65766964656f03636f6d0000010001")
scanner := bufio.NewScanner(Conn)
buf := []byte(msg)
_, err1 := Conn.Write(buf)
if err1 != nil {
fmt.Println(msg, err1)
}
for scanner.Scan() {
fmt.Println(scanner.Bytes())
}
}
Here you have the proof that it actually arrives:
WireShark Screen Capture
I've testes reading directly from conn with:
func main() {
Conn, err := net.Dial("udp", "8.8.8.8:53")
CheckError(err)
defer Conn.Close()
msg, _ := hex.DecodeString("5ab9010000010000000000001072312d2d2d736e2d68357137646e65650b676f6f676c65766964656f03636f6d0000010001")
buf := []byte(msg)
_, err1 := Conn.Write(buf)
if err1 != nil {
fmt.Println(msg, err1)
}
Reader(Conn)
}
func Reader(conn net.Conn) {
var buf []byte
for {
conn.Read(buf)
fmt.Println(buf)
}
}
You can't use bufio around a UDP connection. UDP is not a stream oriented protocol, so you need to differentiate the individual datagrams yourself, and avoid partial reads to prevent data loss.
In order to read from an io.Reader, you must have space allocated to read into, and you need to use the bytes read value returned from the Read operation. Your example could be reduced to:
conn, err := net.Dial("udp", "8.8.8.8:53")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
msg, _ := base64.RawStdEncoding.DecodeString("WrkBAAABAAAAAAAAEHIxLS0tc24taDVxN2RuZWULZ29vZ2xldmlkZW8DY29tAAABAAE")
resp := make([]byte, 512)
conn.Write(msg)
n, err := conn.Read(resp)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%q\n", resp[:n])
I have zeromq: stable 4.1.4 installed using brew on MacOSX and have written a simple PUB/SUB program to test zeromq. But when I run the sample program using flags --bufsize > 5 (to use a buffer of size > 5MB) (go run go_zmq_pubsub.go --bufsize=6); it throws the following exception:
No buffer space available (tcp.cpp:69)
SIGABRT: abort
PC=0x7fff9911c286 m=0
signal arrived during cgo execution
Below is the program I used to test the zeromq4.x
package main
import (
"fmt"
"flag"
"strconv"
"sync"
log "github.com/Sirupsen/logrus"
zmq "github.com/pebbe/zmq4"
"time"
)
var _ = fmt.Println
func main(){
var port int
var bufsize int
flag.IntVar(&port, "port", 7676, "server's zmq tcp port")
flag.IntVar(&bufsize, "bufsize", 0, "socket kernel buffer size")
flag.Parse();
publisher, err := zmq.NewSocket(zmq.PUB)
if(err != nil) {
log.Fatal(err)
}
//set publisher kernel transmit buffer size
//convert into bytes
if err := publisher.SetSndbuf(bufsize * 1000000); err != nil {
log.Fatal(err)
}
defer publisher.Close()
publisher.Bind("tcp://*:" + strconv.Itoa(port))
//SETUP subscriber
subscriber, err := zmq.NewSocket(zmq.SUB)
if(err != nil) {
log.Fatal(err)
}
//set subscriber kernel receive buffer size
if err := subscriber.SetRcvbuf(bufsize * 1000000); err != nil {
log.Fatal(err)
}
defer subscriber.Close()
subscriber.Connect("tcp://127.0.0.1:" + strconv.Itoa(port))
subscriber.SetSubscribe("")
var wg sync.WaitGroup
wg.Add(2)
idx := 0
go func(wg *sync.WaitGroup) {
//start streaming messages
ticker := time.NewTicker(1 * time.Second)
go func() {
for {
select {
case <-ticker.C:
_, err = publisher.Send("PKG:"+strconv.Itoa(idx), 0)
idx++;
if(err != nil) {
log.Error(err)
}
}
}
}()
}(&wg)
//receiver
go func(wg *sync.WaitGroup) {
go func(){
for {
payload, err := subscriber.Recv(0)
_ = payload
if err != nil {
log.Error(err)
break
}
//now sending into worker pool
log.Info("RECEIVE:" + payload)
}
}()
}(&wg)
wg.Wait()
}
On Centos7 with lib-zeromq built from source, the above code works without problem.
Not sure if it's due to libzeromq or the OS itself.
Thanks.
A buffer size of > 5MB is pointless. Anything beyond the bandwidth-delay product of the link concerned is wasted space.
Moderate your requirements.