OPT_KEEPALIVE Broken in RTCS 4.2? Causing idle connection to RST in RTSC 4.2, but not 4.1

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

OPT_KEEPALIVE Broken in RTCS 4.2? Causing idle connection to RST in RTSC 4.2, but not 4.1

1,464 Views
pmt
Contributor V

Greetings!

When I recently updated to RTCS 4.2.0.0 (and RTCS 4.2.0.1).  I have the OPT_KEEPALIVE property enabled on one of my "control" sockets that I am using for a home brew FTP server.

In RTCS 4.1, no issues, seems to work as intended.

In RTCS 4.2, when the control socket connection sits idle for a few minutes the server side (MQX/RTCS) the first KEEPALIVE sent ends up resetting the socket connection.  KEEPALIVE should not do this unless the remote side is gone.   Two keep alive probes from RTCS (ID=80 and 81), one keepalive response from the host , then RTCS resets the connection.

pastedImage_0.png

Any clues?!?!

PMT

Labels (1)
0 Kudos
Reply
6 Replies

956 Views
Carlos_Musich
NXP Employee
NXP Employee

HI PMT,

Workaround could be to call the setsockopt() after listen()/connect() returns.

Regards,

Carlos

0 Kudos
Reply

956 Views
Carlos_Musich
NXP Employee
NXP Employee

Hi PMT,

I am nt having issueas with OPT_KEEPALIVE.

Can you please describe how can I reproduce this behavior?

Regards,

Carlos

0 Kudos
Reply

956 Views
pmt
Contributor V

This is basically what I am doing:

Create a listening socket on the RTCS side with the following socket options:

     OPT_KEEPALIVE = 2

      OPT_TIMEWAIT_TIMEOUT = 5000

Connect to the socket (i.e. TELNET from PC).

Let the connection sit idle for the KEEPALIVE period, 2 minutes.

Connection will then reset as a result of the KEEPALIVE message.

Let me know if you can't reproduce, then I can work on creating a code snippet test case.

Thanks,

PMT

0 Kudos
Reply

956 Views
Carlos_Musich
NXP Employee
NXP Employee

Hi PMT,

it would be useful if you could share the code snippet.

Thanks!

Carlos

0 Kudos
Reply

956 Views
pmt
Contributor V

Carlos,

Test case at bottom.

Instructions:

Call ListenTask() with a port number of your choice, example ListenTask(23);

telnet to the port from a PC, "telnet x.x.x.x"

Don't any any activity on the socket... simply wait a couple minutes

The application has a keepalive of 1 minute.  It will incorrectly disconnect after this time.  Change the keepalive to 0 by changing FTPD_SOCKET_KEEPALIVE_TIMEOUT_M (0) 

Try the same as above.  Socket will not disconnect.

This only happens in RTCS4.2, but not 4.1.

#include <mqx.h>

#include <bsp.h>

#include <rtcs.h>

#define FTPD_SOCKET_WAIT_TIMEOUT_MS (5000)

#define FTPD_SOCKET_KEEPALIVE_TIMEOUT_M (1)

#define FTPD_MAX_MESSAGE_SIZE (128)

#define FTPD_SESSION_LIMIT (6)

#define FTPD_PENDING_LIMIT (3)

static const uint32_t OptValueTimeWaitTimeout  = FTPD_SOCKET_WAIT_TIMEOUT_MS;

static const uint32_t OptValueKeepAliveTimeout = FTPD_SOCKET_KEEPALIVE_TIMEOUT_M;

// Session information

typedef struct

{

  bool    Active;

  uint32_t            CtrlSocket; // Socket handle for control connection

}

FTPD_SESSION;

//-----------------------------------------------------------------------------

//

//-----------------------------------------------------------------------------

static _task_id TaskCreate(void (_CODE_PTR_ TaskPtr)(uint32_t),

  uint32_t StackSize,

  uint32_t Priority,

  const char *Name,

  uint32_t Parameter)

{

  TASK_TEMPLATE_STRUCT Task;

  memset((void *) &Task, 0, sizeof(Task));

  Task.TASK_ADDRESS   = TaskPtr;

  Task.TASK_STACKSIZE = StackSize;

  Task.TASK_PRIORITY   = Priority;

  Task.TASK_ATTRIBUTES = MQX_FLOATING_POINT_TASK;

  Task.TASK_NAME = (char *) Name;

  Task.CREATION_PARAMETER = Parameter;

  return _task_create(0,0,(uint32_t) &Task);

}

// Handle a new session

static void SessionTask(uint32_t Parameters)

