-
Notifications
You must be signed in to change notification settings - Fork 0
Add Stream buffer limit to WriteSCTP configurable via environment var. #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -11,6 +11,7 @@ import ( | |||||
| "io" | ||||||
| "math" | ||||||
| "net" | ||||||
| "os" | ||||||
| "sync" | ||||||
| "sync/atomic" | ||||||
| "time" | ||||||
|
|
@@ -1620,13 +1621,22 @@ func (a *Association) AcceptStream() (*Stream, error) { | |||||
|
|
||||||
| // createStream creates a stream. The caller should hold the lock and check no stream exists for this id. | ||||||
| func (a *Association) createStream(streamIdentifier uint16, accept bool) *Stream { | ||||||
| var bufferLimit uint64 | ||||||
| if limitStr := os.Getenv("SCTP_STREAM_BUFFER_LIMIT"); limitStr != "" { | ||||||
| _, err := fmt.Sscanf(limitStr, "%d", &bufferLimit) | ||||||
| if err != nil || bufferLimit == 0 { | ||||||
|
||||||
| if err != nil || bufferLimit == 0 { | |
| if err != nil { |
Copilot
AI
Dec 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The environment variable is read and parsed on every stream creation, which could impact performance when many streams are created. Consider reading the environment variable once during Association initialization and passing the value to createStream(), or caching it in the Association struct.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -78,6 +78,7 @@ type Stream struct { | |||||||||||||||||||||||||||||||||||||||||||||||
| state StreamState | ||||||||||||||||||||||||||||||||||||||||||||||||
| log logging.LeveledLogger | ||||||||||||||||||||||||||||||||||||||||||||||||
| name string | ||||||||||||||||||||||||||||||||||||||||||||||||
| bufferLimit uint64 | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // StreamIdentifier returns the Stream identifier associated to the stream. | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -269,6 +270,16 @@ func (s *Stream) Write(payload []byte) (n int, err error) { | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // WriteSCTP writes len(payload) bytes from payload to the DTLS connection. | ||||||||||||||||||||||||||||||||||||||||||||||||
| func (s *Stream) WriteSCTP(payload []byte, ppi PayloadProtocolIdentifier) (int, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| // Check buffer limit. | ||||||||||||||||||||||||||||||||||||||||||||||||
| if s.bufferLimit > 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||
| s.lock.RLock() | ||||||||||||||||||||||||||||||||||||||||||||||||
| currentBuffered := s.bufferedAmount | ||||||||||||||||||||||||||||||||||||||||||||||||
| s.lock.RUnlock() | ||||||||||||||||||||||||||||||||||||||||||||||||
| if currentBuffered+uint64(len(payload)) > s.bufferLimit { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return 0, fmt.Errorf("stream buffer limit exceeded: %d bytes", s.bufferLimit) | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+273
to
+280
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Check buffer limit. | |
| if s.bufferLimit > 0 { | |
| s.lock.RLock() | |
| currentBuffered := s.bufferedAmount | |
| s.lock.RUnlock() | |
| if currentBuffered+uint64(len(payload)) > s.bufferLimit { | |
| return 0, fmt.Errorf("stream buffer limit exceeded: %d bytes", s.bufferLimit) | |
| } | |
| // Check and update buffer under a single lock to avoid races. | |
| if s.bufferLimit > 0 { | |
| s.lock.Lock() | |
| prospective := s.bufferedAmount + uint64(len(payload)) | |
| if prospective > s.bufferLimit { | |
| s.lock.Unlock() | |
| return 0, fmt.Errorf("stream buffer limit exceeded: %d bytes", s.bufferLimit) | |
| } | |
| s.bufferedAmount = prospective | |
| s.lock.Unlock() | |
| } else { | |
| // Keep bufferedAmount consistent even when there is no explicit limit. | |
| s.lock.Lock() | |
| s.bufferedAmount += uint64(len(payload)) | |
| s.lock.Unlock() |
Copilot
AI
Dec 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new buffer limit check logic lacks test coverage. Consider adding tests that verify the buffer limit is enforced correctly, including scenarios where writes succeed when under the limit, fail when exceeding the limit, and handle concurrent writes appropriately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using fmt.Sscanf with %d format specifier can parse negative numbers into the uint64 variable, which would result in a very large positive value due to unsigned integer wrapping. Consider using strconv.ParseUint instead, which will return an error for negative values and provide better control over the parsing behavior.