Step 3: Adding Bells and Whistles

Top  Previous  Next

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:

 

 

...

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:

 

device.tbs:

 

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:

 

 

...

 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:

 

 

...

'--------------------------------------------------------------------

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

...