automote / ESP-CoAP

This repo contains CoAP protocol for ESP-12E
http://thingtronics.com
GNU General Public License v3.0
71 stars 28 forks source link

Memory leakage with packet having a Token in it #11

Closed koreldan closed 5 years ago

koreldan commented 6 years ago

Reproducibility:

Hardware: ESP8266 Software : Firefox version 45.02 + Copper extension

Set arduino sketch as server using this library. Printing 'ESP.getFreeHeap();' when a coap request is received to check memory usage.

Sending a request from Copper in debug mode (up right checkbox) with and without a token.

Behaviour: Not setting a token the ESP free memory doesn't change... while setting a token memory goes down on each request over time (8 byte each request).

Checking RFC7252 specs... a token should take exactly 8 byte

EDIT: removing the ESP coap server response to an external request with a token, the leakage still be there... so it seems that the ESP Coap server doesn't release the memory used to store the token when it receives a request with it

koreldan commented 6 years ago

Solved !

Into the file "coap_server.cpp" i've added 'delete request->token;' after line number 363.

The problem was that the 'token' variable is a uint8_t *

This type of variable is not delete by system automatically and needs to be deleted by user.

In the code there's no delete statement of that variable... so at each request new memory is allocated and previously allocated is never freed, growing over time/requests.

Probably is not the best solution, but it works atm.

