Step 3: Adding Bells and Whistles
This section is currently being reworked. We apologize for the inconvenience. If you need immediate assistance, please contact Tibbo Support.
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:
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
...
'--------------------------------------------------------------------
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
...