Closed koreldan closed 5 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();
}
}
`
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