func benchmarkReadWriteIPv4UDP(b *testing.B, p *ipv4.PacketConn, wb, rb []byte, dst net.Addr, ifi *net.Interface) { cm := ipv4.ControlMessage{TTL: 1} if ifi != nil { cm.IfIndex = ifi.Index } if n, err := p.WriteTo(wb, &cm, dst); err != nil { b.Fatal(err) } else if n != len(wb) { b.Fatalf("got %v; want %v", n, len(wb)) } if _, _, _, err := p.ReadFrom(rb); err != nil { b.Fatal(err) } }
func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "windows": t.Skipf("not supported on %s", runtime.GOOS) } c, err := net.ListenPacket("udp4", "127.0.0.1:0") if err != nil { t.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c) defer p.Close() dst, err := net.ResolveUDPAddr("udp4", c.LocalAddr().String()) if err != nil { t.Fatal(err) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) cf := ipv4.FlagTTL | ipv4.FlagSrc | ipv4.FlagDst | ipv4.FlagInterface wb := []byte("HELLO-R-U-THERE") if err := p.SetControlMessage(cf, true); err != nil { // probe before test if nettest.ProtocolNotSupported(err) { t.Skipf("not supported on %s", runtime.GOOS) } t.Fatal(err) } var wg sync.WaitGroup reader := func() { defer wg.Done() rb := make([]byte, 128) if n, cm, _, err := p.ReadFrom(rb); err != nil { t.Error(err) return } else if !bytes.Equal(rb[:n], wb) { t.Errorf("got %v; want %v", rb[:n], wb) return } else { s := cm.String() if strings.Contains(s, ",") { t.Errorf("should be space-separated values: %s", s) } } } writer := func(toggle bool) { defer wg.Done() cm := ipv4.ControlMessage{ Src: net.IPv4(127, 0, 0, 1), } if ifi != nil { cm.IfIndex = ifi.Index } if err := p.SetControlMessage(cf, toggle); err != nil { t.Error(err) return } if n, err := p.WriteTo(wb, &cm, dst); err != nil { t.Error(err) return } else if n != len(wb) { t.Errorf("short write: %v", n) return } } const N = 10 wg.Add(N) for i := 0; i < N; i++ { go reader() } wg.Add(2 * N) for i := 0; i < 2*N; i++ { go writer(i%2 != 0) } wg.Add(N) for i := 0; i < N; i++ { go reader() } wg.Wait() }
func (s *Server) ListenAndServeUDPv4() { ipAddr := &net.IPAddr{IP: net.IPv4zero} conn, err := net.ListenIP("ip4:udp", ipAddr) if err != nil { l.Info(err.Error()) return } defer conn.Close() if err = bindToDevice(conn, "tap"+s.name); err != nil { l.Info(err.Error()) return } s.Lock() s.ipv4conn, err = ipv4.NewRawConn(conn) s.Unlock() if err != nil { l.Info(err.Error()) return } if err = s.ipv4conn.SetControlMessage(ipv4.FlagDst, true); err != nil { l.Warning(err.Error()) return } buffer := make([]byte, 1500) var gw net.IP for _, addr := range s.metadata.Network.IP { if addr.Family == "ipv4" && addr.Host == "true" && addr.Gateway == "true" { gw = net.ParseIP(addr.Address) } } iface, err := net.InterfaceByName("tap" + s.name) if err != nil { l.Info(fmt.Sprintf("failed to get iface: %s", err.Error())) return } for { select { case <-s.done: return default: s.ipv4conn.SetReadDeadline(time.Now().Add(time.Second)) hdr, _, _, err := s.ipv4conn.ReadFrom(buffer) if err != nil { switch v := err.(type) { case *net.OpError: if v.Timeout() { continue } case *net.AddrError: if v.Timeout() { continue } case *net.UnknownNetworkError: if v.Timeout() { continue } default: l.Warning(err.Error()) return } } var ip4 layers.IPv4 var udp layers.UDP var dhcp4req layers.DHCPv4 parser := gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, &ip4, &udp, &dhcp4req) decoded := []gopacket.LayerType{} err = parser.DecodeLayers(buffer, &decoded) for _, layerType := range decoded { switch layerType { case layers.LayerTypeDHCPv4: if dhcp4req.Operation == layers.DHCP_MSG_REQ { dhcp4res, err := s.ServeUDPv4(&dhcp4req) if err != nil { l.Warning(err.Error()) continue } if dhcp4res == nil { // ignore empty dhcp packets continue } buf := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{true, true} gopacket.SerializeLayers(buf, opts, &layers.UDP{SrcPort: 67, DstPort: 68}, dhcp4res) wcm := ipv4.ControlMessage{TTL: 255} wcm.Dst = net.IPv4bcast.To4() wcm.Src = gw.To4() wcm.IfIndex = iface.Index err = s.ipv4conn.WriteTo(&ipv4.Header{Len: 20, TOS: hdr.TOS, TotalLen: 20 + int(len(buf.Bytes())), FragOff: 0, TTL: 255, Protocol: int(layers.IPProtocolUDP), Src: gw.To4(), Dst: net.IPv4bcast.To4()}, buf.Bytes(), &wcm) if err != nil { l.Warning(err.Error()) continue } } else { continue } } } } } }