forked from rosa/hakurei
internal/netlink: make full response available
The previous API makes it impossible to retrieve remaining messages in the current iteration. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -143,8 +143,45 @@ type Complete struct{}
|
|||||||
// Error returns a hardcoded string that should never be displayed to the user.
|
// Error returns a hardcoded string that should never be displayed to the user.
|
||||||
func (Complete) Error() string { return "returning from roundtrip" }
|
func (Complete) Error() string { return "returning from roundtrip" }
|
||||||
|
|
||||||
|
// HandlerFunc handles [syscall.NetlinkMessage] and returns a non-nil error to
|
||||||
|
// discontinue the receiving of more messages.
|
||||||
|
type HandlerFunc func(resp []syscall.NetlinkMessage) error
|
||||||
|
|
||||||
|
// receive receives from a socket with specified flags until a non-nil error is
|
||||||
|
// returned by f. An error of type [Complete] is returned as nil.
|
||||||
|
func (c *conn) receive(f HandlerFunc, flags int) error {
|
||||||
|
for {
|
||||||
|
buf := c.buf
|
||||||
|
if n, _, err := syscall.Recvfrom(c.fd, buf, flags); err != nil {
|
||||||
|
return os.NewSyscallError("recvfrom", err)
|
||||||
|
} else if n < syscall.NLMSG_HDRLEN {
|
||||||
|
return syscall.EBADE
|
||||||
|
} else {
|
||||||
|
buf = buf[:n]
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := syscall.ParseNetlinkMessage(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range resp {
|
||||||
|
header := &resp[i].Header
|
||||||
|
if header.Seq != c.seq || header.Pid != getpid() {
|
||||||
|
return &InconsistentError{*header, c.seq, getpid()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = f(resp); err != nil {
|
||||||
|
if err == (Complete{}) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Roundtrip sends the pending message and handles the reply.
|
// Roundtrip sends the pending message and handles the reply.
|
||||||
func (c *conn) Roundtrip(f func(msg *syscall.NetlinkMessage) error) error {
|
func (c *conn) Roundtrip(f HandlerFunc) error {
|
||||||
if c.buf == nil {
|
if c.buf == nil {
|
||||||
return syscall.EINVAL
|
return syscall.EINVAL
|
||||||
}
|
}
|
||||||
@@ -158,38 +195,3 @@ func (c *conn) Roundtrip(f func(msg *syscall.NetlinkMessage) error) error {
|
|||||||
|
|
||||||
return c.receive(f, 0)
|
return c.receive(f, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// receive receives from a socket with specified flags until a non-nil error is
|
|
||||||
// returned by f. An error of type [Complete] is returned as nil.
|
|
||||||
func (c *conn) receive(
|
|
||||||
f func(msg *syscall.NetlinkMessage) error,
|
|
||||||
flags int,
|
|
||||||
) error {
|
|
||||||
for {
|
|
||||||
buf := c.buf
|
|
||||||
if n, _, err := syscall.Recvfrom(c.fd, buf, flags); err != nil {
|
|
||||||
return os.NewSyscallError("recvfrom", err)
|
|
||||||
} else if n < syscall.NLMSG_HDRLEN {
|
|
||||||
return syscall.EBADE
|
|
||||||
} else {
|
|
||||||
buf = buf[:n]
|
|
||||||
}
|
|
||||||
|
|
||||||
msgs, err := syscall.ParseNetlinkMessage(buf)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, msg := range msgs {
|
|
||||||
if msg.Header.Seq != c.seq || msg.Header.Pid != getpid() {
|
|
||||||
return &InconsistentError{msg.Header, c.seq, getpid()}
|
|
||||||
}
|
|
||||||
if err = f(&msg); err != nil {
|
|
||||||
if err == (Complete{}) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -18,23 +18,23 @@ func DialRoute() (*RouteConn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// rtnlConsume consumes a message from rtnetlink.
|
// rtnlConsume consumes a message from rtnetlink.
|
||||||
func rtnlConsume(msg *syscall.NetlinkMessage) error {
|
func rtnlConsume(resp []syscall.NetlinkMessage) error {
|
||||||
switch msg.Header.Type {
|
for i := range resp {
|
||||||
case syscall.NLMSG_DONE:
|
switch resp[i].Header.Type {
|
||||||
return Complete{}
|
case syscall.NLMSG_DONE:
|
||||||
|
return Complete{}
|
||||||
|
|
||||||
case syscall.NLMSG_ERROR:
|
case syscall.NLMSG_ERROR:
|
||||||
if e := As[syscall.NlMsgerr](msg.Data); e != nil {
|
if e := As[syscall.NlMsgerr](resp[i].Data); e != nil {
|
||||||
if e.Error == 0 {
|
if e.Error == 0 {
|
||||||
return Complete{}
|
return Complete{}
|
||||||
|
}
|
||||||
|
return syscall.Errno(-e.Error)
|
||||||
}
|
}
|
||||||
return syscall.Errno(-e.Error)
|
return syscall.EBADE
|
||||||
}
|
}
|
||||||
return syscall.EBADE
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InAddr is equivalent to struct in_addr.
|
// InAddr is equivalent to struct in_addr.
|
||||||
|
|||||||
Reference in New Issue
Block a user