lwip-users
[Top][All Lists]
Advanced

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

[lwip-users] [lwip] lwIP crashing after 17MB of data transfer


From: psheer
Subject: [lwip-users] [lwip] lwIP crashing after 17MB of data transfer
Date: Wed, 08 Jan 2003 23:57:42 -0000

Hi Adam and others

I still have a problem with lwip-cvs-20020215 that I had
with a previous version, lwip-cvs-20020114

I have created a BSD socket layer (way below) for PaulOS.
I use nc (net cat) to dump many megs through this echo
server...


[[[

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <socket.h>
#include "lwip/lwip/src/include/lwip/stats.h"

#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))

static int listen_socket (int listen_port)
{
    struct sockaddr_in a;
    int s;
    if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
        perror ("socket() failed");
        return -1;
    }
    memset (&a, 0, sizeof (a));
    a.sin_port = htons (listen_port);
    a.sin_family = AF_INET;
    if (bind (s, (struct sockaddr *) &a, sizeof (a)) < 0) {
        perror ("bind() failed");
        close (s);
        return -1;
    }
    printf ("accepting connections on port %d\n", (int) listen_port);
    listen (s, 10);
    return s;
}

int main (int argc, char **argv)
{
    int fd, s, r, l = 0;
    char buf[2048];
    struct sockaddr_in a;
    int i = 0;

    s = listen_socket (81);
    for (;;) {
        l = sizeof (struct sockaddr_in);
        fd = accept (s, (struct sockaddr *) &a, &l);
        for (;;) {
            char *p;
            r = read (fd, buf, 1024);
            if (r <= 0) {
                perror ("read");
                break;
            }
            p = buf;
            while (r > 0) {
                int c;
                c = write (fd, p, min (1024, r));
                if (c <= 0) {
                    perror ("write");
                    goto out;
                }
                p += c;
                r -= c;
            }
        }
      out:
        close (fd);
    }
}

]]]


but after dumping 17 megs it dies unexpectedly. I turn
on debug, but with debug on, it works perfectly. It also
works perfectly if I add a small delay to the main loop.
It seems to only break when it runs flat out, and then
always in exactly the same place. After it dies I can
still ping it though.

I added code to the above to check memory usage but
memory usage is really very small.

I am using much more memory than the default lwipopts.h
 - i have raised most of the values by an order of
magnitude. Note that this is running on an Atmel ARM7TDMI
with 512kB of SRAM.

any ideas??

-paul

---------------------------


#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "errno.h"
#include "file.h"
#include "list.h"
#include "sys/ioctl.h"

static int lwip_error_to_errno (int v)
{
    const int e[] =
        { 0, ENOMEM, ENOBUFS, ECONNABORTED, ECONNRESET, ESHUTDOWN, ENOTCONN, 
EINVAL, EINVAL,
EHOSTUNREACH,
        EADDRINUSE
    };
    return e[-v];
}

#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))

LIST_TYPE_DECLARE (incoming_item, struct tcp_pcb * pcb;);
LIST_TYPE_DECLARE (packet_item, struct pbuf *pbuf;);

static void incoming_free (incoming_item * p)
{
    if (p->pcb) {
        tcp_arg (p->pcb, NULL);
        tcp_sent (p->pcb, NULL);
        tcp_recv (p->pcb, NULL);
        tcp_close (p->pcb);
    }
}

static void packet_free (packet_item * p)
{
    pbuf_free (p->pbuf);
}

struct socket_info {
#define LISTENER_MAGIC  0x95de8a3b
#define STREAM_MAGIC    0x3fd740ab
    int type;
    int ref;                    /* number of times dup'ed */
    struct tcp_pcb *pcb;
    union {
        struct {
            int listener_queue_max_len;
             LIST_DECLARE (incoming_list, incoming_item);       /* queued 
incoming connections for
listening sockets */
        } listener;
        struct {
            LIST_DECLARE (packet_list, packet_item);    /* queued incoming 
packets for connected
sockets */
            struct pbuf *current;
            int in_packet_offset;
        } stream;
    } d;
};

static void _socket_close (struct socket_info *info)
{
    if (info->pcb) {
        tcp_arg (info->pcb, NULL);
        tcp_sent (info->pcb, NULL);
        tcp_recv (info->pcb, NULL);
        tcp_close (info->pcb);
        info->pcb = 0;
    }
}


static err_t _socket_poll (void *arg, struct tcp_pcb *pcb)
{
    if (arg == NULL) {
        tcp_close (pcb);
    }
#if 0
    else {
        send_data (pcb, (struct http_state *) arg);
    }
#endif

    return ERR_OK;
}

static void _socket_error (void *arg, err_t err)
{
    struct socket_info *info = (struct socket_info *) arg;
    ldeleteall (info->d.stream.packet_list);
    if (info->pcb)
        _socket_close (info);
}

