Step 3: Adding Bells and Whistles

This and other projects in the Code Examples section are published on our website under the name "test_dhcp_lib".

Writing quality code means anticipating things to go wrong and not as planned. Here are some ideas on fortifying your code:

Check the result of dhcp_start

()

This one returns one of the en_dhcp_status_codes() and you should check what's returned! Decide for yourself what to do in each particular case or simply halt the execution if there is an error:

** Tibbo Basic **


...
if dhcp_start(PL_SOCK_INTERFACE_NET)<>DHCP_STATUS_OK then sys.halt 'do the same for the Wi-Fi interface
...

What to do when callback_dhcp_failure() is called

The DHCP client, once started, continues to run indefinitely. Still, at some point your application has to face the simple fact that the DHCP configuration has, indeed, failed, and it is time to do something about it. A set of alternative configuration parameters will come handy at that time. In the code below, net_dhcp_fail_ctr and wln_dhcp_fail_ctr accumulate failures. Notice how dhcp_stop() is called once the count reaches DHCP_FAIL_LIMIT:

** Tibbo Basic **


include "global.tbh"

'--------------------------------------------------------------------
const DHCP_FAIL_LIMIT=1 'max number of DHCP retry "batches"
const ALT_NET_IP="192.168.1.40"
const ALT_NET_GATEWAY_IP="192.168.1.1"
const ALT_NET_NETMASK="255.255.255.0"
const ALT_WLN_IP="192.168.1.41"
const ALT_WLN_GATEWAY_IP="192.168.1.1"
const ALT_WLN_NETMASK="255.255.255.0"

'--------------------------------------------------------------------
#if NET_AVAILABLE
 dim net_dhcp_fail_ctr as byte 'no need to init to 0 (this is automatic for global vars)
#endif

#if WLN_AVAILABLE
 dim wln_dhcp_fail_ctr as byte 'no need to init to 0 (this is automatic for global vars)
#endif

'====================================================================
sub callback_dhcp_ok(renew as no_yes, interface as pl_sock_interfaces, byref ip as string, byref gateway_ip as string, byref netmask as string, lease_time as dword)
 dim f as byte

 #if NET_AVAILABLE
         if interface=PL_SOCK_INTERFACE_NET then
                 if renew=YES and net.ip<>ip then
                         'this is a lease renewal and the DHCP server has issues new IP
                         'it is better to reboot than deal with the implications of the changed IP
                         sys.reboot
                 end if

                 if net.ip<>ip then
                         'no need to close sockets -- this is definitely NOT a renewal an the DHCP lib
                         'has already closed all socket connections on this interface prior to setting
                         'the IP to 0.0.0.0
                         net.ip=ip
                         net.gatewayip=gateway_ip
                         net.netmask=netmask
                         net_dhcp_fail_ctr=0
                 end if
         end if
 #endif

 #if WLN_AVAILABLE
         if interface=PL_SOCK_INTERFACE_WLN then
                 if renew=YES and wln.ip<>ip then
                         'this is a lease renewal and the DHCP server has issues new IP
                         'it is better to reboot than deal with the implications of the changed IP
                         sys.reboot
                 end if

                 if wln.ip<>ip then
                         'no need to close sockets -- this is definitely NOT a renewal an the DHCP lib
                         'has already closed all socket connections on this interface prior to setting
                         'the IP to 0.0.0.0
                         wln.ip=ip
                         wln.gatewayip=gateway_ip
                         wln.netmask=netmask
                         wln_dhcp_fail_ctr=0
                 end if
         end if
 #endif
end sub

'--------------------------------------------------------------------
sub callback_dhcp_failure(interface as pl_sock_interfaces,failure_code as en_dhcp_status_codes)
 #if NET_AVAILABLE
         if interface=PL_SOCK_INTERFACE_NET then
                 if net_dhcp_fail_ctr>=DHCP_FAIL_LIMIT then
                         net.ip=ALT_NET_IP
                         net.gatewayip=ALT_NET_GATEWAY_IP
                         net.netmask=ALT_NET_NETMASK
                         dhcp_stop(PL_SOCK_INTERFACE_NET)
                 else
                         net_dhcp_fail_ctr=net_dhcp_fail_ctr+1
                 end if
         end if
 #endif

 #if WLN_AVAILABLE
         if interface=PL_SOCK_INTERFACE_WLN then
                 if wln_dhcp_fail_ctr>=DHCP_FAIL_LIMIT then
                         wln.ip=ALT_WLN_IP
                         wln.gatewayip=ALT_WLN_GATEWAY_IP
                         wln.netmask=ALT_WLN_NETMASK
                         dhcp_stop(PL_SOCK_INTERFACE_WLN)
                 else
                         wln_dhcp_fail_ctr=wln_dhcp_fail_ctr+1
                 end if
         end if
 #endif
end sub
...

What to do when callback_dhcp_pre_clear_ip() is called

This is very application-specific but we'd say, close your existing TCP connections nicely. Whatever you leave unattended will be brutally squashed by the DHCP library (using the sock.discard hammer), so you may have to tend to your socket connections in advance. Here is an example where you wait for the unsent data to be sent out on a "SOCK_DATA" socket:

** Tibbo Basic **


...
 sock.num=SOCK_DATA
 while sock.txlen>0
         doevents 'optional, allows other things in your app to execute
 wend
...

What to do when callback_dhcp_pre_buffrq() is called

If it is called then you don't have enough buffer pages. OK, don't panic... you can always take some buffers away from somebody. Supposing you have a lot of buffers in the "SOCK_DATA" socket of your project. Sockets are useless without properly configured IP, so you could just temporary use this buffer space:

** Tibbo Basic **


...
'--------------------------------------------------------------------
sub callback_dhcp_pre_buffrq(required_buff_pages as byte)
 sock_release(SOCK_DATA) 'this deallocates buffers
end sub

'--------------------------------------------------------------------
sub callback_dhcp_buff_released()
 sock.num=SOCK_DATA
 sock.rxbuffrq(sys.freebuffpages/2)
 sock.txbuffrq(sys.freebuffpages/2)
 sys.buffalloc
 'proceed with socket setup
end sub
...