2012-06-18 14 views
8

Estoy usando una pila TCP/IP llamada lwip. Implementé una función a continuación para enviar paquetes de datos, inspirada en una función de devolución de llamada similar que recibe paquetes de datos.LightWeight IP: Buffer no libera

Cada vez que se recibe un paquete, creo un búfer usando la función pbuf_alloc. Luego, envío el paquete usando udp_sendto. Finalmente, libero el buffer usando pbuf_free. (Consulte el código a continuación.)

Por alguna razón, pbuf_free no está liberando el búfer. (Me da un desbordamiento de memoria intermedia después de n paquetes, donde n es el tamaño de la piscina.) The lwip wiki advierte que:

El controlador de red puede tampoco asumir que la memoria se pBuf realmente liberada cuando llama pbuf_free.

¿Cómo puedo forzar pbuf_free para liberar mi memoria intermedia? ¿Cómo se evita el desbordamiento del búfer?

(. Mi aplicación a continuación)

static err_t IAP_tftp_send_data_packet(struct udp_pcb *upcb, struct ip_addr *to, int to_port, int block) 
{ 
    err_t err; 
    struct pbuf *pkt_buf; 
    char packet[TFTP_DATA_PKT_LEN_MAX]; 
    int bytesRead; 
    int bytesToSend; 

    /* Specify that we are sending data. */ 
    IAP_tftp_set_opcode(packet, TFTP_DATA); 

    /* Specify the block number that we are sending. */ 
    IAP_tftp_set_block(packet, block); 

    bytesRead = IAP_tftp_set_data(packet, block); 

    if(bytesRead != 0) { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - (512 - bytesRead + 1); 
    } else { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - 512; 
    } 

    pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL); 

    if (!pkt_buf) 
    { 
    print("(TFTP) Buffer overflow!\r\n"); 
    } 

    /* Copy the file data onto pkt_buf. */ 
    memcpy(pkt_buf->payload, packet, bytesToSend); 

    err = udp_sendto(upcb, pkt_buf, to, to_port); 

    /* free the buffer pbuf */ 
    printf("%d\n\r", pbuf_free(pkt_buf)); 

    return err; 
} 
+0

¿Revisó el recuento de referencias en el búfer? Me temo que solo se libera si el recuento de referencia es 1. – Fred

+0

Posiblemente 'udp_sendto' toma una referencia y la libera de forma asincrónica (en un temporizador?). Tal vez solo necesitas darle un tiempo? – ugoren

+0

@ugoren: He intentado esperar mientras hay un desbordamiento del búfer, pero el desbordamiento del búfer permanece. – Randomblue

Respuesta

7

¿Qué versión de lwIP estás usando? Dependiendo de las diferentes versiones, las respuestas varían mucho.

La función de asignación memp_malloc() llamada dentro de pbuf_alloc() ha fallado o el encadenamiento de pbufs ha fallado. Por lo tanto, devuelve NULL.

pbuf_alloc() también devolverá NULL, si los argumentos pasados ​​también contienen NULL. (Debido a la comprobación de argumentos NULL).

En las versiones más recientes, ¿podría mostrar qué valor contiene la macro MEMP_OVERFLOW_CHECK? El lwIP muestra un comportamiento diferente cuando el valor de macro> = 2.

Y otra causa podría ser si está utilizando multi-threading, los mecanismos de bloqueo dentro de la pbuf_alloc() fallan, podría hacer que devuelva NULL.

Algunas versiones requieren que llame a pbuf_init(), antes de llamar a pbuf_alloc().

Puede probar esto:

pkt_buf = NULL;//Use NULL, just incase the NULL is not 0 as per your compiler. 
pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_REF); 
if(pkt_buf == NULL) 
{ 
    printf("pbuf_alloc failed.\n"); 
} 
else 
{ 
    /* Do something with the allocated pbufs and free it. */ 
} 

PBUF_REF asignará ninguna memoria intermedia para pBuf. El pbu debe usarse solo en un subproceso y si el pbu se pone en cola, se debe llamar a pbuf_take para copiar el búfer.

También puede probar PBUF_RAM que asignará el búfer en la RAM.

Para obtener más información, también puede explorar los archivos fuente de la versión de lwIP que está utilizando.

+0

Avíseme si esta respuesta todavía no respondió su pregunta. – askmish

+0

Te di la recompensa porque tu respuesta es la más prometedora. Puede que tenga que pedirte más detalles ya que tengo tiempo para investigar. Gracias. – Randomblue

+0

Si está cómodo y tiene suficiente tiempo, le sugiero que revise el código fuente de su versión, en lugar de la wiki. La wiki está mal mantenida. – askmish

6

La solución más sencilla parece ser la de hacer que el buffer static, es decir, volver a utilizar el mismo tampón para cada llamada:

static struct pbuf *pkt_buf = NULL; 

if(pkt_buf == NULL) 
    pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL); 
if(pkt_buf == NULL) 
{ 
    print("(TFTP) Buffer overflow!\r\n"); 
} 

Si su escenario implica descargar/volver a cargar el controlador, perderá memoria. Para solucionarlo, establezca el búfer estático fuera de la función IAP_tftp_send_data_packet(), y llame al pbuf_free() cuando el controlador se descargue (suponiendo que lwip lo indique).

+0

Hum, no funciona. Buena idea, sin embargo. – Randomblue

0

Sólo un pensamiento pasajero, posiblemente completamente absurdo. En este código:

if(bytesRead != 0) { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - (512 - bytesRead + 1); 
} else { 
    bytesToSend = TFTP_DATA_PKT_LEN_MAX - 512; 
} 
pkt_buf = pbuf_alloc(PBUF_TRANSPORT, bytesToSend, PBUF_POOL); 

... es posible que bytesRead a asumir el valor 513 - TFTP_DATA_PKT_LEN_MAX?

Si sucediera, ¿no fallaría la solicitud de asignar cero bytes? (esto podría probarse imprimiendo el valor de bytesToSend después del desbordamiento del búfer y comprobando si es distinto de cero).

0

struct pbuf no representa una región continua de la memoria. Es más bien una cadena de ubicaciones de memoria. Por lo tanto, esto no funcionará en el caso general:

memcpy(pkt_buf->payload, packet, bytesToSend); 

Tiene que copiar de forma dispersa sus datos. El memcpy() del fragmento de código puede desbordar el búfer de carga útil y causar todo tipo de efectos secundarios, incluida la incapacidad de liberar la cadena de pbuf limpia.

Cuestiones relacionadas