diff options
author | Sean Karlage <skarlage@fb.com> | 2018-03-09 21:01:18 -0800 |
---|---|---|
committer | insomniac <insomniacslk@users.noreply.github.com> | 2018-03-10 19:40:51 +0000 |
commit | 1ad5e5b04af130aaf5477f746c09688973584d9e (patch) | |
tree | 44faba29db2184a7e8079053336d538df29fcaf0 /dhcpv4/bsdp/client.go | |
parent | f40786cdbd68500988799afb584a4eb007d9d501 (diff) |
Refactor client code, add timeout capabilities
Diffstat (limited to 'dhcpv4/bsdp/client.go')
-rw-r--r-- | dhcpv4/bsdp/client.go | 92 |
1 files changed, 17 insertions, 75 deletions
diff --git a/dhcpv4/bsdp/client.go b/dhcpv4/bsdp/client.go index d2e9c5c..00e5ad5 100644 --- a/dhcpv4/bsdp/client.go +++ b/dhcpv4/bsdp/client.go @@ -3,22 +3,23 @@ package bsdp import ( - "fmt" - "net" - "syscall" + "errors" "github.com/insomniacslk/dhcp/dhcpv4" ) -// Client is a BSDP-specific client suitable for performing BSDP exchanges. -type Client dhcpv4.Client - // Exchange runs a full BSDP exchange (Inform[list], Ack, Inform[select], // Ack). Returns a list of DHCPv4 structures representing the exchange. -func (c *Client) Exchange(ifname string, informList *dhcpv4.DHCPv4) ([]dhcpv4.DHCPv4, error) { +func Exchange(client *dhcpv4.Client, ifname string, informList *dhcpv4.DHCPv4) ([]dhcpv4.DHCPv4, error) { conversation := make([]dhcpv4.DHCPv4, 1) var err error + // Get our file descriptor for the broadcast socket. + fd, err := dhcpv4.MakeBroadcastSocket(ifname) + if err != nil { + return conversation, err + } + // INFORM[LIST] if informList == nil { informList, err = NewInformListForInterface(ifname, dhcpv4.ClientPort) @@ -28,92 +29,33 @@ func (c *Client) Exchange(ifname string, informList *dhcpv4.DHCPv4) ([]dhcpv4.DH } conversation[0] = *informList - // TODO: deduplicate with code in dhcpv4/client.go - fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW) - if err != nil { - return conversation, err - } - err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) - if err != nil { - return conversation, err - } - err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1) - if err != nil { - return conversation, err - } - err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) - if err != nil { - return conversation, err - } - err = dhcpv4.BindToInterface(fd, ifname) + // ACK[LIST] + ackForList, err := dhcpv4.SendReceive(client, fd, informList) if err != nil { return conversation, err } - - bcast := [4]byte{} - copy(bcast[:], net.IPv4bcast) - daddr := syscall.SockaddrInet4{Port: dhcpv4.ClientPort, Addr: bcast} - packet, err := dhcpv4.MakeRawBroadcastPacket(informList.ToBytes()) - if err != nil { - return conversation, err - } - err = syscall.Sendto(fd, packet, 0, &daddr) - if err != nil { - return conversation, err - } - - // ACK 1 - conn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: dhcpv4.ClientPort}) - if err != nil { - return conversation, err - } - defer conn.Close() - - buf := make([]byte, dhcpv4.MaxUDPReceivedPacketSize) - oobdata := []byte{} // ignoring oob data - n, _, _, _, err := conn.ReadMsgUDP(buf, oobdata) - ack1, err := dhcpv4.FromBytes(buf[:n]) - if err != nil { - return conversation, err - } - // TODO match the packet content - // TODO check that the peer address matches the declared server IP and port - conversation = append(conversation, *ack1) + conversation = append(conversation, *ackForList) // Parse boot images sent back by server - bootImages, err := ParseBootImageListFromAck(*ack1) + bootImages, err := ParseBootImageListFromAck(*ackForList) if err != nil { return conversation, err } if len(bootImages) == 0 { - return conversation, fmt.Errorf("Got no BootImages from server") + return conversation, errors.New("got no BootImages from server") } // INFORM[SELECT] - informSelect, err := InformSelectForAck(*ack1, dhcpv4.ClientPort, bootImages[0]) + informSelect, err := InformSelectForAck(*ackForList, dhcpv4.ClientPort, bootImages[0]) if err != nil { return conversation, err } conversation = append(conversation, *informSelect) - packet, err = dhcpv4.MakeRawBroadcastPacket(informSelect.ToBytes()) - if err != nil { - return conversation, err - } - err = syscall.Sendto(fd, packet, 0, &daddr) - if err != nil { - return conversation, err - } - // ACK 2 - buf = make([]byte, dhcpv4.MaxUDPReceivedPacketSize) - n, _, _, _, err = conn.ReadMsgUDP(buf, oobdata) - ack2, err := dhcpv4.FromBytes(buf[:n]) + // ACK[SELECT] + ackForSelect, err := dhcpv4.SendReceive(client, fd, informSelect) if err != nil { return conversation, err } - // TODO match the packet content - // TODO check that the peer address matches the declared server IP and port - conversation = append(conversation, *ack2) - - return conversation, nil + return append(conversation, *ackForSelect), nil } |