Memory Allocation Fails on FreeRTOS_Socket Call

Okay, thanks.

So, I’ll create vApplicationIPNetworkEventHook_Multi() and here is where I call FreeRTOS_socket(), FreeRTOS_bind(), FreeRTOS_select()?

Should I set ipconfigIPv4_BACKWARD_COMPATIBLE? What does this do?

What’s the difference between vApplicationIPNetworkEventHook() and vApplicationIPNetworkEventHook_Multi()?

Hi @dougr,

No, some APIs are not supported to call by hook function because it uses IP task.
I’ll suggest to create a new task to handle this kind of operations.

I don’t think so. That configuration is used for backward compatible with version below V4.0.0 (as described here). People who’s using old FreeRTOS-Plus-TCP might enable this flag to reduce migration effort when updating FreeRTOS-Plus-TCP. Note that enable ipconfigIPv4_BACKWARD_COMPATIBLE will disable some features like multiple interfaces, and IPv6 introduced from V4.0.0.

vApplicationIPNetworkEventHook() is previous hook function before V4.0.0. And vApplicationIPNetworkEventHook_Multi() is current hook function with different input parameters. Refer to vApplicationIPNetworkEventHook_Multi() manual for more detail.

Thanks.

All agreed with @ActoryOu , thank you.

One thing about the function vApplicationIPNetworkEventHook[_Multi](): it is called from the IP-task. Every FreeRTOS task is allowed to become a client of the IP-task, except the IP-task itself. You would see many time-outs because the IP-task can not help itself.

In stead you can wakeup a task that wants to use the network, e.g.;

    xTaskNotify( prvCliTask, IP_TASK_READY, eSetBits );

which would wakeup prvCliTask() and let it know that it can create sockets.

    xTaskNotifyWait( 0U,   /* ulBitsToClearOnEntry */
        ~0U,               /* ulBitsToClearOnExit */
        &( ulEvents ),     /* pulNotificationValue */
        ulMaxBlockTime );
    if( ( ulEvents  & IP_TASK_READY ) != 0U )
    {
        FreeRTOS_printf( ( "Ethernet ready\n" ) );
    }
1 Like

Thanks for everyone’s help so far. I think I’m getting close.

I created vApplicationIPNetworkEventHook_Multi() which gets called on the eNetworkDownEvent. This function creates a task I call NetworkUpTask.

The NetworkUpTask has the following in it:
FreeRTOS_socket(FREERTOS_AF_INET4,FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP)
FreeRTOS_setsockopt(FREERTOS_SO_RCVTIMEO)
FreeRTOS_setsockopt(FREERTOS_SO_SNDTIMEO)
FreeRTOS_bind()
FreeRTOS_listen()
for( ; ; ) {
FreeRTOS_recv(cRXData)
}

All functions including, FreeRTOS_socket(), now return passing values. I’m trying to create a server, not a client.

When executed, I don’t see the this listed in my router’s connected list and I can’t telnet to it.

