Author Topic: fnSendBufTCP  (Read 9046 times)

Offline hervé

  • Jr. Member
  • **
  • Posts: 98
    • View Profile
fnSendBufTCP
« on: January 08, 2010, 09:23:25 AM »
Looking at different topic on the subject, specially http://www.utasker.com/forum/index.php?topic=486.0 which is very interresting, I wanted to use fnSendBufTCP.
But when I put it in my application, I got an exception error inside fnCheckTelnetBinaryTx() function with the simulator, as fnGetTelnetSession()returns a zero-pointer ....

Code: [Select]
extern int fnCheckTelnetBinaryTx(USOCKET Socket)
{
TELNET *TELNET_session = fnGetTelnetSession(Socket);

    if (TELNET_session->usTelnetMode & (TELNET_STUFF_TX_IAC | TELNET_BINARY_MODE)) {
        return 1;
    }
    return 0;
}

So I changed it to :

Code: [Select]
extern int fnCheckTelnetBinaryTx(USOCKET Socket)
{
TELNET *TELNET_session = fnGetTelnetSession(Socket);

    if (TELNET_session == 0)
        return 0;
    if (TELNET_session->usTelnetMode & (TELNET_STUFF_TX_IAC | TELNET_BINARY_MODE)) {
        return 1;
    }
    return 0;
}

Offline hervé

  • Jr. Member
  • **
  • Posts: 98
    • View Profile
fnSendBufTCP problem
« Reply #1 on: January 08, 2010, 10:17:19 AM »
In fact fnSendBufTCP allocate space in memory for the buffer with uMalloc which cannot be freed.
My application is a TCP Client connecting to a TCP server.
Each time the connection got problem, it is closed then opened again :

Code: [Select]
case GIP_OPEN_REQUESTED:
tGIP_TCP_socket = fnTCP_close(GIP_TCP_socket);
fnReleaseTCP_Socket(GIP_TCP_socket);                                    // release existing connection
if ((GIP_TCP_socket = fnGetTCP_Socket(TOS_MINIMISE_DELAY, TCP_NO_TIMEOUT, fnGIPListener)) >= 0) {
ucGIP_RxState = GIP_STATE_OPENED;
} // if
uTaskerStateChange(OWN_TASK, UTASKER_ACTIVATE);
break;

It looks like further fnSendBufTCP calls will consume memory.
Does this means this function could not be used with dynamically created Socket ?

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: fnSendBufTCP
« Reply #2 on: January 08, 2010, 02:00:17 PM »
Hi Hervé

fnGetTelnetSession() can return 0 if called before starting TELNET (using fnStartTelnet()). Or it can also fail if fnStartTelnet() failed due to lack of memory.

The simulator will cause an exception when this happen, which makes it also very obvious that something is not right.

Now there are very probably different opinions on this, but I prefer to let the simulator get an exception so that the root problem (maybe simply that the user didn't realise that fnStartTelnet() must forst be called) rather than protect every point in code so that it can 'silently' fail and then effectively pass the basic problem on to later routines. At the end of the day the problem needs to be solved and I prefer such 'obvious' things to become immediately obvious. In addition it also saves a bit of code because there are less checks which are not necessary once everything is working (configured) correctly anyway.

uMalloc() doesn't allow freeing memory. Its use is as an alternative to declaring static variables but results in about the same situation [there are however advantages since by not activating certain services (eg. using their start calls) they can all be present in code but only the ones being used consume RAM - in some situations it may not be possible to run all services at the same time due to RAM constraints, but they can all be present and just the required one actually started]. malloc() from a library can also be used in parallel but the uTasker demo project and its components don't call it.

fnSendBufTCP() allocates the working TCP buffer space the first time that it is called on the particular socket. After that it already has this space allocated and so doesn't call uMalloc() again.

However this leads to the problem that you are seeing. This is because of the use of fnReleaseTCP_Socket(GIP_TCP_socket); when the connection is closed. This is in fact deleting the socket and all of its contents, as well as the pointer to the allocated TCP buffer. The next socket used will thus try to allocate the working memory again and it will eventually fail due to no more memory.

The solution is not to release the socket - there is no real reason to do this since you know that you will need it again. Generally set GIP_TCP_socket to -1 on initialisation and then only get the socket once with
if (GIP_TCP_socket < 0) fnGetTCP_Socket();

This should solve any problems that you are having.

If you need to re-initialise something else it can still be performed at the same location. See, for example, fnResetTelnetSession() in telnet.c, which is resetting some session information on each close.

On the other hand there is a problem in TELNET with its use of fnStopTelnet(). This also releases the socket and so if it is later started again it may fail due to lack of buffer memory. Normally TELNET is started and never stopped, so this has probably never been experienced (this code originates before the use of buffered TCP was added - there is no problem together with sockets that don't use a buffered TCP).

I will need to look into this a bit more before deciding what is best to do about it...

Regards

Mark






Offline hervé

  • Jr. Member
  • **
  • Posts: 98
    • View Profile
Re: fnSendBufTCP
« Reply #3 on: January 08, 2010, 03:02:29 PM »
Thanks a lot,
I understand that the simulator can cause an exception , which I think is a good thing.

In fact when I call fnSendBufTCP(), it is not on a Telnet Session so I did not call fnStartTelnet() before.
So it is quite normal TELNET_session == 0, no ?

Concerning fnReleaseTCP_Socket() as I told you on the former topic :
http://www.utasker.com/forum/index.php?topic=472.0
I had to use it...if not the TCP Socket is not freed....
And furthermore fnStopTelnet() is using it also.

But I will look closely to find another way.