golang get udp socket buffer size - sockets

I'm writing a udp client and set udp socket send buffer by SetWriteBuffer.
addr, _ := net.ResolveUDPAddr("udp", ":8089")
conn, err :=net.DialUDP("udp", nil, addr)
err =conn.SetWriteBuffer(64*1024*1024)
as above, how can I test set the value is effective or get the send buffer value after call SetWriteBuffer function.
Thank you all.

After looking at the net package code, it looks like SetWriteBuffer makes a syscall to setsockopt (for posix). There is no similar function for GetWriteBuffer. The only way i can think to do this is by making another syscall to getsockopt like so.
addr, _ := net.ResolveUDPAddr("udp", ":8089")
conn, _ := net.DialUDP("udp", nil, addr)
conn.SetWriteBuffer(10 * 1024)
fd, _ := conn.File()
value, _ := syscall.GetsockoptInt(int(fd.Fd()), syscall.SOL_SOCKET, syscall.SO_SNDBUF)
log.Println(value)
fd.Close()
conn.Close()

Check the error value returned by SetWriteBuffer. For example,
package main
import (
"log"
"net"
)
func main() {
addr, err := net.ResolveUDPAddr("udp", ":8089")
conn, err := net.DialUDP("udp", nil, addr)
err = conn.SetWriteBuffer(64 * 1024 * 1024)
if err != nil {
log.Print(err)
}
}

Related

Consecutive Encode/Decode using GOB

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.

Using os.OpenFile() instead of net.Listen()

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

How to deal with sticky tcp packet in go?

I have a tcp server and a client, the server does the following
func providerCallback(conn net.Conn) {
reader := bufio.NewReader(conn)
var err error
for {
lenbyte, _ := reader.Peek(4)
reader.Discard(4)
slen := int(binary.BigEndian.Uint32(lenbyte))
data, err = reader.Peek(slen)
process(data)
reader.Discard(slen)
}
}
The client seems to send packet faster than process can deal with, therefore I'd like to buffer the requests in bufio and process later.
However, as the size of bufio is fixed(4096, even though I can increase it, it is still fixed), which means I can't manually Reset it because there might be a packet cutting of in the end of bufio, as follows
|normal data... [First 20 bytes of packet P] | [the rest of packet P]
|------------------- size of bufio ------------------|
How can I splice packet that is cut off, and reuse the bufio for later packets?
For example,
import (
"bufio"
"encoding/binary"
"io"
"net"
)
func providerCallback(conn net.Conn) error {
rdr := bufio.NewReader(conn)
data := make([]byte, 0, 4*1024)
for {
n, err := io.ReadFull(rdr, data[:4])
data = data[:n]
if err != nil {
if err == io.EOF {
break
}
return err
}
dataLen := binary.BigEndian.Uint32(data)
if uint64(dataLen) > uint64(cap(data)) {
data = make([]byte, 0, dataLen)
}
n, err = io.ReadFull(rdr, data[:dataLen])
data = data[:n]
if err != nil {
return err
}
process(data)
}
return nil
}
func process([]byte) {}

UDP Socket not reading from server in Go

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])

Reading TCP packets via raw sockets in GO

I'm researching raw sockets in GO. I would like to be able to read all TCP packets going to my computer (OSX, en0: 192.168.1.65)
If I switch the protocol from tcp to icmp, I will get packets. Why do I have no packets being read with my code?
package main
import (
"fmt"
"net"
)
func main() {
netaddr, err := net.ResolveIPAddr("ip4", "192.168.1.65")
if err != nil {
fmt.Println(err)
}
conn, err := net.ListenIP("ip4:tcp", netaddr)
if err != nil {
fmt.Println(err)
}
buf := make([]byte, 2048)
for {
numRead, recvAddr, err := conn.ReadFrom(buf)
if err != nil {
fmt.Println(err)
}
if recvAddr != nil {
fmt.Println(recvAddr)
}
s := string(buf[:numRead])
fmt.Println(s)
}
}
The problem with this is that OS X is based on BSD, and BSD doesn't allow you to program raw sockets at the TCP level. You have to use go down to the Ethernet level in order to do so.
I'm using the pcap library with gopackets to do the job.
https://godoc.org/code.google.com/p/gopacket/pcap