I have a bunch of debug printf statements to help debug. Here’s what I’m seeing:
IP Address: 192.168.1.68
MAC Address: 00:0A:35:E5:E5:5E
Port: 45678
Netmask: 255.255.255.0
FreeRTOS_FillEndPoint
FreeRTOS_IPInit_Multi
vTaskStartScheduler
prvIPTask started
prvProcessIPEventsAndTimers: event type: 0 (network down event)
vApplicationIPNetworkEventHook_Multi
NetworkUpTask
Socket created!
FreeRTOS_setsockopt FREERTOS_SO_RCVTIMEO set.
FreeRTOS_setsockopt FREERTOS_SO_SNDTIMEO set.
prvProcessIPEventsAndTimers: event type: 9 (bind event)
FreeRTOS_bind good.
FreeRTOS_listen: 0
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: 3 (ARP timer event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: 3 (ARP timer event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)
prvProcessIPEventsAndTimers: event type: -1 (no event)

Should I be able to see this on my router at this point? Should I be able to telnet to it or ping it?

Am I missing something? I see no errors.

Looks like I forgot to add the FreeRTOS_accept() call after the FreeRTOS_listen() call.

So, I added that, but the call never returns. Is FreeRTOS_accept() blocking?

Optionally yes. As documented here.

About timeouts of connect() and accept():

Accepting a TCP connection is a bit like receiving, and therefor the timeout ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME is used. It can be overridden with the FREERTOS_SO_RCVTIMEO socket option.

The opposite is to connect, which is outgoing. The function FreeRTOS_connect() will block until a connection is built up, or until ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME clock ticks have passed. This can be changed with the socket option FREERTOS_SO_SNDTIMEO.

Note that the child sockets returned by FreeRTOS_accept() have the same properties as their parent socket. This is important because reception of data may already start before accept() has returned the socket to the application. So the buffer space and WIN size must be known before you own the new socket.

Well, I think I want FreeRTOS_accept() to block until a connection is made.

In any case, it never returns although the other tasks are running. I put my NetworkUpTask() code below to see if anyone can see problem. I don’t see anything on my router. I think I’m getting close, but I’m not sure what to try next.

THANKS!

static void NetworkUpTask( void * pvParameters )
{
struct freertos_sockaddr xBindAddress;
struct freertos_sockaddr xClient;
socklen_t xSize = sizeof( xClient );
static const TickType_t xReceiveTimeOut = portMAX_DELAY;
const BaseType_t xBacklog = 20;
static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 );
static char cRXData[ RX_IP_BUFFER_SIZE ];
BaseType_t lBytesReceived;
BaseType_t rv;

printf(“NetworkUpTask\n\r”);

xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET4,
FREERTOS_SOCK_STREAM,
FREERTOS_IPPROTO_TCP );
configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );
if(xListeningSocket != FREERTOS_INVALID_SOCKET) {
printf(“Listening Socket created!\n\r”);
}
else {
printf(“ERROR: Listening Socket could not be created!\n\r”);
}

rv = FreeRTOS_setsockopt( xListeningSocket,
		0,
  	FREERTOS_SO_RCVTIMEO,
  	&xReceiveTimeOut,
  	sizeof( xReceiveTimeOut ) );
if(rv == 0) {
	printf("FreeRTOS_setsockopt FREERTOS_SO_RCVTIMEO set.\n\r");
}
else {
	printf("ERROR: FreeRTOS_setsockopt FREERTOS_SO_RCVTIMEO failed.\n\r");
}

rv = FreeRTOS_setsockopt( xListeningSocket,
		0,
  	FREERTOS_SO_SNDTIMEO,
  	&xSendTimeOut,
  	sizeof( xSendTimeOut ) );
if(rv == 0) {
	printf("FreeRTOS_setsockopt FREERTOS_SO_SNDTIMEO set.\n\r");
}
else {
	printf("ERROR: FreeRTOS_setsockopt FREERTOS_SO_SNDTIMEO failed.\n\r");
}

xBindAddress.sin_port = ( uint16_t ) ucPort;
xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );

rv = FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );
if(rv == 0) {
	printf("FreeRTOS_bind good.\n\r");
}
else {
	printf("ERROR: FreeRTOS_bind failed.\n\r");
}

rv = FreeRTOS_listen( xListeningSocket, xBacklog );
printf("FreeRTOS_listen: %ld\n\r", rv);\

for( ; ; )
{
    xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );
    configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET );
    if(xConnectedSocket != FREERTOS_INVALID_SOCKET) {
    	printf("FreeRTOS_accept good.\n\r");
    }
    else {
    	printf("ERROR: FreeRTOS_accept failed.\n\r");
    }

    lBytesReceived = FreeRTOS_recv( xConnectedSocket, &cRXData, RX_IP_BUFFER_SIZE, 0 );

    if( lBytesReceived > 0 )
    {
        /* Data was received, process it here. */
        printf("TCP RX: %s\n\r", cRXData);
    }
    else if( lBytesReceived == 0 )
    {
        /* No data was received, but FreeRTOS_recv() did not return an error.
        Timeout? */
    }
    else
    {
        /* Error (maybe the connected socket already shut down the socket?).
        Attempt graceful shutdown. */
        FreeRTOS_shutdown( xListeningSocket, FREERTOS_SHUT_RDWR );
        break;
    }
}

}

What is the address part of xBindAddress initialized to?

