From cf1e0741373f30a8d8c8642cdf992eb318b01a2d Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Tue, 12 Aug 2025 12:45:06 +0200 Subject: [PATCH] restore Windows compatibility (#860) (#861) --- client_udp_listener.go | 52 ++++++------------- .../{multi_conn.go => multi_conn_other.go} | 0 .../{single_conn.go => single_conn_other.go} | 0 pkg/readbuffer/read_buffer.go | 13 +++++ pkg/readbuffer/read_buffer_lin.go | 31 +++++++++++ pkg/readbuffer/read_buffer_other.go | 10 ++++ pkg/readbuffer/read_buffer_win.go | 29 +++++++++++ server_udp_listener.go | 16 +++++- 8 files changed, 113 insertions(+), 38 deletions(-) rename pkg/multicast/{multi_conn.go => multi_conn_other.go} (100%) rename pkg/multicast/{single_conn.go => single_conn_other.go} (100%) create mode 100644 pkg/readbuffer/read_buffer.go create mode 100644 pkg/readbuffer/read_buffer_lin.go create mode 100644 pkg/readbuffer/read_buffer_other.go create mode 100644 pkg/readbuffer/read_buffer_win.go diff --git a/client_udp_listener.go b/client_udp_listener.go index c5faf19c..0233a891 100644 --- a/client_udp_listener.go +++ b/client_udp_listener.go @@ -10,6 +10,7 @@ import ( "time" "github.com/bluenviron/gortsplib/v4/pkg/multicast" + "github.com/bluenviron/gortsplib/v4/pkg/readbuffer" ) func int64Ptr(v int64) *int64 { @@ -28,42 +29,7 @@ func randInRange(maxVal int) (int, error) { type packetConn interface { net.PacketConn SyscallConn() (syscall.RawConn, error) -} - -func setAndVerifyReadBufferSize(pc packetConn, v int) error { - rawConn, err := pc.SyscallConn() - if err != nil { - panic(err) - } - - var err2 error - - err = rawConn.Control(func(fd uintptr) { - err2 = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, v) - if err2 != nil { - return - } - - var v2 int - v2, err2 = syscall.GetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF) - if err2 != nil { - return - } - - if v2 != (v * 2) { - err2 = fmt.Errorf("unable to set read buffer size to %v - check that net.core.rmem_max is greater than %v", v, v) - return - } - }) - if err != nil { - return err - } - - if err2 != nil { - return err2 - } - - return nil + SetReadBuffer(bytes int) error } type clientUDPListener struct { @@ -100,11 +66,23 @@ func (u *clientUDPListener) initialize() error { } if u.c.UDPReadBufferSize != 0 { - err := setAndVerifyReadBufferSize(u.pc, u.c.UDPReadBufferSize) + err := u.pc.SetReadBuffer(u.c.UDPReadBufferSize) if err != nil { u.pc.Close() return err } + + v, err := readbuffer.ReadBuffer(u.pc) + if err != nil { + u.pc.Close() + return err + } + + if v != u.c.UDPReadBufferSize { + u.pc.Close() + return fmt.Errorf("unable to set read buffer size to %v, check that the operating system allows that", + u.c.UDPReadBufferSize) + } } u.lastPacketTime = int64Ptr(0) diff --git a/pkg/multicast/multi_conn.go b/pkg/multicast/multi_conn_other.go similarity index 100% rename from pkg/multicast/multi_conn.go rename to pkg/multicast/multi_conn_other.go diff --git a/pkg/multicast/single_conn.go b/pkg/multicast/single_conn_other.go similarity index 100% rename from pkg/multicast/single_conn.go rename to pkg/multicast/single_conn_other.go diff --git a/pkg/readbuffer/read_buffer.go b/pkg/readbuffer/read_buffer.go new file mode 100644 index 00000000..ea25ac21 --- /dev/null +++ b/pkg/readbuffer/read_buffer.go @@ -0,0 +1,13 @@ +// Package readbuffer contains a function to get the read buffer size of a socket. +package readbuffer + +import ( + "net" + "syscall" +) + +// PacketConn is a packet connection. +type PacketConn interface { + net.PacketConn + SyscallConn() (syscall.RawConn, error) +} diff --git a/pkg/readbuffer/read_buffer_lin.go b/pkg/readbuffer/read_buffer_lin.go new file mode 100644 index 00000000..f1c83634 --- /dev/null +++ b/pkg/readbuffer/read_buffer_lin.go @@ -0,0 +1,31 @@ +//go:build linux + +package readbuffer + +import ( + "syscall" +) + +// ReadBuffer returns the read buffer size. +func ReadBuffer(pc PacketConn) (int, error) { + rawConn, err := pc.SyscallConn() + if err != nil { + panic(err) + } + + var v int + var err2 error + + err = rawConn.Control(func(fd uintptr) { + v, err2 = syscall.GetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF) + }) + if err != nil { + return 0, err + } + + if err2 != nil { + return 0, err2 + } + + return v / 2, nil +} diff --git a/pkg/readbuffer/read_buffer_other.go b/pkg/readbuffer/read_buffer_other.go new file mode 100644 index 00000000..cc699373 --- /dev/null +++ b/pkg/readbuffer/read_buffer_other.go @@ -0,0 +1,10 @@ +//go:build !linux && !windows + +package readbuffer + +import "fmt" + +// ReadBuffer returns the read buffer size. +func ReadBuffer(pc PacketConn) (int, error) { + return 0, fmt.Errorf("read buffer size is unimplemented on the current operating system") +} diff --git a/pkg/readbuffer/read_buffer_win.go b/pkg/readbuffer/read_buffer_win.go new file mode 100644 index 00000000..9199e9e6 --- /dev/null +++ b/pkg/readbuffer/read_buffer_win.go @@ -0,0 +1,29 @@ +//go:build windows + +package readbuffer + +import "syscall" + +// ReadBuffer returns the read buffer size. +func ReadBuffer(pc PacketConn) (int, error) { + rawConn, err := pc.SyscallConn() + if err != nil { + panic(err) + } + + var v int + var err2 error + + err = rawConn.Control(func(fd uintptr) { + v, err2 = syscall.GetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF) + }) + if err != nil { + return 0, err + } + + if err2 != nil { + return 0, err2 + } + + return v, nil +} diff --git a/server_udp_listener.go b/server_udp_listener.go index b26b2e1d..3aeb5855 100644 --- a/server_udp_listener.go +++ b/server_udp_listener.go @@ -1,12 +1,14 @@ package gortsplib import ( + "fmt" "net" "strconv" "sync" "time" "github.com/bluenviron/gortsplib/v4/pkg/multicast" + "github.com/bluenviron/gortsplib/v4/pkg/readbuffer" ) type clientAddr struct { @@ -99,11 +101,23 @@ func (u *serverUDPListener) initialize() error { } if u.readBufferSize != 0 { - err := setAndVerifyReadBufferSize(u.pc, u.readBufferSize) + err := u.pc.SetReadBuffer(u.readBufferSize) if err != nil { u.pc.Close() return err } + + v, err := readbuffer.ReadBuffer(u.pc) + if err != nil { + u.pc.Close() + return err + } + + if v != u.readBufferSize { + u.pc.Close() + return fmt.Errorf("unable to set read buffer size to %v, check that the operating system allows that", + u.readBufferSize) + } } u.clients = make(map[clientAddr]readFunc)