This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Can I use both TCP native sockets and BSD sockets?

First of all, I'm using RL-NET V4 Legacy, MDK 5.25. And the uC I am using is the ARM7 LPC2468.

The system I'm programming uses "a lot" of sockets. It has:

- Default TCPNET HTTP server up to 3 sessions;
- Default TCPNET FTP server 1 session;
- A custom server for custom communications - up to 30 client TCPNET socket connections (Maintained by "Custom Comm" Task);
- 1 TCPNET UDP socket for logging messages through the network to a specific logging app (logs from several tasks!);
- 1 Default TCPNET DNS client.

And it has 2 BSD sockets:

- 1 BSD TCP socket for SQL querying (Maintained by "Database Querying" Task);
- 1 BSD TCP socket for Internet communications / RESTful (Maintained by "Replication" Task);

All the TCPNET native sockets are used within the WebMain Task, and they are maintained through events/mailboxes shared between the WebMain Task and the other Tasks.
In contrast with that, each BSD socket is used within each individual task, not in the WebMain Task.

The documentation just says that TCPNET NATIVE sockets must be dealt with in the Web Main Task, since it's functions are non-reentrant. 
Meanwhile, it says the BSD sockets support concurrency. It also says that BSD sockets are based on the TCP native sockets. 

The reason I use both BSD and TCP native sockets is because in the beginning the development used only TCP native sockets, then we realised that for other new tasks it was easier to do by using BSD sockets.

But the question is, can I use both? Or I must stick with one of the them?