Hi RAc,

I have ucPort = 45678. After the FreeRTOS_htons function, xBindAddress.sin_port = 28338.

I am not asking about the port, but address member - generally INADDR_ANY for accepting sockets.

xBindAddress values
sin_len = 5
sin_family = 5
sin_port = 28338
sin_flowinto = 101058054
sin_address (ulIP_IPv4) = 117901063
sin_address (ulIP_IPv6) ucBytes [0:15] = 7 7 7 7 8 8 8 8 9 9 9 9 16 16 16 16

The IP address I set is 192.168.1.68 in the FreeRTOS_FillEndPoint() function call in main.c.

That does not look right from my understanding. The IP4v4 address translates to 0x7070707 which is consistent with the IPv6 interpretation but no valid IPv4 address.

Hmm. I think I’m following the example I found.

I have this code in main:

uint8_t ucMACAddress[6] = { 0x00, 0x0A, 0x35, 0xE5, 0xE5, 0x5E };
uint8_t ucIPAddress[4] = { 192, 168, 1, 68 };
uint8_t ucNetMask[4] = { 255, 255, 0, 0 };
uint8_t ucGatewayAddress[4] = { 10, 10, 10, 1 };
uint8_t ucDNSServerAddress[4] = { 208, 67, 222, 222 };

FreeRTOS_FillEndPoint( &( xInterfaces[ 0 ] ), &( xEndPoints[ 0 ] ), ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );

Should I be doing it differently? Or, does the MAC address and IP address get set somewhere else?

But the variable is local in your NetworkSetup function, so it must be different from what you do in main(). You may have a misunderstanding; the binding address is generally independent of a network configuration address. Please study the documentation for bind() and examples of successful passive communication setups. Normally the address part of the structure passed to bind() before listen() is INADDR_ANY (0), implying that connection attempts through all interfaces on this machine will be serviced by this end point. You can also copy the address of one of youir interfaces if required, but you must explicitly set the address part of a binding address.

@dougr, it could still be useful if you can show more code of your project.

When you fill in a socket address, it is recommended to set all fields. For instance like:

    memset( &xBindAddress, 0, sizeof( xBindAddress ) );
    xBindAddress.sin_len = sizeof( xBindAddress );
    xBindAddress.sin_family = FREERTOS_AF_INET;
    xBindAddress.sin_port = ( uint16_t ) ucPort;
    xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );

IThe above code makes me wonder what variable is ucPort? It looks like an 8-bit variable? Can that hold a 16-bit port number?

About the network setup:

    uint8_t ucMACAddress[6] = { 0x00, 0x0A, 0x35, 0xE5, 0xE5, 0x5E };
    uint8_t ucIPAddress[4] = { 192, 168, 1, 68 };
    uint8_t ucNetMask[4] = { 255, 255, 0, 0 };
    uint8_t ucGatewayAddress[4] = { 10, 10, 10, 1 };
    uint8_t ucDNSServerAddress[4] = { 208, 67, 222, 222 };

I am not sure if you use it, but with this setup you need a gateway to reach your gateway!

The network has an IPv4 address 192.168.0.0

You can ARP with all devices whose address is 192.168.x.x. When you want to reach an remote address of 10.10.10.1 you would need a gateway.
In other works, you are mixing a class A with a class C network.

Your netmask is OK/legal, but it should be noted that in most cases, class C address range has 254 hosts per network:

    uint8_t ucIPAddress[4] = { 192, 168, 1, 68 };
    uint8_t ucNetMask[4]   = { 255, 255, 255, 0 };

In the above example, any host with 192.168.1.x can become a gateway.

#define ipconfigNIC_N_TX_DESC 4
#define ipconfigNIC_N_RX_DESC 64 // 64 correct?

Yes that is good. When the outgoing descriptors are busy, the network driver will wait for a free slot. A queue of 4 is more than enough because transmissions are very fast.

For incoming packets, we need more buffer space: the IP-task may be busy and we don’t want to drop incoming packets.

pxZynq_FillInterfaceDescriptor(0, &( xInterfaces[0]));

FreeRTOS_FillEndPoint( &( xInterfaces[ 0 ] ), &( xEndPoints[ 0 ] ), ucIPAddress,
ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );

