lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lwip-users] Handling ERR_MEM from tcp_close()


From: Longin Kandinsky
Subject: [lwip-users] Handling ERR_MEM from tcp_close()
Date: Wed, 16 Nov 2016 12:39:58 +0100

Hello,

I'm developing specific TCP server using RAW LwiP 1.41 and I have some
doubts about understanding closing connection.

My TCP server should have only one active client per bound port. If
new client comes (tcp_accept callback with new pcb) the old one should
be shut down.

Here is the part of code (I've cut off some stuff with asserts, debug
printing etc...):

/*******************************************************************************/
enum eServer_state
{
    eServer_state_None = 0,
    eServer_state_Listening,
    eServer_state_Established,
    eServer_state_Closing
};

/* This struct will be passed through arg in callbaks */
struct sTcpServer {
    enum eServer_state e_state;
    struct tcp_pcb *ps_pcb;
    ...
};

static err_t TcpServer_callback_accept(void *arg, struct tcp_pcb
*ps_newPcb, err_t err)
{
    err_t d_err;

    /* Compiler optimization */
    LWIP_UNUSED_ARG(err);
    /* As arg is passed sTcpServer struct from listening pcb. This
user struct is static */
    struct sTcpServer *ps_tcpserver = (struct sTcpServer*) arg;

    if (ps_tcpserver->e_state == eServer_state_Listening) {
        /* No active connection */
        TcpServer_establishConnection(ps_tcpserver, ps_newPcb);
        d_err = ERR_OK;
    } else if (ps_tcpserver->e_state == eServer_state_Established) {
        /* We can have only one active tcp connection */
        /* Shutdown the old one */
        TcpServer_closeConnection(ps_tcpserver);
        /* Establish the new one */
        TcpServer_establishConnection(ps_tcpserver, ps_newPcb);
        d_err = ERR_OK;
    } else {
        tcp_abort(ps_newPcb);
        d_err = ERR_ABRT;
    }
    return d_err;
}

static void TcpServer_establishConnection(struct sTcpServer *ps_tcpserver,
        struct tcp_pcb * ps_newPcb)
{
    ps_tcpserver->e_state = eServer_state_Established;
    ps_tcpserver->ps_pcb = ps_newPcb;
    tcp_arg(ps_tcpserver->ps_pcb, ps_tcpserver);
    tcp_recv(ps_tcpserver->ps_pcb, TcpServer_callback_recv);
    tcp_err(ps_tcpserver->ps_pcb, TcpServer_callback_error);
    tcp_poll(ps_tcpserver->ps_pcb, TcpServer_callback_poll, 2);
}

static void TcpServer_closeConnection(struct sTcpServer *ps_tcpserver)
 {
    err_t d_err;

    /* removing callbacks */
    tcp_arg(ps_tcpserver->ps_pcb, NULL);
    tcp_sent(ps_tcpserver->ps_pcb, NULL);
    tcp_recv(ps_tcpserver->ps_pcb, NULL);
    tcp_err(ps_tcpserver->ps_pcb, NULL);
    tcp_poll(ps_tcpserver->ps_pcb, NULL, 0);

    d_err = tcp_close(ps_tcpserver->ps_pcb);

    /* Not enough memory for close operation, we will
     * try later in ack/poll callbacks */
    if (d_err != ERR_OK) {
        /* Set callbacks again?*/
        /* Possible memory leak when server accepts next client*/
        assert(0);

        tcp_arg(ps_tcpserver->ps_pcb, ps_tcpserver);
        tcp_err(ps_tcpserver->ps_pcb, TcpServer_callback_error);
        tcp_recv(ps_tcpserver->ps_pcb, TcpServer_callback_recv);
        tcp_sent(ps_tcpserver->ps_pcb, TcpServer_callback_sent);
        tcp_poll(ps_tcpserver->ps_pcb, TcpServer_callback_poll, 2);
        ps_tcpserver->e_state = eServer_state_Closing;
    } else {
        ps_tcpserver->ps_pcb = NULL;
        ps_tcpserver->e_state = eServer_state_Listening;
    }
}

/*******************************************************************************/

Everything works how I want - there is always one active client
connected to specific port.
But what to do if tcp_close returns ERR_MEM?

This is from documentation:
"Closes the connection. The function may return ERR_MEM if no memory
  was available for closing the connection. If so, the application
  should wait and try again either by using the acknowledgment
  callback or the polling functionality. If the close succeeds, the
  function returns ERR_OK.

  The pcb is deallocated by the TCP code after a call to tcp_close(). "

If tcp_close returns ERR_MEM, the pcb is still allocated? So I should
set callbacks again  - mainly tcp_poll and tcp_sent where I will try
to call my TcpServer_closeConnection if there is
"eServer_state_Closing" state?

I was thinking about using just tcp_abort(). Problem is I'm unsure
about returning ERR_ABRT in tcp_accept callback, because there is the
newly allocated pcb with a new connection and I want to abort "old"
pcb...


something like this:
/********************************************************************************/
static err_t TcpServer_callback_accept(void *arg, struct tcp_pcb
*ps_newPcb, err_t err)
{
    err_t d_err;

    /* Compiler optimization */
    LWIP_UNUSED_ARG(err);

    struct sTcpServer *ps_tcpserver = (struct sTcpServer*) arg;

    if (ps_tcpserver->e_state == eServer_state_Listening) {
        /* No active connection */
        TcpServer_establishConnection(ps_tcpserver, ps_newPcb);
        d_err = ERR_OK;
    } else if (ps_tcpserver->e_state == eServer_state_Established) {
        /* We can have only one active tcp connection */
        /* Shutdown the old one */
        tcp_abort(ps_tcpserver->ps_pcb);
        /* Establish the new one */
        TcpServer_establishConnection(ps_tcpserver, ps_newPcb);
        d_err = ERR_ABRT; //??????????????????????????????????????
    } else {
        tcp_abort(ps_newPcb);
        d_err = ERR_ABRT;
    }
    return d_err;
}
/********************************************************************************/


What is the right way?

Thanks,
Longin



reply via email to

[Prev in Thread] Current Thread [Next in Thread]