diff --git a/client.go b/client.go index dfc7e17..510bea2 100644 --- a/client.go +++ b/client.go @@ -2,10 +2,12 @@ package dhcp4client import ( "bytes" + "fmt" "hash/fnv" "math/rand" "net" "sync" + "syscall" "time" "github.com/d2g/dhcp4" @@ -142,13 +144,32 @@ 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) { + start := time.Now() + for { - c.connection.SetReadTimeout(c.timeout) + timeout := c.timeout - time.Since(start) + if timeout < 0 { + 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 } @@ -186,10 +207,20 @@ 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{}, &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 }