Just to make sure: the interface and endpoint structs that you pass here, should continue to exist as long as the IP-stack is being used. Please declare them as static variables in the file, usually main.c
Do not declare them on the stack of main(), because the stack may get a new destination once the scheduler has started.

Wow! Thanks for all the replies and support!

RAc, I was copying code from the examples and tutorials. I thought I only needed to set the addresses in FreeRTOS_FillEndPoint(). So, I tried to change the xBindAddress.sin_address to INADDR_ANY, but it is undeclared when I compile.

htibosch, I’m adding more of my code below. I misnamed ucPort. It is a uint16_t variable. I’m renaming it usPort.

I just copied the gateway address and DNS server address from an example. What should they be set to? I’ll change the netmask to 255.255.255.0. I declared xInterfaces and xEndPoints as global variables. I’m changing xBindAddress as suggested.

I read the MAC address, IP address, and netmask from an EEPROM.

CURRENT CODE:

// global variables
uint8_t ucMACAddress[6] = { 0x00, 0x0A, 0x35, 0xE5, 0xE5, 0x5E };
uint8_t ucIPAddress[4] = { 192, 168, 1, 68 };
uint8_t ucNetMask[4] = { 255, 255, 255, 0 };
uint8_t ucGatewayAddress[4] = { 10, 10, 10, 1 };
uint8_t ucDNSServerAddress[4] = { 208, 67, 222, 222 };
uint16_t usPort = 45678;
const BaseType_t xBacklog = 20;

NetworkInterface_t xInterfaces[ 1 ];
NetworkEndPoint_t xEndPoints[ 4 ];
Socket_t xListeningSocket;
Socket_t xConnectedSocket;

int main()
{
pxZynq_FillInterfaceDescriptor(0, &( xInterfaces[0]));

FreeRTOS_FillEndPoint( &( xInterfaces[ 0 ] ), &( xEndPoints[ 0 ] ), ucIPAddress,
ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );

FreeRTOS_IPInit_Multi();

vTaskStartScheduler();
}

void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent, struct xNetworkEndPoint * pxEndPoint )
{
static BaseType_t xTasksAlreadyCreated = pdFALSE;

printf(“vApplicationIPNetworkEventHook_Multi\n\r”);

/* Check this was a network up event, as opposed to a network down event. /
if( eNetworkEvent == eNetworkUp ) {
/
Create the tasks that use the TCP/IP stack if they have not already been created. /
if( xTasksAlreadyCreated == pdFALSE ) {
/
Create the tasks here. /
xTaskCreate( NetworkUpTask, /
The function that implements the task. /
“NetworkUpTask”, /
Just a text name for the task to aid debugging. /
ipconfigIP_TASK_STACK_SIZE_WORDS, /
The stack size is defined in FreeRTOSIPConfig.h. /
NULL, /
The task parameter, not used in this case. /
ipconfigIP_TASK_PRIORITY, /
The priority assigned to the task is defined in FreeRTOSConfig.h. /
NULL ); /
The task handle is not used. */

  	xTasksAlreadyCreated = pdTRUE;
  	FreeRTOS_printf( ( "Application idle hook network up\n" ) );
  }

}
else {
FreeRTOS_printf( ( “Application idle hook network down\n” ) );
}
}

static void NetworkUpTask( void * pvParameters )
{
struct freertos_sockaddr xBindAddress;
struct freertos_sockaddr xClient;
socklen_t xSize = sizeof( xClient );
static const TickType_t xReceiveTimeOut = portMAX_DELAY;
const BaseType_t xBacklog = 20;
static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 );
static char cRXData[ RX_IP_BUFFER_SIZE ];
BaseType_t lBytesReceived;
BaseType_t rv;

printf(“NetworkUpTask\n\r”);

xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET4,
FREERTOS_SOCK_STREAM,
FREERTOS_IPPROTO_TCP );
configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );
if(xListeningSocket != FREERTOS_INVALID_SOCKET) {
printf(“Listening Socket created!\n\r”);
}
else {
printf(“ERROR: Listening Socket could not be created!\n\r”);
}

