We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hi all,
I am implementing a web server using the RL TCP/IP stack. I'm using a web server from Allegro (RomPager), as opposed to the Keil HTTP server, because I required SSL/TSL.
I've got to the stage where the web server works through the Keil TCP/IP stack, and even SSL works.
When the web server wants to close a connection that exists over a socket, I make use of the tcp_close() function. From reading the documentation and from reading other posts and FAQs from this site, I understand fully that the procedure is as follows:
1. Call tcp_close(). It should return __TRUE.
2. Allow time for the listener socket callback function to be called, with the value TCP_EVT_CLOSE.
3. Then, ensure the socket has definitely finished closing by calling tcp_get_state, and ensuring the result is either TCP_STATE_CLOSED or TCP_STATE_LISTEN.
Here's the problem: If the browser is Internet Explorer 7, a call to tcp_close() NEVER results in a TCP_EVT_CLOSE event at the callback function. If my memory serves me right, a call to tcp_get_state always results in TCP_STATE_FINW2. After a few seconds though (maybe 10 or 20 seconds), Internet Explorer 7 seems to abort the connection. Once IE7 has aborted the connection, then the socket definitely does return to TCP_STATE_LISTEN.
If I use Firefox, the socket DOES close properly. I call tcp_close(), and the callback function is quickly called with a TCP_EVT_CLOSE event, and my socket becomes a listener again immediately.
I am new to network programming and I have not yet used a network sniffer to try to see what's going on. But that's what I'm going to try to do next. If anyone has any suggestions in the meantime about this, I would be extremely grateful for suggestions.
Regards
Trevor
I suspect that you're not familiar with the Keil TCPNET TCP/IP stack.
There is no such function as setsocketopt() with the Keil TCP/IP stack, and there is no option equivalent to SO_REUSEADDR. The Keil stack has a very simple interface and it doesn't provide WinSock / BSD style functions.
There are some timeout options in the keil Net_Config.c file. The timeout options that I can find that are applicable to TCP are as follows:
---
TCP_MAXRETRY :- How many times TCP module will try to retransmit data before giving up. Default is 5.
TCP_RETRYTOUT :- If data frame not acknowledged within this time frame, TCP module will try to resend data again. Default 4 seconds.
TCP_DEFTOUT :- Default TCP Socket Keep Alive timeout. When it expires with no TCP data frame send, TCP Connection is closed. Default 120 seconds.
TCP_INIT_RETRY_TOUT :- TCP initial Retransmit period in seconds. Default 1 second.
TCP_SYN_RETRY_TOUT :- TCP SYN frame retransmit period in seconds. Default 2 seconds.
TCP_CONRETRY :- Number of retries to establish a connection. Default 7.
I don't think that altering any of those configuration options would resolve this problem. Again, the only option I can see is to abort the socket if it 'hangs' in a time wait state for too long.
Trev
Trevor, Indeed, I still haven't started working with Keil's TCP/IP framework (but I will soon) so I don't know the details. It is indeed unfortunate that vital RFCs are not fully implemented, but after all, they are still only "recommendations"...
Thanks for your thoughts and ideas though - it's much appreciated. It would be nice to use a 'nicer' solution if one exists.
The Keil stack is a strange beast really and took me a bit of time to interface to the web server I'm using, which expects to see a BSD-like interface. Furthermore it's the first TCP/IP work I've ever done and I've not actually done any WinSock programming at all, although I'm familiar with the basics.
For starters I had to code a simple memory pool to store receive packets as they come in. The Keil stack just returns received packets to a callback function (so receive packets must be dealt with there and then; Keil have implemented a flow control option to make things easier). I then provide the buffers to the server through a 'recv()'-style wrapper function, and free up the buffers when the server has transmitted its reply.
The other concept that I had to get my head around was how listener sockets are used. With a conventional stack, I believe that you only ever need to create one listener socket, and then calling accept() will automatically assign you a new socket for each new connection. But with the Keil stack, a listener socket becomes the socket over which the connection is made. So you have to set up as many listener sockets at the start for as many connections as you'll ever want.
Trevor,
Thanks for your interesting post.
You wrote:
The Keil stack just returns received packets to a callback function (so receive packets must be dealt with there and then;...
Well, I can only guess that Keil did that in order to save RAM footprint while preventing the need to re-compile the stack if buffer sizes change. But I have no idea why they deviated from the common socket interface.