Parents
  • The problem is that, before this, we were using the TCP native sockets and using them inside concurrent tasks instead of inside the Main TCP Task, which was really wrong! And in top of that we were also using BSD sockets in other tasks... we were having troubles with the system getting the ethernet stuck, like if the memory was fragmented but sometimes part of it was released, and we got the ethernet unstuck for a few seconds before it got stuck again... we were also having ETH MEM LOCKS sporadically.

    With these problems, we've changed all the TCP native sockets to be manipulated only inside the Main TCP Task.
    The BSD sockets are still being used in other Tasks. It seems that the problem was attenuated!

    Unfortunately, we're still having an issue!
    The problem is that we're still getting the error ETH_MEM_LOCK after several hours of runtime - last time it took 24 hours for this to happen.

    For what we know, ETH_MEM_LOCK stands for:

    /* Locked Memory management function (alloc/free) re-entered. */
    /* RTX multithread protection malfunctioning, not implemented */
    /* or interrupt disable is not functioning correctly. */

    However, as I said, we're using TCP native only inside the Main TCP Task. And the BSD sockets are used outside, in other tasks.
    As assumed, this should work, right? 

    Now there's only one TCP Native socket, which its purpose is logging messages from tasks through UDP socket.
    The rest of the sockets are all BSD.
    The routines we call for the BSD sockets are:

    - socket();
    - closesocket();
    - connect();
    - ioctlsocket();
    - send();
    - recv();
    - sendto();
    - recvfrom();
    - bind();
    - accept();
    - listen();

    Below there is most part of the code we're using today for the TCP Native sockets.
    At the end I've also added the ETH interrupt.

    @Edit: we are also using HTTP and FTP native servers

    // File webmain.c -- Main TCP Task
    extern int logger_task(void);
    extern void logger_task_init(void);
    
    static __task void web_main_task(void) {
        dhcp_disable();
        os_evt_clr(0xFFFF, os_tsk_self());
    	logger_task_init(); // initialize mailbox for logging messages
    	
        while (1) {
            os_evt_wait_or(1, 0xFFFF); // event set on web_tick_task (100ms) and ethernet interrupt (driver)
    		
    		BOOL tcpNetPend = __TRUE;
    		int loggerPend = 1;
    		while (tcpNetPend || loggerPend) {
    			loggerPend = logger_func();
    			tcpNetPend = main_TcpNet();
    		}
    		
    		// Event from http (button 'reset' clicked)
            if (os_evt_wait_and(WEB_FORCE_RESET, 0) == OS_R_EVT) {
                os_evt_clr(0xFFFF, os_tsk_self());
                soft_reset();
            }
        }
    }
    
    ...
    ...
    
    // File dbg_udp.c
    
    // dbgPrint() -- Function that is used to insert message on mailbox from other Tasks
    
    int logger_func(void) {
        logger_message_t *pmsg = NULL;
    	if (os_mbx_wait(&logger_mail, (void*)&pmsg, 0) != OS_R_TMO) {
    		if (pmsg != NULL) {
    			dbg_udp_send(pmsg->c, pmsg->str, pmsg->len); // socket, udp_get_buf() and udp_send()
    			_free_box(logger_box, pmsg);
    			pmsg = NULL;
    		}
    	}
    	return os_mbx_check(&logger_mail) != LOGGER_MESSAGE_MAX;
    }
    
    static int _started = 0;
    static U8 _sock = 0;
    static int _sendfail = 0;
    
    static U16 __dbg_udp_callback(U8 sock, U8 *remip, U16 remp, U8 *buf, U16 len) {
        return 0;
    }
    
    void dbg_udp_init(void) {
        if (!_started) {
            if (!_sock)
                _sock = udp_get_socket(0, UDP_OPT_SEND_CS, __dbg_udp_callback);
            if (_sock)
                _started = udp_open(_sock, 4301);
        }
    }
    
    void dbg_udp_send(int c, char *msg, uint32_t len) {
        dbg_udp_init();
    	if (_sendfail)
    		len++;
        if (_started && msg != NULL && len > 0) {
            if (len >= DBG_BUF_MAX)
                len = DBG_BUF_MAX-1;
            U8 *buf = udp_get_buf(len | 0x8000);
            if (buf != NULL) {
    			if (_sendfail) {
    				mem_copy(buf, (void*)msg, len-1);
    				buf[len-1] = '!';
    			}
    			else {
    				mem_copy(buf, (void*)msg, len);
    			}
    			__dbg_cript((char*)buf, len); // only cripts each byte of the buffer
    			_sendfail = 0;
                udp_send(_sock, (U8[]){ 255, 255, 255, 255 }, 4303,
                    buf, len);
            }
    		else {
    			_sendfail = 1;
    		}
        }
    }
    
    ...
    ...
    
    // File EMAC_LAN8720.c -- Eth driver
    
    // #define DRIVER_EMAC_FILTER_EN -- Enables or disables filtering of MAC Address
    
    static void interrupt_ethernet (void) __irq {
      /* EMAC Ethernet Controller Interrupt function. */
      OS_FRAME *frame;
      U32 idx,int_stat,RxLen,info;
      U32 *sp,*dp;
    #if DRIVER_EMAC_FILTER_EN
      extern U8 own_hw_adr[];
      struct __ethernet_header *eh = NULL;
      int process_eth_buf;
      uint8_t broadcast_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
    #endif
    
      while ((int_stat = (MAC_INTSTATUS & MAC_INTENABLE)) != 0) {
        MAC_INTCLEAR = int_stat;
        if (int_stat & INT_RX_DONE) {
          /* Packet received, check if packet is valid. */
          idx = MAC_RXCONSUMEINDEX;
          while (idx != MAC_RXPRODUCEINDEX) {
            info = Rx_Stat[idx].Info;
            if (!(info & RINFO_LAST_FLAG)) {
              goto rel;
            }
            RxLen = (info & RINFO_SIZE) - 3;
            if (RxLen > ETH_MTU || (info & RINFO_ERR_MASK)) {
              /* Invalid frame, ignore it and free buffer. */
              goto rel;
            }
    #if DRIVER_EMAC_FILTER_EN
    		process_eth_buf = 0;
    		eh = (struct __ethernet_header *)Rx_Desc[idx].Packet;
    		if (mem_comp(eh->destination, own_hw_adr, ETH_ADRLEN) == 0) {
    			process_eth_buf = 1;
    	    }
    		else if (mem_comp(eh->destination, broadcast_mac, ETH_ADRLEN) == 0) {
    			process_eth_buf = 1;
    		}
    		if (process_eth_buf == 1) {
    #endif
    			/* Flag 0x80000000 to skip sys_error() call when out of memory. */
    			frame = alloc_mem (RxLen | 0x80000000);
    			/* if 'alloc_mem()' has failed, ignore this packet. */
    			if (frame != NULL) {
    			  dp = (U32 *)&frame->data[0];
    			  sp = (U32 *)Rx_Desc[idx].Packet;
    			  for (RxLen = (RxLen + 3) >> 2; RxLen; RxLen--) {
    				*dp++ = *sp++;
    			  }
    			  put_in_queue (frame);
    			  isr_evt_set(1, wmain_tid);
    			}
    #if DRIVER_EMAC_FILTER_EN
    		}
    #endif
    rel:    if (++idx == NUM_RX_FRAG) idx = 0;
            /* Release frame from EMAC buffer. */
            MAC_RXCONSUMEINDEX = idx;
          }
        }
        if (int_stat & INT_TX_DONE) {
          /* Frame transmit completed. */
        }
      }
      /* Acknowledge the interrupt. */
      VICVectAddr = 0;
    }
    
    void sys_error (ERROR_CODE code) {  
      except_params_t params = {0};
      params[0] = isr_tsk_get();
      
      switch (code) {
        case ERR_MEM_LOCK:
          /* Locked Memory management function (alloc/free) re-entered. */
          /* RTX multithread protection malfunctioning, not implemented */
          /* or interrupt disable is not functioning correctly. */
          except_add(EXCEPT_ETH_MEM_LOCK, params);
          break;
        
        // others cases are implemented
        // they were removed to reduce the question
      }
      // wdt force reset
      soft_reset();
    }
    ...
    ...