rv = FreeRTOS_setsockopt( xListeningSocket,
		0,
  	FREERTOS_SO_RCVTIMEO,
  	&xReceiveTimeOut,
  	sizeof( xReceiveTimeOut ) );
if(rv == 0) {
	printf("FreeRTOS_setsockopt FREERTOS_SO_RCVTIMEO set.\n\r");
}
else {
	printf("ERROR: FreeRTOS_setsockopt FREERTOS_SO_RCVTIMEO failed.\n\r");
}

rv = FreeRTOS_setsockopt( xListeningSocket,
		0,
  	FREERTOS_SO_SNDTIMEO,
  	&xSendTimeOut,
  	sizeof( xSendTimeOut ) );
if(rv == 0) {
	printf("FreeRTOS_setsockopt FREERTOS_SO_SNDTIMEO set.\n\r");
}
else {
	printf("ERROR: FreeRTOS_setsockopt FREERTOS_SO_SNDTIMEO failed.\n\r");
}

xBindAddress.sin_port = ( uint16_t ) usPort;
xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );

rv = FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );
if(rv == 0) {
	printf("FreeRTOS_bind good.\n\r");
}
else {
	printf("ERROR: FreeRTOS_bind failed.\n\r");
}

rv = FreeRTOS_listen( xListeningSocket, xBacklog );
printf("FreeRTOS_listen: %ld\n\r", rv);\

for( ; ; )
{
    xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );
    configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET );
    if(xConnectedSocket != FREERTOS_INVALID_SOCKET) {
    	printf("FreeRTOS_accept good.\n\r");
    }
    else {
    	printf("ERROR: FreeRTOS_accept failed.\n\r");
    }

    lBytesReceived = FreeRTOS_recv( xConnectedSocket, &cRXData, RX_IP_BUFFER_SIZE, 0 );

    if( lBytesReceived > 0 )
    {
        /* Data was received, process it here. */
        printf("TCP RX: %s\n\r", cRXData);
    }
    else if( lBytesReceived == 0 )
    {
        /* No data was received, but FreeRTOS_recv() did not return an error.
        Timeout? */
    }
    else
    {
        /* Error (maybe the connected socket already shut down the socket?).
        Attempt graceful shutdown. */
        FreeRTOS_shutdown( xListeningSocket, FREERTOS_SHUT_RDWR );
        break;
    }
}

}

Interesting. Looks as if you took the sample code from the TCP echo server which has the same problem - it may rely on a zero initialized structure (INADDR_ANY - sorry I do not know the TCP+ name equivalent - happens to be all zeroes, so the echo server may happen to work coincidentally). Should be fixed in the sample code.

As a workaround to see if that is your problem, you can either memset your structure to all 0s before assigning the port (good practice to always initialize your locals anyways) or model your code after this example:

freertos/FreeRTOS-Plus/Demo/Common/Demo_IP_Protocols/Common/FreeRTOS_TCP_server.c at master · particle-iot/freertos · GitHub if that applies to your code.

Hmm. This line is giving me an incompatible type error. How is this supposed to be set?

xBindAddress.sin_address = FreeRTOS_inet_addr_quick(ucIPAddress[0], ucIPAddress[1], ucIPAddress[2], ucIPAddress[3]);

…/FreeRTOS-Plus-TCP-main/source/include/FreeRTOS_Sockets.h:474:5: error: incompatible types when assigning to type ‘IP_Address_t’ {aka ‘union IP_Address’} from type ‘long unsigned int’
474 | ( ( ( ( uint32_t ) ( ucOctet3 ) ) << 24 ) |
| ^
…/src/vApplicationIPNetworkEventHook_Multi.c:91:32: note: in expansion of macro ‘FreeRTOS_inet_addr_quick’
91 | xBindAddress.sin_address = FreeRTOS_inet_addr_quick(ucIPAddress[0], ucIPAddress[1], ucIPAddress[2], ucIPAddress[3]);
| ^~~~~~~~~~~~~~~~~~~~~~~~
make[1]: *** [src/subdir.mk:209: src/vApplicationIPNetworkEventHook_Multi.o] Error 1
make: *** [makefile:38: all] Error 2

Never mind. I changed the assignment to xBindAddress.sin_address.ulIP_IPv4.