static void _listener_error (void *arg, err_t err)
{
    struct socket_info *info = (struct socket_info *) arg;
    ldeleteall (info->d.listener.incoming_list);
    if (info->pcb)
        _socket_close (info);
}

static void *socket_dup (void *o)
{
    struct socket_info *info = (struct socket_info *) o;
    info->ref++;
    return info;
}

static void socket_close (void *o)
{
    struct socket_info *info = (struct socket_info *) o;
    if (info->ref) {
        info->ref--;
        return;
    }
    if (info->type == LISTENER_MAGIC) {
        ldeleteall (info->d.listener.incoming_list);
        _socket_close (info);
    } else {
        ldeleteall (info->d.stream.packet_list);
        _socket_close (info);
    }
    free (o);
}

static inline int _socket_write_space (struct socket_info *info)
{
    if (stats.memp[MEMP_TCP_SEG].used > stats.memp[MEMP_TCP_SEG].avail / 2)
        return 0;
    return tcp_sndbuf (info->pcb);
}

static int socket_write_space (void *o, int n)
{
    struct socket_info *info = (struct socket_info *) o;

    if (info->type != STREAM_MAGIC)
        return -1;

    if (!info->pcb)
        return -1;

    return _socket_write_space (info);
}

static int socket_write (void *o, unsigned char *s, int len)
{
    struct socket_info *info = (struct socket_info *) o;
    err_t err;

    if (info->type != STREAM_MAGIC) {
        errno = ENOTSOCK;
        return -1;
    }

    if (!info->pcb) {
        errno = ENOTCONN;
        return -1;
    }

    do {
/* explicit (i.e. one extra) */
        global_callback ();
        if (!info->pcb)         /* socket closed */
            return 0;
    } while (_socket_write_space (info) <= 0);

    len = min (len, tcp_sndbuf (info->pcb));

    err = tcp_write (info->pcb, s, len, 1);

    if (err == ERR_OK) {
        if (!info->pcb->unacked)
            tcp_output (info->pcb);
        return len;
    }
    errno = lwip_error_to_errno (err);
    return -1;
}

static int socket_write_queue (void *o)
{
    struct socket_info *info = (struct socket_info *) o;
    struct tcp_seg *unsent;
    int total = 0;
    if (info->type != STREAM_MAGIC)
        return -1;
    if (!info->pcb)
        return -1;
    for (unsent = info->pcb->unsent; unsent; unsent = unsent->next)
        total += unsent->len;
    return total;
}

static int socket_write_nonblock (void *o, unsigned char *s, int len)
{
    if (socket_write_space (o, 0))
        return socket_write (o, s, len);
    errno = EAGAIN;
    return -1;
}

err_t _socket_recv (void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
    struct socket_info *info = (struct socket_info *) arg;
    if (err == ERR_OK && p == NULL) {
        _socket_close (info);
    }
    if (err == ERR_OK && p != NULL) {
        struct packet_item *j;
/* record the packet in our list for later reading */
        lappend (info->d.stream.packet_list);
        j = ltail (info->d.stream.packet_list);
        j->pbuf = p;
    }
    return ERR_OK;
}

static int socket_read (void *o, unsigned char *s, int len)
{
    struct socket_info *info = (struct socket_info *) o;
    struct packet_item *j;
    int r = 0;

    if (info->type != STREAM_MAGIC) {
        errno = ENOTSOCK;
        return -1;
    }

    if (!info->pcb) {
        errno = ENOTCONN;
        return -1;
    }

    for (;;) {
/* explicit (i.e. always one extra callback) */
        global_callback ();
        if (!info->pcb)         /* socket closed */
            return 0;
        if ((j = lhead (info->d.stream.packet_list)))
            if (j->pbuf->tot_len > 0)
                break;
    }

/* start at the first pbuf in the segment */
    if (!info->d.stream.current) {
        info->d.stream.current = j->pbuf;
        info->d.stream.in_packet_offset = 0;
    }

/* FIXME: quadruple check this algorithm */
    for (;;) {
        int c;
        c = min (len, info->d.stream.current->len - 
info->d.stream.in_packet_offset);
        if (!c)
            break;              /* out of space */
        memcpy (s, info->d.stream.current->payload + 
info->d.stream.in_packet_offset, c);
        s += c;
        r += c;
        len -= c;
        info->d.stream.in_packet_offset += c;
        if (info->d.stream.in_packet_offset == info->d.stream.current->len) {
            info->d.stream.current = info->d.stream.current->next;
            info->d.stream.in_packet_offset = 0;
        }
        if (!info->d.stream.current) {
/* consumed all pbufs, so delete segment */
            ldeleteinc (info->d.stream.packet_list, j);
            if (!j)
                break;          /* nothing left to process */
            info->d.stream.current = j->pbuf;
        }
    }

    tcp_recved (info->pcb, r);

    tcp_output (info->pcb);

    return r;
}

static int socket_read_avail (void *o, int n)
{
    packet_item *j;
    int total = 0;

    struct socket_info *info = (struct socket_info *) o;

    if (info->type == STREAM_MAGIC) {
        if (!info->pcb)
            return -1;
        lsearchforward (info->d.stream.packet_list, j, total += 
j->pbuf->tot_len);
        return total;
    }

/* return a count of the incoming connections */
    return lcount (info->d.listener.incoming_list);
}

static int socket_read_nonblock (void *o, unsigned char *s, int len)
{
    if (socket_read_avail (o, 0))
        return socket_read (o, s, len);
    errno = EAGAIN;
    return -1;
}

static err_t _socket_accept (void *arg, struct tcp_pcb *pcb, err_t err)
{
    struct socket_info *info = (struct socket_info *) arg;
    incoming_item *j;

    if (lcount (info->d.listener.incoming_list) >=
info->d.listener.listener_queue_max_len)
        return ERR_MEM;

    lappend (info->d.listener.incoming_list);
    j = ltail (info->d.listener.incoming_list);
    j->pcb = pcb;

    return ERR_OK;
}

static void *socket_socket (void *param, int arg1, int arg2)
{
    struct socket_info *info;

    info = (struct socket_info *) malloc (sizeof (struct socket_info));
    if (!info) {
        errno = ENOMEM;
        return 0;
    }
    memset (info, 0, sizeof (struct socket_info));
    info->pcb = tcp_new ();
    if (!info->pcb) {
        errno = ENOMEM;
        free (info);
        return 0;
    }
    info->type = LISTENER_MAGIC;
    linit (info->d.listener.incoming_list, incoming_item, incoming_free);
    tcp_err (info->pcb, _listener_error);
    return (void *) info;
}

static int socket_ioctl (void *o, int cmd, int *config)
{
    struct socket_info *info = (struct socket_info *) o;
    struct sockaddr_in *s = (struct sockaddr_in *) config;
    err_t r;
    switch (cmd) {
    case SIOBIND:
        if (info->type != LISTENER_MAGIC) {
            errno = ENOTSOCK;
            return -1;
        }
        r = tcp_bind (info->pcb, (struct ip_addr *) &s->sin_addr, ntohs 
(s->sin_port));
        if (r != ERR_OK) {
            errno = lwip_error_to_errno (r);
            return -1;
        }
        return 0;
    case SIOLISTEN:
        if (info->type != LISTENER_MAGIC) {
            errno = ENOTSOCK;
            return -1;
        }
        info->pcb = tcp_listen (info->pcb);
        info->d.listener.listener_queue_max_len = *config;
        tcp_arg (info->pcb, o);
        tcp_accept (info->pcb, _socket_accept);
        return 0;
    }
    errno = EINVAL;
    return -1;
}

static void *socket_accept (void *o, struct sockaddr *addr, int *addrlen)
{
    incoming_item *j;
    struct socket_info *info, *linfo = (struct socket_info *) o;

    if (linfo->type != LISTENER_MAGIC) {
        errno = ENOTSOCK;
        return 0;
    }
    if (*addrlen != sizeof (struct sockaddr_in)) {
        errno = EFAULT;
        return 0;
    }

    j = lhead (linfo->d.listener.incoming_list);
    if (!j) {
        errno = EAGAIN;
        return 0;
    }
    info = (struct socket_info *) malloc (sizeof (struct socket_info));
    if (!info) {
        errno = ENOMEM;
        return 0;
    }
    memset (info, 0, sizeof (struct socket_info));
    info->type = STREAM_MAGIC;
    linit (info->d.stream.packet_list, packet_item, packet_free);

    info->pcb = j->pcb;
    j->pcb = 0;                 /* set to zero so it doesn't free */

/* remove from listener queue */
    ldeleteinc (linfo->d.listener.incoming_list, j);

    tcp_arg (info->pcb, (void *) info);
    tcp_recv (info->pcb, _socket_recv);
    tcp_err (info->pcb, _socket_error);
    tcp_poll (info->pcb, _socket_poll, 4);

    return (void *) info;
}

struct file file_socket = {
    socket_socket,              /* we use the open() method */
    socket_dup,
    socket_close,
    socket_ioctl,
    0,
    socket_write,
    socket_write,
    socket_write_space,
    socket_write_nonblock,
    0,
    socket_read,
    socket_read,
    socket_read_avail,
    socket_read_nonblock,
    socket_write_queue,
    0,
    0,
    socket_accept,
};







---------------------------------------------
This message was sent using World Mail.
http://www.worldonline.co.za


[This message was sent through the lwip discussion list.]




reply via email to

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