Reply
  • The problem is that, before this, we were using the TCP native sockets and using them inside concurrent tasks instead of inside the Main TCP Task, which was really wrong! And in top of that we were also using BSD sockets in other tasks... we were having troubles with the system getting the ethernet stuck, like if the memory was fragmented but sometimes part of it was released, and we got the ethernet unstuck for a few seconds before it got stuck again... we were also having ETH MEM LOCKS sporadically.

    With these problems, we've changed all the TCP native sockets to be manipulated only inside the Main TCP Task.
    The BSD sockets are still being used in other Tasks. It seems that the problem was attenuated!

    Unfortunately, we're still having an issue!
    The problem is that we're still getting the error ETH_MEM_LOCK after several hours of runtime - last time it took 24 hours for this to happen.

    For what we know, ETH_MEM_LOCK stands for:

    /* Locked Memory management function (alloc/free) re-entered. */
    /* RTX multithread protection malfunctioning, not implemented */
    /* or interrupt disable is not functioning correctly. */

    However, as I said, we're using TCP native only inside the Main TCP Task. And the BSD sockets are used outside, in other tasks.
    As assumed, this should work, right? 

    Now there's only one TCP Native socket, which its purpose is logging messages from tasks through UDP socket.
    The rest of the sockets are all BSD.
    The routines we call for the BSD sockets are:

    - socket();
    - closesocket();
    - connect();
    - ioctlsocket();
    - send();
    - recv();
    - sendto();
    - recvfrom();
    - bind();
    - accept();
    - listen();

    Below there is most part of the code we're using today for the TCP Native sockets.
    At the end I've also added the ETH interrupt.

    @Edit: we are also using HTTP and FTP native servers

    // File webmain.c -- Main TCP Task
    extern int logger_task(void);
    extern void logger_task_init(void);
    
    static __task void web_main_task(void) {
        dhcp_disable();
        os_evt_clr(0xFFFF, os_tsk_self());
    	logger_task_init(); // initialize mailbox for logging messages
    	
        while (1) {
            os_evt_wait_or(1, 0xFFFF); // event set on web_tick_task (100ms) and ethernet interrupt (driver)
    		
    		BOOL tcpNetPend = __TRUE;
    		int loggerPend = 1;
    		while (tcpNetPend || loggerPend) {
    			loggerPend = logger_func();
    			tcpNetPend = main_TcpNet();
    		}
    		
    		// Event from http (button 'reset' clicked)
            if (os_evt_wait_and(WEB_FORCE_RESET, 0) == OS_R_EVT) {
                os_evt_clr(0xFFFF, os_tsk_self());
                soft_reset();
            }
        }
    }
    
    ...
    ...
    
    // File dbg_udp.c
    
    // dbgPrint() -- Function that is used to insert message on mailbox from other Tasks
    
    int logger_func(void) {
        logger_message_t *pmsg = NULL;
    	if (os_mbx_wait(&logger_mail, (void*)&pmsg, 0) != OS_R_TMO) {
    		if (pmsg != NULL) {
    			dbg_udp_send(pmsg->c, pmsg->str, pmsg->len); // socket, udp_get_buf() and udp_send()
    			_free_box(logger_box, pmsg);
    			pmsg = NULL;
    		}
    	}
    	return os_mbx_check(&logger_mail) != LOGGER_MESSAGE_MAX;
    }
    
    static int _started = 0;
    static U8 _sock = 0;
    static int _sendfail = 0;
    
    static U16 __dbg_udp_callback(U8 sock, U8 *remip, U16 remp, U8 *buf, U16 len) {
        return 0;
    }
    
    void dbg_udp_init(void) {
        if (!_started) {
            if (!_sock)
                _sock = udp_get_socket(0, UDP_OPT_SEND_CS, __dbg_udp_callback);
            if (_sock)
                _started = udp_open(_sock, 4301);
        }
    }
    
    void dbg_udp_send(int c, char *msg, uint32_t len) {
        dbg_udp_init();
    	if (_sendfail)
    		len++;
        if (_started && msg != NULL && len > 0) {
            if (len >= DBG_BUF_MAX)
                len = DBG_BUF_MAX-1;
            U8 *buf = udp_get_buf(len | 0x8000);
            if (buf != NULL) {
    			if (_sendfail) {
    				mem_copy(buf, (void*)msg, len-1);
    				buf[len-1] = '!';
    			}
    			else {
    				mem_copy(buf, (void*)msg, len);
    			}
    			__dbg_cript((char*)buf, len); // only cripts each byte of the buffer
    			_sendfail = 0;
                udp_send(_sock, (U8[]){ 255, 255, 255, 255 }, 4303,
                    buf, len);
            }
    		else {
    			_sendfail = 1;
    		}
        }
    }
    
    ...
    ...
    
    // File EMAC_LAN8720.c -- Eth driver
    
    // #define DRIVER_EMAC_FILTER_EN -- Enables or disables filtering of MAC Address
    
    static void interrupt_ethernet (void) __irq {
      /* EMAC Ethernet Controller Interrupt function. */
      OS_FRAME *frame;
      U32 idx,int_stat,RxLen,info;
      U32 *sp,*dp;
    #if DRIVER_EMAC_FILTER_EN
      extern U8 own_hw_adr[];
      struct __ethernet_header *eh = NULL;
      int process_eth_buf;
      uint8_t broadcast_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
    #endif
    
      while ((int_stat = (MAC_INTSTATUS & MAC_INTENABLE)) != 0) {
        MAC_INTCLEAR = int_stat;
        if (int_stat & INT_RX_DONE) {
          /* Packet received, check if packet is valid. */
          idx = MAC_RXCONSUMEINDEX;
          while (idx != MAC_RXPRODUCEINDEX) {
            info = Rx_Stat[idx].Info;
            if (!(info & RINFO_LAST_FLAG)) {
              goto rel;
            }
            RxLen = (info & RINFO_SIZE) - 3;
            if (RxLen > ETH_MTU || (info & RINFO_ERR_MASK)) {
              /* Invalid frame, ignore it and free buffer. */
              goto rel;
            }
    #if DRIVER_EMAC_FILTER_EN
    		process_eth_buf = 0;
    		eh = (struct __ethernet_header *)Rx_Desc[idx].Packet;
    		if (mem_comp(eh->destination, own_hw_adr, ETH_ADRLEN) == 0) {
    			process_eth_buf = 1;
    	    }
    		else if (mem_comp(eh->destination, broadcast_mac, ETH_ADRLEN) == 0) {
    			process_eth_buf = 1;
    		}
    		if (process_eth_buf == 1) {
    #endif
    			/* Flag 0x80000000 to skip sys_error() call when out of memory. */
    			frame = alloc_mem (RxLen | 0x80000000);
    			/* if 'alloc_mem()' has failed, ignore this packet. */
    			if (frame != NULL) {
    			  dp = (U32 *)&frame->data[0];
    			  sp = (U32 *)Rx_Desc[idx].Packet;
    			  for (RxLen = (RxLen + 3) >> 2; RxLen; RxLen--) {
    				*dp++ = *sp++;
    			  }
    			  put_in_queue (frame);
    			  isr_evt_set(1, wmain_tid);
    			}
    #if DRIVER_EMAC_FILTER_EN
    		}
    #endif
    rel:    if (++idx == NUM_RX_FRAG) idx = 0;
            /* Release frame from EMAC buffer. */
            MAC_RXCONSUMEINDEX = idx;
          }
        }
        if (int_stat & INT_TX_DONE) {
          /* Frame transmit completed. */
        }
      }
      /* Acknowledge the interrupt. */
      VICVectAddr = 0;
    }
    
    void sys_error (ERROR_CODE code) {  
      except_params_t params = {0};
      params[0] = isr_tsk_get();
      
      switch (code) {
        case ERR_MEM_LOCK:
          /* Locked Memory management function (alloc/free) re-entered. */
          /* RTX multithread protection malfunctioning, not implemented */
          /* or interrupt disable is not functioning correctly. */
          except_add(EXCEPT_ETH_MEM_LOCK, params);
          break;
        
        // others cases are implemented
        // they were removed to reduce the question
      }
      // wdt force reset
      soft_reset();
    }
    ...
    ...

Children