Home/Support/Support Forum/BL4S200 intermittently sends [FIN, ACK]
Welcome to Digi Forum, where you can ask questions and receive answers from other members of the community.

BL4S200 intermittently sends [FIN, ACK]

0 votes
Hi,
I am running an application on the BL4S200 to read a group of DPM. The code can be described below

costate
{
tcp_open(&socket_dpm_1, ...);
do
{
waitfor(DelayMs(20));
tcp_tick(NULL);
} while((!sock_established(&socket_dpm_31)) &&
(sock_bytesready(&socket_dpm_31)=-1)) );

tcp_open(&socket_dpm_2, ...);
tcp_open(&socket_dpm_3, ...);

while(!done)
{
read socket_dpm_1, socket_dpm_2, socket_dpm_3
performs some processing
waitfor(DelayMs(20));
}

close socket_dpm_1, socket_dpm_2, socket_dpm_3
}

During normal operation, the network traffic on Wireshark looks like the following:
1/ Rabbit sends read request to the DPM
2/ DPM sends ACK
3/ DPM sends PSH/ACK with data
4/ Rabbit sends ACK

However, the Rabbit intermittently sends [FIN, ACK] in step 4 instead of an ACK, the DPM then returns [FIN, ACK] and the connection closes.

Is there something that I missed or should have done for this to work more reliably?

Thank you,
David
asked May 24, 2016 in Rabbit by phungd New to the Community (3 points)

Please log in or register to answer this question.

5 Answers

+1 vote
Generally, a clean FIN,ACK from the Rabbit indicates that the socket has been closed from the Rabbit end. Have you tried defining TCP_VERBOSE to see what sequence of actions the stack has taken?

Another thing to check would be keep alive status on the sockets if there are significant pauses in the data stream.

Regards,
Peter
answered May 25, 2016 by petermcs Veteran of the Digi Community (1,130 points)
Thank you for your answer.
I used DCRTCP_VERBOSE as you suggested and found that just right before the communication error occurred, I got the below messages:

ARP: check returns OBSOLETE
APR: arpresolve_start for IP 00000000 i/f 0...
ARP: check returns bcast/loopback
ARP: check returns bcast/loopback

Do you know why did this happen?
Thank you,
David
Hmmm,

From what I recall, the default ARP cache is quite small and the stack practises speculative caching by adding any addresses it sees broadcast in ARP responses on the network to the cache which can quite quickly flush the ARP cache of useful entries.

You can increase the size of the ARP cache by defining ARP_TABLE_SIZE. I put a hack in my copy of the UDP.LIB library to stop broadcast packets flushing the ARP cache as it was hitting performance with my code.

There are some other macros in ARP.LIB that might bear tweaking to tune the ARP cache handling but I haven't looked into them.

Regards,
Peter
0 votes
Could it be something related to how you're managing multiple sockets? Are those sockets defined as globals, or as static variables in main()? They shouldn't be located on the stack (auto).

Is it possible you forgot to update a variable name when copying/pasting code?
answered May 25, 2016 by TomCollins Veteran of the Digi Community (1,872 points)
0 votes
Peter,
I defined ARP_TABLE_SIZE to 50, but that did not make a different.

On Wireshark capture, I saw that there is a "TCP Window Update" from 0.0.0.0 to 0.0.0.0, then immediately follow that is a [FIN, ACK] from the Rabbit to the DPM.

The "TCP Window Update" from 0.0.0.0 to 0.0.0.0 corresponds to the following messages we got on the debug log:
ARP: check returns OBSOLETE
ARP: arpresolve_start for IP 00000000 i/f 0...

Why did Rabbit call arpresolve_start for "00000000"?