The whole edited function looks like this: ` bool coapServer::loop() {

        uint8_t buffer[BUF_MAX_SIZE];
        int32_t packetlen = Udp.parsePacket();

        if (packetlen > 0) {

            packetlen = Udp.read(buffer, packetlen >= BUF_MAX_SIZE ? BUF_MAX_SIZE : packetlen);

            request->bufferToPacket(buffer,packetlen);

    //call endpoint url function

            String url = "";
            for (int i = 0; i < request->optionnum; i++) {
                if (request->options[i].number == COAP_URI_PATH && request->options[i].length > 0) {
                    char urlname[request->options[i].length + 1];
                    memcpy(urlname,request->options[i].buffer,request->options[i].length);
                    urlname[request->options[i].length] = NULL;
                    if(url.length() > 0)
                        url += "/";
                    url += urlname;

                }
            }

    //response

            if(request->code_()==COAP_EMPTY && request->type_()== COAP_CON ){

                response->version=request->version;
                response->type=COAP_RESET;
                response->code=COAP_EMPTY_MESSAGE;
                response->messageid=request->messageid;
                response->token=request->token;
                response->payload=NULL;
                response->payloadlen=0;
                sendPacket(response,Udp.remoteIP(),Udp.remotePort());
            }else if(request->code_()==COAP_EMPTY && request->type_()==COAP_RESET){

                for(uint8_t i=0;i<obscount;i++){
                    if(observer[i].observer_clientip==Udp.remoteIP()  && observer[i].observer_url==url){

                        observer[i]=observer[i+1];
                        observer[i+1]={0};
                        obscount=obscount-1;
                    }
                }

            }
            else if(request->code_()==COAP_GET||request->code_()==COAP_PUT||request->code_()==COAP_POST||request->code_()==COAP_DELETE){

                if(request->type_()== COAP_CON){

                    response->version=request->version;
                    response->type=COAP_ACK;
                    response->tokenlen=request->tokenlen;
                    response->messageid=request->messageid;
                    response->token=request->token;
                }
                else if (request->type_()==COAP_NONCON){
                    response->version=request->version;
                    response->type=COAP_NONCON;
                    response->tokenlen=request->tokenlen;
                    response->messageid=request->messageid;
                    response->token=request->token;
                }

                if(request->code_()==COAP_GET){

                    uint8_t num;
                    for(uint8_t i=0;i<=request->optionnum;i++)
                    {
                        if(request->options[i].number==COAP_OBSERVE){
                            num=i;
                            break;
                        }
                    }

                    if(request->options[num].number==COAP_OBSERVE){

                        if(*(request->options[num].buffer)==1){

                            for(uint8_t i=0;i<obscount;i++){
                                if(observer[i].observer_clientip==Udp.remoteIP()  && observer[i].observer_url==url){

                                    observer[i]=observer[i+1];
                                    observer[i+1]={0};
                                    obscount=obscount-1;
                                }

                            }

                            uri.find(url)(request,Udp.remoteIP(),Udp.remotePort(),0);

                        }

                        else {

                            addObserver(url,request,Udp.remoteIP(),Udp.remotePort());

                        }
                    }
                    else if(url==String(".well-known/core")){

                        resourceDiscovery(response,Udp.remoteIP(),Udp.remotePort(),resource);

                    }else if(!uri.find(url)){

                        response->payload=NULL;
                        response->payloadlen=0;
                        response->code=COAP_NOT_FOUND;

                        response->optionnum=0;

                        char optionBuffer[2];
                        optionBuffer[0] = ((uint16_t)COAP_TEXT_PLAIN  & 0xFF00) >> 8;
                        optionBuffer[1] = ((uint16_t)COAP_TEXT_PLAIN  & 0x00FF) ;
                        response->options[response->optionnum].buffer = (uint8_t *)optionBuffer;
                        response->options[response->optionnum].length = 2;
                        response->options[response->optionnum].number = COAP_CONTENT_FORMAT;
                        response->optionnum++;

                        sendPacket(response,Udp.remoteIP(),Udp.remotePort());   

                    }else{

                        uri.find(url)(request,Udp.remoteIP(),Udp.remotePort(),0);
                    }

                }else if(request->code_()==COAP_PUT){

                    if(!uri.find(url)){

                        response->payload=NULL;
                        response->payloadlen=0;
                        response->code=COAP_NOT_FOUND;

                        response->optionnum=0;

                        char optionBuffer[2];
                        optionBuffer[0] = ((uint16_t)COAP_TEXT_PLAIN  & 0xFF00) >> 8;
                        optionBuffer[1] = ((uint16_t)COAP_TEXT_PLAIN  & 0x00FF) ;
                        response->options[response->optionnum].buffer = (uint8_t *)optionBuffer;
                        response->options[response->optionnum].length = 2;
                        response->options[response->optionnum].number = COAP_CONTENT_FORMAT;
                        response->optionnum++;

                        sendPacket(response,Udp.remoteIP(),Udp.remotePort());   

                    }else{
                        uri.find(url)(request,Udp.remoteIP(),Udp.remotePort(),0);
                    }
                }else if(request->code==COAP_POST){

                    int i;
                    for( i=0;i<rcount;i++){
                        if(resource[i].rt==url){

                            uri.find(url)(request,Udp.remoteIP(),Udp.remotePort(),0);
                            break;
                        }
                    }
                    if(i==rcount){
                //add new resource

                    }

                }else if(request->code==COAP_DELETE){

                    if(!uri.find(url)){
                        response->payload=NULL;
                        response->payloadlen=0;
                        response->code=COAP_NOT_FOUND;

                        response->optionnum=0;

                        char optionBuffer[2];
                        optionBuffer[0] = ((uint16_t)COAP_TEXT_PLAIN  & 0xFF00) >> 8;
                        optionBuffer[1] = ((uint16_t)COAP_TEXT_PLAIN  & 0x00FF) ;
                        response->options[response->optionnum].buffer = (uint8_t *)optionBuffer;
                        response->options[response->optionnum].length = 2;
                        response->options[response->optionnum].number = COAP_CONTENT_FORMAT;
                        response->optionnum++;

                        sendPacket(response,Udp.remoteIP(),Udp.remotePort());   

                    }else{//delete

                    }

                }
                delete request->token; // THE ADDED LINE
            }

        }

//checking for the change for resource 
        unsigned currentMillis=millis();
        if ((unsigned long)(currentMillis-previousMillis)>=interval)
        {   
    //observing a resouce 

            uri.find(resource[0].rt)(request,(0,0,0,0),NULL,1);
            previousMillis=millis();
        }

    }

`