{

  FTPD_SESSION *SessionPtr = (FTPD_SESSION *) Parameters;

  char cmd[FTPD_MAX_MESSAGE_SIZE];

  uint32_t count = FTPD_SOCKET_KEEPALIVE_TIMEOUT_M;

  RTCS_attachsock(SessionPtr->CtrlSocket);

  printf("Socket connected with KEEPALIVE = %u\r\n", count);

  while(1)

  {

  // read from socket and throw away data

  count = recv(SessionPtr->CtrlSocket, cmd, 1, 0);

  if (count == RTCS_ERROR) break;

  }

  printf("Socket shutting down\r\n");

  shutdown(SessionPtr->CtrlSocket, FLAG_CLOSE_TX);

  SessionPtr->Active = FALSE;

  _task_destroy(_task_get_id());

  return;

}

// Listen Socket

void ListenTask(uint32_t ListenPort)

{

  struct sockaddr_in remoteAddr, localAddr;

  FTPD_SESSION FtpdSession[FTPD_SESSION_LIMIT];

  uint16_t addrLen;

  uint32_t i, Socket, SocketNew, Priority;

  uint32_t MaxPending  = FTPD_PENDING_LIMIT;

  // Init FTPd session tracking

  for (i=0; i<FTPD_SESSION_LIMIT; i++) FtpdSession[i].Active = FALSE;

  // store the current task priority

  _task_get_priority(_task_get_id(), &Priority);

  // create TCP/IP socket

  if ( (Socket = socket(AF_INET, SOCK_STREAM, 0)) == RTCS_HANDLE_ERROR)

  {

  _task_destroy(_task_get_id());

  return;

  }

    setsockopt(Socket, SOL_TCP, OPT_KEEPALIVE,        (void *) &OptValueKeepAliveTimeout, sizeof(OptValueKeepAliveTimeout));

  setsockopt(Socket, SOL_TCP, OPT_TIMEWAIT_TIMEOUT, (void *) &OptValueTimeWaitTimeout,  sizeof(OptValueTimeWaitTimeout));

  // Bind socket to the listen port

    localAddr.sin_family      = AF_INET;

    localAddr.sin_port        = ListenPort;

    localAddr.sin_addr.s_addr = INADDR_ANY;

  if (bind(Socket, (struct sockaddr_in *) &localAddr, sizeof(localAddr)) != RTCS_OK)

  {

  shutdown(Socket, FLAG_CLOSE_TX);

  _task_destroy(_task_get_id());

  return;

  }

  // Listen on listen port

  if (listen(Socket, MaxPending) != RTCS_OK)

  {

  shutdown(Socket, FLAG_CLOSE_TX);

  _task_destroy(_task_get_id());

  return;

  }

    while(1)

  {

  // Accept new sessions

  addrLen = sizeof(remoteAddr);

  SocketNew = accept(Socket, (struct sockaddr_in *) &remoteAddr, &addrLen);

  if (SocketNew == RTCS_HANDLE_ERROR)

  {

  _time_delay(1000);

  }

  else

  {

  setsockopt(SocketNew, SOL_TCP, OPT_TIMEWAIT_TIMEOUT, (void *) &OptValueTimeWaitTimeout, sizeof(OptValueTimeWaitTimeout));

  // find a session and start the session task

  for (i=0; i<FTPD_SESSION_LIMIT; i++)

  {

  if (FtpdSession[i].Active == FALSE)

  {

  // start a new session

  memset(&(FtpdSession[i]), 0, sizeof(FtpdSession[0]));

  FtpdSession[i].Active = TRUE;

  FtpdSession[i].CtrlSocket = SocketNew;

  RTCS_detachsock(SocketNew);

  // Spawn session handler

  if (TaskCreate(SessionTask, 1024, Priority, "Session", (uint32_t) &FtpdSession[i]) == MQX_NULL_TASK_ID)

  {

  FtpdSession[i].Active = FALSE;

  shutdown(SocketNew, FLAG_CLOSE_TX);

  }

  break;

  }

  }

  // If no free session so close the connection

  if (i == FTPD_SESSION_LIMIT)

  {

  shutdown(SocketNew, FLAG_CLOSE_TX);

  }

  }

  // Limit the number of accept loops we process every second.

  _time_delay(250);

  }

}

0 Kudos
Reply

956 Views
Carlos_Musich
NXP Employee
NXP Employee

HI PMT,

thank you, I reproduced this issue and confirmed this is a bug. I reported it to MQX development team. Just for your reference the report number is MQX-5684.

I will keep you informed about the status of the issue.

We really appreciate this inputs.

Regards,

Carlos

0 Kudos
Reply