Thank you,
David
answered May 25, 2016 by phungd New to the Community (3 points)
There could be some memory corruption taking place as 0.0.0.0 is not a valid address. It might be worth enabling debug in ARP.LIB and setting a break point at the place where the "ARP: check returns OBSOLETE" message is generated to see what the chain leading up to it is like (it might need a bit of code added to check for 0.0.0.0 if that message is triggered a lot for valid addresses as well.

Regards,
Peter
0 votes
Hi Tom,
The variables are declared globally, not in main. So, they should be static.
answered May 25, 2016 by phungd New to the Community (3 points)
0 votes
Below is the code:

/**************************************************************************
control_x_x_x.c
**************************************************************************/
// Set a default of declaring all local variables "auto" (on stack)
#class auto

#define DCRTCP_DEBUG
#define DCRTCP_VERBOSE

#define TCPCONFIG 1
#define _PRIMARY_STATIC_IP "192.168.10.10"
#define _PRIMARY_NETMASK "255.255.255.0"
#define MY_GATEWAY "192.168.10.1"
#define MY_NAMESERVER "192.168.10.1"
#define PORT_EXT 23
#define MAX_TCP_SOCKET_BUFFERS 20

#define DPM_A31 "192.168.10.31"
#define DPM_PORT 502

#memmap xmem
#use "dcrtcp.lib"
#use "BLxS2xx.lib"
#use "sdflash.lib"

#define VERSION "1.2.f"
#define END_TEXT "End of debug"

// Global vars
tcp_Socket socket_dpm_31, socket_ext;

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
void main()
{
struct tm t;
long error_count = 0;
long max_reading_time_31 = 0;
long start_time = 0;
long active_loop_count = 0;

int j, rc, write_status = 0;
int bytes_read, total_bytes_read = 0;
char buffer[100];
word iface;

char t_mac_buf[6], t_mac_addr[40];
longword ip_dpm_31;
int a_count;
char store31[10];
char buffer31[10];
int temp_bytes_31, bytes_read_31;

// Initialize the controller
brdInit();

// Start network and wait for interface to come up (or error exit).
sock_init_or_exit(1);

// get MAC address for the rabbit
for (iface = 0; iface < IF_MAX; ++iface)
if (is_valid_iface(iface))
{
printf("Interface %u is valid.\n");
if (!ifconfig(iface, IFG_HWA, t_mac_buf, IFS_END))
{
sprintf(t_mac_addr,"\n\rHardware address is %02x:%02x:%02x:%02x:%02x:%02x",
t_mac_buf[0],t_mac_buf[1],t_mac_buf[2],
t_mac_buf[3],t_mac_buf[4],t_mac_buf[5]);
printf("\n\t %s", t_mac_addr);
}
else
{
printf("\n\t No hardware address for this interface");
}
}

while(1)
{
// Costate #1
costate
{
if(!tcp_listen(&socket_ext,PORT_EXT,0,0,NULL,0))
{
printf("\n\rERROR: Failed to open ext connection on port %d", PORT_EXT);
abort;
}

while(!sock_established(&socket_ext) && sock_bytesready(&socket_ext)==-1)
{
waitfor(DelayMs(10)); // probably can be longer
tcp_tick(NULL);
}

tcp_tick(NULL);
waitfor(DelayMs(100));
//sock_write(&socket_ext,"\r\nERROR ",sizeof("\r\nERROR ")-1);
}

// Costate #2
costate
{
start_time = MS_TIMER;

// DPM A 31 connection initialization
ip_dpm_31 = resolve(DPM_A31);
tcp_open(&socket_dpm_31, 0, ip_dpm_31, DPM_PORT, NULL);
printf("Waiting for connection DPM 31...\n");
a_count = 0;
do
{
waitfor(DelayMs(20));
a_count++;
tcp_tick(NULL);
printf("\n\t\testablish dpm socket count: %d", a_count);
} while(((!sock_established(&socket_dpm_31) && sock_bytesready(&socket_dpm_31)==-1)) && ((a_count > 0) && (a_count < 20)));
if (a_count == 20)
{
printf("Connection failed DPM ...\n");
}
else
{
printf("Connection received DPM 31...\n");
}

// Reading loop
do
{
start_time = MS_TIMER;
waitfor(DelayMs(20));

bytes_read_31 = 0;
write_status = 0;
write_status = sock_write(&socket_dpm_31,"*1B1\r\l",sizeof("*1B1\r\l")-1);
tcp_tick(NULL);
if (write_status == -1)
{
printf("\n\rERROR on socket: Unabled to write to socket, will try again...");
waitfor(DelayMs(500));
write_status = 0;
tcp_tick(NULL);
write_status = sock_write(&socket_dpm_31, "*1B1\r\l", sizeof("*1B1\r\l") - 1);
if(write_status == -1)
{
printf("\n\r=== ERROR on socket: Unabled to write to socket on retry");
}
}
if(write_status != -1)
{
a_count = 0;
do
{
tcp_tick(NULL);
waitfor(DelayMs(20));
temp_bytes_31 = sock_bytesready(&socket_dpm_31);
a_count++;
} while ((temp_bytes_31 == -1) && (a_count < 10));

bytes_read_31 = sock_fastread(&socket_dpm_31,buffer31,sizeof(buffer31)-1);
}
if(bytes_read_31 > 0)
{
buffer31[bytes_read_31]=0;
}
else // MODIFIED FOR TEST
{
error_count = error_count + 1;
mktm(&t, dc_timestamp);
printf("\n\r%02d:%02d:%02d\n", t.tm_hour, t.tm_min, t.tm_sec);
printf("\n\t\t== buffer31 bytes read: %d", bytes_read_31);
}

if(active_loop_count > 10000)
{
active_loop_count = 0;
}
else
{
active_loop_count = active_loop_count + 1;
if(active_loop_count % 23 == 0)
{
printf("\r\nERROR_COUNT = %d\r\n", error_count);
}
}
} while(1);

sock_close(&socket_dpm_31);
waitfor(DelayMs(50)); // Make sure the socket is completely closed
} // end costate fast DPM bank A

} // end while
}
answered May 31, 2016 by phungd New to the Community (3 points)
...