From 683b02b06cce0686c75c8703424fbe27ccd83f9c Mon Sep 17 00:00:00 2001 From: Roman Lisagor Date: Fri, 8 Jun 2018 13:25:28 +0200 Subject: [PATCH 1/2] Read timeout accounts for total time to receive relevant packet, not just any packet --- client.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index dfc7e17..7185b06 100644 --- a/client.go +++ b/client.go @@ -6,6 +6,7 @@ import ( "math/rand" "net" "sync" + "syscall" "time" "github.com/d2g/dhcp4" @@ -145,8 +146,15 @@ func (c *Client) SendDiscoverPacket() (dhcp4.Packet, error) { //Retreive Offer... //Wait for the offer for a specific Discovery Packet. func (c *Client) GetOffer(discoverPacket *dhcp4.Packet) (dhcp4.Packet, error) { + start := time.Now() + for { - c.connection.SetReadTimeout(c.timeout) + timeout := c.timeout - time.Since(start) + if timeout < 0 { + return dhcp4.Packet{}, syscall.ETIMEDOUT + } + + c.connection.SetReadTimeout(timeout) readBuffer, source, err := c.connection.ReadFrom() if err != nil { return dhcp4.Packet{}, err @@ -186,8 +194,15 @@ func (c *Client) SendRequest(offerPacket *dhcp4.Packet) (dhcp4.Packet, error) { //Retreive Acknowledgement //Wait for the offer for a specific Request Packet. func (c *Client) GetAcknowledgement(requestPacket *dhcp4.Packet) (dhcp4.Packet, error) { + start := time.Now() + for { - c.connection.SetReadTimeout(c.timeout) + timeout := c.timeout - time.Since(start) + if timeout < 0 { + return dhcp4.Packet{}, syscall.ETIMEDOUT + } + + c.connection.SetReadTimeout(timeout) readBuffer, source, err := c.connection.ReadFrom() if err != nil { return dhcp4.Packet{}, err From 45101b2b7db70316458cd81730558ac4cb963cf1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 8 Jun 2018 13:47:12 +0200 Subject: [PATCH 2/2] Return friendlier errors on timeout --- client.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index 7185b06..510bea2 100644 --- a/client.go +++ b/client.go @@ -2,6 +2,7 @@ package dhcp4client import ( "bytes" + "fmt" "hash/fnv" "math/rand" "net" @@ -143,6 +144,15 @@ func (c *Client) SendDiscoverPacket() (dhcp4.Packet, error) { return discoveryPacket, c.SendPacket(discoveryPacket) } +// TimeoutError records a timeout when waiting for a DHCP packet. +type TimeoutError struct { + Timeout time.Duration +} + +func (te *TimeoutError) Error() string { + return fmt.Sprintf("no DHCP packet received within %v", te.Timeout) +} + //Retreive Offer... //Wait for the offer for a specific Discovery Packet. func (c *Client) GetOffer(discoverPacket *dhcp4.Packet) (dhcp4.Packet, error) { @@ -151,12 +161,15 @@ func (c *Client) GetOffer(discoverPacket *dhcp4.Packet) (dhcp4.Packet, error) { for { timeout := c.timeout - time.Since(start) if timeout < 0 { - return dhcp4.Packet{}, syscall.ETIMEDOUT + return dhcp4.Packet{}, &TimeoutError{Timeout: c.timeout} } c.connection.SetReadTimeout(timeout) readBuffer, source, err := c.connection.ReadFrom() if err != nil { + if errno, ok := err.(syscall.Errno); ok && errno == syscall.EAGAIN { + return dhcp4.Packet{}, &TimeoutError{Timeout: c.timeout} + } return dhcp4.Packet{}, err } @@ -199,12 +212,15 @@ func (c *Client) GetAcknowledgement(requestPacket *dhcp4.Packet) (dhcp4.Packet, for { timeout := c.timeout - time.Since(start) if timeout < 0 { - return dhcp4.Packet{}, syscall.ETIMEDOUT + return dhcp4.Packet{}, &TimeoutError{Timeout: c.timeout} } c.connection.SetReadTimeout(timeout) readBuffer, source, err := c.connection.ReadFrom() if err != nil { + if errno, ok := err.(syscall.Errno); ok && errno == syscall.EAGAIN { + return dhcp4.Packet{}, &TimeoutError{Timeout: c.timeout} + } return dhcp4.Packet{}, err }