Skip to content

Commit fc697a3

Browse files
marten-seemanngopherbot
authored andcommitted
unix: add ParseOneSocketControlMessage to parse control messages without allocating
Fixes golang/go#54714. Change-Id: If711272937078b6c696756823aa4dfcec358b719 Reviewed-on: https://go-review.googlesource.com/c/sys/+/425917 Reviewed-by: Matt Layher <[email protected]> Reviewed-by: Michael Pratt <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Run-TryBot: Matt Layher <[email protected]>
1 parent 5726498 commit fc697a3

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

unix/sockcmsg_unix.go

+14
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
5252
return msgs, nil
5353
}
5454

55+
// ParseOneSocketControlMessage parses a single socket control message from b, returning the message header,
56+
// message data (a slice of b), and the remainder of b after that single message.
57+
// When there are no remaining messages, len(remainder) == 0.
58+
func ParseOneSocketControlMessage(b []byte) (hdr Cmsghdr, data []byte, remainder []byte, err error) {
59+
h, dbuf, err := socketControlMessageHeaderAndData(b)
60+
if err != nil {
61+
return Cmsghdr{}, nil, nil, err
62+
}
63+
if i := cmsgAlignOf(int(h.Len)); i < len(b) {
64+
remainder = b[i:]
65+
}
66+
return *h, dbuf, remainder, nil
67+
}
68+
5569
func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
5670
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
5771
if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) {

unix/syscall_unix_test.go

+18-1
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ func passFDChild() {
322322
}
323323
}
324324

325-
// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage,
325+
// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, ParseOneSocketControlMessage,
326326
// and ParseUnixRights are able to successfully round-trip lists of file descriptors.
327327
func TestUnixRightsRoundtrip(t *testing.T) {
328328
testCases := [...][][]int{
@@ -350,6 +350,23 @@ func TestUnixRightsRoundtrip(t *testing.T) {
350350
if len(scms) != len(testCase) {
351351
t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms)
352352
}
353+
354+
var c int
355+
for len(b) > 0 {
356+
hdr, data, remainder, err := unix.ParseOneSocketControlMessage(b)
357+
if err != nil {
358+
t.Fatalf("ParseOneSocketControlMessage: %v", err)
359+
}
360+
if scms[c].Header != hdr || !bytes.Equal(scms[c].Data, data) {
361+
t.Fatal("expected SocketControlMessage header and data to match")
362+
}
363+
b = remainder
364+
c++
365+
}
366+
if c != len(scms) {
367+
t.Fatalf("expected %d SocketControlMessages; got %d", len(scms), c)
368+
}
369+
353370
for i, scm := range scms {
354371
gotFds, err := unix.ParseUnixRights(&scm)
355372
if err != nil {

0 commit comments

Comments
 (0)