I already made a couple of modifications to ColdFire Lite in the past weeks that I consider improvements, and now I have made a couple more!
My current project (which is based on AN3518 by Eric Gregori) uses an HTTP client to download information from the internet and display it on an LCD screen.
All of this works fine, unless the HTTP server is off line or the IP address cannot be resolved by the CF Lite DNS client. If this happens, my application hangs in a loop somewhere in the CF Lite operating system.
So yesterday I took the time to figure out what was going on and what I could do to fix this. And I have found 2 fixes...
The first modification is done in the file dnsclnt.c. It appeared that the dns client always returns an IP addres, no matter wether the address could be resolved or not. Only, the returned IP address appears to be some memory pointer instead of an actual IP address when the URL is false.
I solved this by commenting out the line marked in red below and adding the green line:
static int dnc_lookup(char * name, struct dns_querys ** cacheentry) { struct dns_querys * dns_entry; int alias; /* look through the cache for the passed name */ for(dns_entry = dns_qs; dns_entry; dns_entry = dns_entry->next) { if(strcmp(dns_entry->dns_names, name) == 0) break; if((dns_entry->he.h_name) && (strcmp(dns_entry->he.h_name, name) == 0)) { break; } for(alias = 0; alias < MAXDNSALIAS; alias++) { if((dns_entry->alist[alias]) && (strcmp(dns_entry->alist[alias], name) == 0)) goto found_name; } } found_name: /* if not found, return error */ if (dns_entry == NULL) return ENP_PARAM; /* else, prepare to return entry index */ if (cacheentry != NULL) *cacheentry = dns_entry; /* if completed request, return success */ //if (dns_entry->rcode != DNSRC_UNSET) if (dns_entry->rcode == DNSRC_OK) /* MvdH : modification */ return 0; /* incomplete request -- return pending or timed-out status */ if (dns_entry->tries < dns_trys) /* still trying? */ return ENP_SEND_PENDING; else return ENP_TIMEOUT; }
(code sample based on CF Lite V3.2)
On to the second modification.
The second modification is located in the file tcpapi.c. The function m_connect uses a 'while' loop to give the system time to connect to the server. But it will NEVER exit this loop when the system cannot connect to that server. So I commented out that loop (red) and replaced it by another one (green), with a built-in time out of 30 seconds.This time out does require the use of an additional variable tmo to keep track of time.
int m_connect(M_SOCK so, struct sockaddr_in * sin, M_CALLBACK(name)) { struct tcpcb * tp; int e = 0; unsigned long tmo; : : : : if(so->state & SS_NBIO) /* if socket non-blocking, return now */ { /* Socket may have blocked to connect in tcp_output() and then been * set to non-blocking in connect callback - e.g., FTP server does this. */ if(so->state & SS_ISCONNECTED) goto rtn; /* fall to here if it's really in progress */ e = so->error = EINPROGRESS; goto rtn; } ///////////////////////////////////////////////////////////////////////////////////////////////////// // MvdH : the original version locked the system up when the destination // doesn't exist // Modified this to make the connection time out tmo = cticks + (30 * TPS); do { if (cticks > tmo) break; tk_yield(); } while (so->state & SS_ISCONNECTING); ///////////////////////////////////////////////////////////////////////////////////////////////////// /* while(so->state & SS_ISCONNECTING) { tcp_sleep(so); //FSL give time to allow connection to complete } */ if(so->state & SS_ISCONNECTED) e = 0; else // e = so->error; e = so->error = ETIMEDOUT; rtn: UNLOCK_NET_RESOURCE(NET_RESID); return e; }
(code sample based on CF Lite V3.2)
So far everything seems to work fine with these modifications. I have tested it with some false URLs and IP addresses. The false IP address connect attempt times out after 30 seconds; the false URL takes a bit more time but it does time out.
I hope this helps...
- Marc
Regarding the tmo stuff, the way you are using cticks and tmo does not handle wrap around properly. The key point to remember is that there must be a modulo subtraction in the test:
unsigned long start_time;
...
start_time = cticks;
...
if (cticks - start_time > 30 * TPS) /* 30 seconds have elapsed, even if cticks wrapped around. */
Also, access to cticks should be volatile (I think one of the coldfire lite updates got that).
Yes, I realize 4 billion cticks is a long time, and similar cticks-related calculations are botched throughout coldfire lite, but the cost to do this right is essentially zero. In my stuff I use one of the 32 bit DMA timers as a free-running microsecond counter, which wraps around every 4295 seconds.
Thanks for notifying me!
In fact, I did realize that, but I didn't care about it. Silly me, trying to improve things and ignoring this... But you are right, there's more of that kind of stuff in CF Lite, I actually copied it from another piece of CF Lite code!
Could you explain to me the "volatile" thing? This is one of the things in the C language that I don't understand what they do...
Marc VDH wrote:
Could you explain to me the "volatile" thing? This is one of the things in the C language that I don't understand what they do...
The C FAQ, 18.1.7 Type Qualifiers, has a good paragraph on volatile:
http://c-faq.com/~scs/cclass/int/sx4ga.html
bkatt wrote:
The C FAQ, 18.1.7 Type Qualifiers, has a good paragraph on volatile:
http://c-faq.com/~scs/cclass/int/sx4ga.html
Very good information, thanks!
Forgot to mark a couple of lines in the tcpapi.c code:
Near the end of the source, another line is commented out (red) and replaced by (green).
// e = so->error; e = so->error = ETIMEDOUT;
Marc,
Very good info. I'm also using the AN3518 code to do some remote client work. I periodically do wget to send some postdata and get command info. Works very nicely behind firewalls and such becuase it is all just standard HTTP on port 80.
I did run into some difficulties with TCP source port numbering. Seems some cable modems block port 1080 and and Coldfire lite sequences through this. Take a look at the thread a few days back regarding the 5223X RNG.
Dave
That information you give there is very interesting also. I will apply those changes in my program.
Thanks!
Marc:
You may want to submit a service request on your changes, flagging them as a feature request. Any improvements to the code are welcome, and if they are integrated into a future release, everyone else benefits. Thanks for your contributions.
---Tom
Hello Tom,
I will do that.
I have checked the service request page but I cannot find a "feature request" option.
Can you point me there?
- Marc
Marc:
Glad to help. OK, on the first page of the SR entry process, choose Technical Request as the Category, and CodeWarrior as the Topic. Click Next. On the second page, enter the relevant information as to the platform ColdFire Lite executes on. You will have to enter CodeWarrior for ColdFire for the product. For the Root Cause entry, pick Feature Request. Then fill out the rest of the form. My only concern, upon closer study of the form, is that this request might be too CodeWarrior-oriented, rather than point up fixes for a support package. In that case, I would just go with the standard service request, and report the enhancements along with the fixes. Your choice. HTH.
---Tom
OK, thanks. I will put everything I have done sofar in a Word document and then send it to Freescale.
- Marc