Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

websocket fails in simple app after websocket is created 4 times. #2

Open
Daniel-Trevitz opened this issue Nov 30, 2015 · 2 comments
Open

Comments

@Daniel-Trevitz
Copy link

I am working on an application that uses esphttpd to provide a single webpage and uses websocket for life updating. After four connections a websocket would no longer be created.

@Daniel-Trevitz
Copy link
Author

I'm not super motivated to find the right way to do this... My solution is as follows:

httpd.c -- perform a complete cleanup when retiring a connection
//Retires a connection for re-use
static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn)
{
if (conn->post->buff != NULL)
os_free(conn->post->buff);

if(conn->cleanup)
    conn->cleanup(conn);

//Find the matching conndata in pool
int i;
for (i = 0; i < MAX_CONN; i++) 
{
    if (&connData[i] == conn) 
    {
        break;
    }
}

if(i < 0 || i >= MAX_CONN)
{
    os_printf("Failed to find the connection to clear\n");
}

os_memset(&connPrivData[i], 0, sizeof(HttpdPriv));
os_memset(&connData[i],     0, sizeof(HttpdConnData));
os_memset(&connPostData[i], 0, sizeof(HttpdPostData));

}

httpd.h -- Add the cleanup callback
typedef void (* cgiCleanupCallback)(HttpdConnData connData);
typedef int (
cgiSendCallback)(HttpdConnData connData);
typedef int (
cgiRecvHandler)(HttpdConnData *connData, char *data, int len);

//A struct describing a http connection. This gets passed to cgi functions.
struct HttpdConnData {
struct espconn *conn;
char requestType;
char *url;
char *getArgs;
const void *cgiArg;
void *cgiData;
void *cgiPrivData; // Used for streaming handlers storing state between requests
char *hostName;
HttpdPriv *priv;
cgiCleanupCallback cleanup;
cgiSendCallback cgi;
cgiRecvHandler recvHdl;
HttpdPostData *post;
int remote_port;
uint8 remote_ip[4];
};

cgiwebsocket.c --- Add the cleanup function and set the callback.

static void ws_cleanup()
{
llStart = NULL;
}

--- Within cgiWebsocket ---
//Set data receive handler
connData->recvHdl = cgiWebSocketRecv;
// Set the cleanup handler
connData->cleanup = ws_cleanup;

Because llStart points to data that we clean the fatal call to the websocket causes some kind of crash instead of re-initializing llStart.

If anything like that exists in the other cgi's it probabbly needs a cleanup function as well.

@Charlie-Chan
Copy link

Thanks for this, I was suffering with a similar problem - I'd found that just refreshing my browser would reliably kill the webSocket -
1/ browse to webSocket start - starts ok
2/ refresh - still ok
3/ refresh - still ok
4/ refresh - broken.

Your solution mostly fixes my problem, but not quite. The 4th refresh would still break, but a 5th would get it going again. I think that the problem is where you jump on the llStart pointer rather thank delinking the appropriate item in the linked-list. I've used exactly as you describe above, except I created a new function RemoveFromll, which is called from ws_cleanup, and I found that ws_cleanup needed to remove itself from the parent structure in case that got used reused by a handle which wasn't the same websocket (maybe it should get initialised when a socket is first connected?):

int RemoveFromll(HttpdConnData *connData)
{
    if (llStart)
    {
        if (llStart->conn==connData)
        {
            llStart=llStart->priv->next;
        }
        else
        {
            Websock *lwsPrior=NULL;
            Websock *lws=llStart;
            //Find ws that links to this one.
            while (lws!=NULL && lws->conn!=connData)
            {
                lwsPrior=lws;
                lws=lws->priv->next;
            }
            if (lwsPrior!=NULL)
            {
                lwsPrior->priv->next=lws->priv->next;
            }
            else
            {
                return 1;
            }
        }
    }
    return 0;
}

int ICACHE_FLASH_ATTR ws_cleanup(HttpdConnData *connData)
{
    int llStatus=0;
    llStatus=RemoveFromll(connData);
    connData->cleanup=0;
    return llStatus;
    }

I also commented out the linked-list removal in cgiWebsocket, because now its done in the cleanup:

int ICACHE_FLASH_ATTR cgiWebsocket(HttpdConnData *connData) {
    char buff[256];
    int i;
    sha1nfo s;
    if (connData->conn==NULL) {
        //Connection aborted. Clean up.
//      os_printf("WS: Cleanup\n");
        if (connData->cgiPrivData) {
            Websock *ws=(Websock*)connData->cgiPrivData;
            if (ws->closeCb) ws->closeCb(ws);
            //Clean up linked list
            //if (llStart==ws) {
            //  llStart=ws->priv->next;
            //} else if (llStart) {
            //  Websock *lws=llStart;
                //Find ws that links to this one.
            //  while (lws!=NULL && lws->priv->next!=ws) lws=lws->priv->next;
            //  if (lws!=NULL) lws->priv->next=ws->priv->next;
            //}
            if (ws->priv) os_free(ws->priv);
            os_free(connData->cgiPrivData);
            connData->cgiPrivData=NULL;
        }
        return HTTPD_CGI_DONE;
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants