This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Problem with IP Stack ...


I have a serious problem with the IP Stack of ecos. Whenever UDP packets are
sent to an open socket and nobody cares to read the packets, ecos crashes after
a while. The problem seems to be related to the long known `out of MBUFs'
problem. At least one occasionally reads this message before the crash happens.
As I understand, however, running out of MBUFs should not actually crash the
system.

The attached code will reproduce the problem.

target code:
	mbuf.cpp

host code (linux):
	client.cpp


To reproduce the problem first load and start mbuf. It will open an udp socket
and then print mbuf statistics.

Then start the client tool:
	./client 10.16.2.238 9001 100000

The last argument determines an interval (realized as a for loop) between two
consecutive transmissions of data. A smaller value results in faster
transmissions.

With an interval value of 0 (up to 100000 on my machine) ecos crashes
immediately.

The problem is not restricted to UDP sockets. It also happens after return from
accept of a TCP socket. Note, however, that the problem does not occur *before*
accept returns.

I use ecos version 2.0 (from June or Juli).

Any ideas on what is going on here or where I could start searching?


Thx,
Tom
#include <cyg/infra/diag.h>
#include <pkgconf/kernel.h>
#include <cyg/kernel/sched.hxx>

#include <cyg/infra/cyg_type.h>
#include <cyg/kernel/kapi.h>
#include <cyg/kernel/thread.hxx>
#include <cyg/kernel/thread.inl>

#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>

#include <sys/types.h>	// socket
#include <sys/socket.h>	// socket
#include <netinet/in.h>	// IPPROTO_TCP
#include <netinet/ip.h>	// IPTOS_....
#include <arpa/inet.h>	// inet_addr / inet_aton

static cyg_uint8    threadStack[ CYGNUM_HAL_STACK_SIZE_TYPICAL ];
static char	    threadName[] = "Network Test Thread";
static cyg_handle_t threadHandle;
static cyg_thread   thread;

static void UdpThreadFunction( cyg_addrword_t threadObject );

externC void cyg_kmem_print_stats();

externC void cyg_user_start()
{
    cyg_thread_create( 5,			    // prio
		       UdpThreadFunction,	    // entry
		       0,			    // data
		       threadName,
		       threadStack,
		       sizeof( threadStack ),
		       &threadHandle,
		       &thread );

    cyg_thread_resume( threadHandle );
    
    Cyg_Scheduler::start();
}



struct SockAddrIn: public sockaddr_in
{
    SockAddrIn();
    SockAddrIn(const char* aAddr, const unsigned short aPort);

    struct sockaddr* ToSockAddr();
};



SockAddrIn::SockAddrIn()
{
    memset(static_cast<struct sockaddr_in*>(this), 0, 
	   sizeof(struct sockaddr_in));
}



SockAddrIn::SockAddrIn(const char* aAddr, const unsigned short aPort)
{
    memset(static_cast<struct sockaddr_in*>(this), 0, 
	   sizeof(struct sockaddr_in));

    struct in_addr  ia;
    
    (void) inet_aton( aAddr, &ia );
    
    sin_family       = AF_INET;
    sin_port         = htons(aPort);
    sin_addr.s_addr  = ia.s_addr;
}



struct sockaddr* SockAddrIn::ToSockAddr()
{
    return reinterpret_cast< struct sockaddr* >( this );
}
    


class MyUdpSocket
{
public:
    MyUdpSocket( const char ip_addr[], unsigned short port );
    ~MyUdpSocket();
    
protected:
    int	itsFd;
};



MyUdpSocket::MyUdpSocket( const char ip_addr[], unsigned short port )
{
    if ( (itsFd = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 )
    {
	diag_printf("socket failed: \"%s\"\n", strerror(errno));
	return;
    }
    
    SockAddrIn    sin(ip_addr, 9001);
    
    if ( bind( itsFd, sin.ToSockAddr(), sizeof(sin) ) < 0 )
    {
	diag_printf("bind failed: \"%s\"\n", strerror( errno ) );

	close( itsFd );
	itsFd = -1;
    }
}



MyUdpSocket::~MyUdpSocket()
{
    diag_printf("in MyUdpSocket::~MyUdpSocket\n");
    
    if ( itsFd != -1 )
    {
	diag_printf("in MyUdpSocket::~MyUdpSocket closing socket: %u\n",
		     itsFd);
	
	if ( close( itsFd ) < 0 )
	{
	    diag_printf("close: \"%s\"\n", strerror(errno));
	}
    }
}




static void UdpThreadFunction( cyg_addrword_t data )
{
    diag_printf("in UDP thread ...\n");
    
    void init_eth0( char my_ip_string[] );
    
    char my_ip_string[16];    // template for "uuu.vvv.www.xxx"
    
    init_eth0( my_ip_string );
    
    MyUdpSocket	sock( my_ip_string, 9001 );
    
    diag_printf("return from socket, now printing stats\n");
    
    for ( ;; )
    {
	cyg_kmem_print_stats();
	Cyg_Thread::self()->delay( 10 );
    }
}


#include <network.h>
#include <cyg/hal/hal_if.h>

#ifndef CONFIG_IP
#define CONFIG_IP 5
#endif

// offset added to the ip address of RedBoot, used
// for the ip address of the application 
#define IP_ADDR_OFFSET 8

extern cyg_bool_t   eth0_up;
extern struct bootp eth0_bootp_data;

// local ip address mapping
extern cyg_bool_t   eth0_up;
typedef unsigned char ip_addr_t[4];

void init_eth0( char my_ip_string[] )
{
    bool ip_ok;
    ip_addr_t my_ip;
    const char  *eth0_name = "eth0";

    // get the ip address of RedBoot out of flash
    ip_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
                                        const_cast< char* >("bootp_my_ip"), 
					&my_ip, CONFIG_IP);

//    diag_printf("ip: %d %d %d %d\n", my_ip[0], my_ip[1], my_ip[2], my_ip[3]);

    CYG_ASSERT( my_ip[3] + IP_ADDR_OFFSET <= 255, "IP address exceeds 255");

    // add offset to it
    my_ip[3] += IP_ADDR_OFFSET;
//    my_ip[3] = 232;     // ssgtest1ec.ssg.frequentis.frq

    sprintf(my_ip_string, "%d.%d.%d.%d", my_ip[0], my_ip[1], my_ip[2], my_ip[3]);
    diag_printf("IP: %s\n", my_ip_string );

    eth0_up = true;
    build_bootp_record(&eth0_bootp_data,
		       "Hollaro",
		       (const char *)my_ip_string,  // IP address
		       "255.255.254.0",             // net mask
		       "10.16.3.255",               // broadcast address
		       "10.16.2.1",                 // gateway address
		       "10.16.2.20");               // server address

    // call "the" init function
    if (!init_net(eth0_name, &eth0_bootp_data)) {
        diag_printf("Network initialization failed for eth0\n");
        eth0_up = false;
        return;
    }
    show_bootp(eth0_name, &eth0_bootp_data);
}
#include <sys/types.h>	// socket
#include <sys/socket.h>	// socket
#include <netinet/in.h>	// IPPROTO_TCP
#include <netinet/ip.h>	// IPTOS_....
#include <arpa/inet.h>	// inet_addr / inet_aton



#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#include <iostream>
using namespace std;

#define REDBOOT_CONSOLE	1
#define LOG_LEVEL	1000


struct SockAddrIn: public sockaddr_in
{
    SockAddrIn();
    SockAddrIn(const char* aAddr, const unsigned short aPort);

    struct sockaddr* ToSockAddr();
};


SockAddrIn::SockAddrIn()
{
    memset(static_cast<struct sockaddr_in*>(this), 0, 
	   sizeof(struct sockaddr_in));
}



SockAddrIn::SockAddrIn(const char* aAddr, const unsigned short aPort)
{
    memset(static_cast<struct sockaddr_in*>(this), 0, 
	   sizeof(struct sockaddr_in));

    struct in_addr  ia;
    
    (void) inet_aton( aAddr, &ia );
    
    sin_family       = AF_INET;
    sin_port         = htons(aPort);
    sin_addr.s_addr  = ia.s_addr;
}



struct sockaddr* SockAddrIn::ToSockAddr()
{
    return reinterpret_cast< struct sockaddr* >( this );
}
    



int main( int argc, char** argv )
{
    if ( argc != 4 )
    {
	cerr << "Usage: " << argv[0] << " ip-addr port delay" << endl;
	exit ( 1 );
    }
    
    unsigned short  port;
    
    if ( sscanf( argv[2], "%hd", &port ) != 1 )
    {
	cerr << "illegal port argument received: \"" << argv[2] << "\"" << endl;
	cerr << "Usage: " << argv[0] << " ip-addr port delay" << endl;
	exit ( 1 );
    }
    
    unsigned int  delay;
    
    if ( sscanf( argv[3], "%d", &delay ) != 1 )
    {
	cerr << "illegal delay argument received: \"" << argv[3] << "\"" 
	     << endl;
	cerr << "Usage: " << argv[0] << " ip-addr port delay" << endl;
	exit ( 1 );
    }
    
    int	itsFd;
    
    if ( (itsFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
    {
	if ( REDBOOT_CONSOLE && ( LOG_LEVEL > 0 ) )
	{
	    printf("socket failed: \"%s\"\n", strerror(errno));
	}

	return false;
    }
    
    SockAddrIn    addr(argv[1], port);
    cout <<  "connecting to " << inet_ntoa(addr.sin_addr) 
	  << " " << ntohs(addr.sin_port) << endl;
    
    if ( connect( itsFd, addr.ToSockAddr(), sizeof( addr ) ) < 0 )
    {
	perror("connect");
	return 1;
    }
    
    const unsigned int	dataLen( 256 );
    char    data[ dataLen ];
    
    for ( ;; )
    {
	cout << "writing " << dataLen << " bytes to socket" << endl;
	write( itsFd, data, dataLen );
	for (unsigned int i (0); i < delay; ++i);
    }
    
    return true;
}

-- 
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]