Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Revision:
26:dc3e7f96338f
Parent:
25:d63125298eb3
Child:
27:26c168f5aa97
--- a/Socket/bsd/stack_endpoint.cpp	Tue Jun 11 23:28:50 2013 +0000
+++ b/Socket/bsd/stack_endpoint.cpp	Sat Jun 15 18:38:26 2013 +0000
@@ -10,444 +10,311 @@
 #include "cmsis_os.h"
 #include "mbed.h"
 #include "Socket.h"
+#include "Mutex.h"
 
 //#define ptsock_dbg printf
 #define ptsock_dbg(...)
 
 int in_the_stack = 0;
+Mutex *PicoTcpLock;
+Queue<void,10> *PicoTcpEvents;
 
 
 static Thread * serverThread = NULL;
-// global queue for open requests
-Queue<struct picotcp_socketcall,10> picotcp_socketcall_queue;
-Queue<struct stack_endpoint,10> picotcp_socketcall_response_queue;
+
+#define pt_proxy_dbg(...) 
+
+/* Testing ng blocking mechanism */
 
-static inline void sendOpenResponse(struct stack_endpoint * arg)
-{
-    picotcp_socketcall_response_queue.put(arg);
-}
+/* 
+ * backend of select function, used in blocking (like picotcp_read()...) 
+ * calls. Sleeps on the message queue 
+ * 
+ *
+ * WARNING: PicoTcpLock (big stack lock) must be acquired before entering this.
+ */
 
-static inline uint16_t readSocketCommand(struct stack_endpoint * endp)
+static inline int __critical_select(struct stack_endpoint *ep, uint32_t time)
 {
-    osEvent event = endp->CallActivateQueue->get(0); // Tx for Client, Rx for Me, non blocking
-    if(event.status == osEventMessage)
-        return *((uint16_t *)event.value.p);
-    return NO_COMMAND;
-}
-
-static inline void sendSocketResponse(struct stack_endpoint *endp)
-{
-    endp->CallResponseQueue->put(endp);
+  int retval = 0;
+  uint16_t ev = ep->revents;
+  uint32_t in_time = PICO_TIME_MS();
+  
+  PicoTcpLock->unlock();
+  while ((ep->events & ep->revents) == 0) {
+    ep->queue->get(time);
+    if ((time != osWaitForever) && (PICO_TIME_MS() > in_time + time)) {
+        printf("TIMEOUT in critical select... (ev:%04x rev:%04x \n", ep->events, ep->revents);
+        PicoTcpLock->lock();
+        return 0;
+    }
+  }
+  PicoTcpLock->lock();
+  return 1;
 }
 
-static int stack_compare(void *ka, void *kb)
-{
-  struct stack_endpoint *a = (struct stack_endpoint *)ka, *b = (struct stack_endpoint *)kb;
-  if (a->s < b->s)
-    return -1;
-  if (a->s > b->s)
-    return 1;
-  return 0;
-}
-
-PICO_TREE_DECLARE(stack_ep_tree, stack_compare);
-
-static struct stack_endpoint *GET_SOCK_BY_PICOSOCK(struct pico_socket *s)
+static void wakeup(uint16_t ev, struct pico_socket *s)
 {
-  struct stack_endpoint test;
-  test.s = s;  
-  return (struct stack_endpoint *)pico_tree_findKey(&stack_ep_tree, &test);
-}
+  struct stack_endpoint *ep = (struct stack_endpoint *)s->priv;
+  if (!ep) {
+    printf("WAKEUP: no socket :(\n");
+    return;
+  }
+  ep->revents |= ev;
 
-static void stack_Add(struct stack_endpoint *ep)
-{
-  pico_tree_insert(&stack_ep_tree, ep);
-}
-
-static void stack_Del(struct stack_endpoint *ep)
-{
-  pico_tree_delete(&stack_ep_tree, ep);
-}
-
-static void status_pending_off(struct stack_endpoint *ep)
-{
-    //ep->pending = NO_COMMAND; //no event
+  if ((ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN)) {
+    ep->connected = 0;
+  }
+  if ((ev & PICO_SOCK_EV_CONN) || (ev & PICO_SOCK_EV_RD)) {
+      ep->connected = 1;
+  }
+  ep->queue->put((void *)0);
 }
 
 
-
-
-static int send_wakeup(struct stack_endpoint *ep)
+struct stack_endpoint *picotcp_socket(uint16_t net, uint16_t proto, uint16_t timeout)
 {
-  int ret = 0;
-  if (ep->pending == NO_COMMAND)
-    return -1;
-  ep->retval = 1;
-  // send response
-  sendSocketResponse(ep);
-  return ret;
+  struct stack_endpoint *ep = (struct stack_endpoint *)pico_zalloc(sizeof(struct stack_endpoint));
+  uint16_t p_net = ((net == AF_INET6)?PICO_PROTO_IPV6:PICO_PROTO_IPV4);
+  uint16_t p_proto = ((proto == SOCK_DGRAM)?PICO_PROTO_UDP:PICO_PROTO_TCP);
+  PicoTcpLock->lock();
+  ep->s = pico_socket_open( p_net, p_proto, &wakeup );
+  if (ep->s == NULL) {
+    delete(ep->queue);
+    pico_free(ep);
+    ep = NULL;
+    printf("Error opening socket!\n");
+  } else {
+    ep->s->priv = ep;
+    ep->queue = new Queue<void,1>();
+  }
+  PicoTcpLock->unlock();
+  return ep;
 }
 
 
-
-static int send_retval(struct stack_endpoint *ep, int retval)
+int picotcp_state(struct stack_endpoint *ep)
 {
-  int ret = 0;
-  if (ep->pending == NO_COMMAND)
-    return -1;
-  ep->retval = retval;
-  // send queue
-  sendSocketResponse(ep);
-  status_pending_off(ep);
+/* TODO: return one of:
+    SOCK_OPEN,
+    SOCK_BOUND,
+    SOCK_LISTEN,
+    SOCK_CONNECTED,
+    SOCK_CLOSED
+*/
+    return ep->state;
+}
+
+int picotcp_bind(struct stack_endpoint *ep, struct sockaddr *_local_addr, socklen_t len)
+{
+  int ret;
+  struct sockaddr_in *local_addr;
+  local_addr = (struct sockaddr_in *)_local_addr;
+  
+  PicoTcpLock->lock();
+  ret = pico_socket_bind(ep->s, (struct pico_ip4 *)(&local_addr->sin_addr.s_addr), &local_addr->sin_port);
+  PicoTcpLock->unlock();
   return ret;
 }
 
-static int send_error(struct stack_endpoint *ep)
-{
-  ep->code  = pico_err;
-  return send_retval(ep, -1);
-}
-static void set_timer(struct stack_endpoint *ep)
+int picotcp_listen(struct stack_endpoint *ep, int queue)
 {
-  if (ep->timeout == osWaitForever)
-    return;
-
-  if (ep->t_call == 0) {
-    ep->t_call = PICO_TIME_MS();
-    ep->t_expire = ep->t_call + ep->timeout;
-  }
+  int ret;
+  PicoTcpLock->lock();
+  ret = pico_socket_listen(ep->s, queue);
+  PicoTcpLock->unlock();
+  return ret;
 }
 
-static void check_timer_expired(struct stack_endpoint *ep)
+int picotcp_connect(struct stack_endpoint *ep, struct sockaddr *_srv_addr, socklen_t len)
 {
-  if (ep->timeout == osWaitForever)
-    return; /* never */
-
-  if (ep->t_expire < PICO_TIME_MS()) {
-    ep->retval = 0;
-    sendSocketResponse(ep);
-  }
-}
-
-
-static void retry_connect(struct stack_endpoint *ep)
-{
+  int retval;
+  struct sockaddr_in *srv_addr;
+  srv_addr = (struct sockaddr_in *)_srv_addr;
+  PicoTcpLock->lock();
+  pico_socket_connect(ep->s, (struct pico_ip4 *)(&srv_addr->sin_addr.s_addr), srv_addr->sin_port);
+  ep->events = PICO_SOCK_EV_CONN | PICO_SOCK_EV_ERR;
+  __critical_select(ep, osWaitForever);
   if ((ep->revents & PICO_SOCK_EV_CONN) && ep->connected) {
     ep->revents &= (~PICO_SOCK_EV_CONN);
     ep->revents |= PICO_SOCK_EV_WR;
     ptsock_dbg("Established. sock state: %x\n", ep->s->state);
-    send_retval(ep, 0);
-  }else {
-    pico_socket_connect(ep->s, &ep->addr, ep->port);
-    ep->events |= PICO_SOCK_EV_CONN;
+    retval = 0;
+  } else {
+    retval = -1;
   }
+  PicoTcpLock->unlock();
+  return retval;
 }
 
-static void retry_accept(struct stack_endpoint *ep)
+struct stack_endpoint *picotcp_accept(struct stack_endpoint *ep, struct sockaddr *_cli_addr, socklen_t *len)
 {
-  struct pico_ip4 peer ={};
-  uint16_t port = 0;
-  
-  struct stack_endpoint *aep;
-  struct pico_socket *sa;
-  set_timer(ep); 
+  int retval;
+  struct stack_endpoint *aep = (struct stack_endpoint *) pico_zalloc(sizeof(struct stack_endpoint));
+  struct sockaddr_in *cli_addr = (struct sockaddr_in *)_cli_addr;
+  if (!aep)
+    return aep;
+  PicoTcpLock->lock();
+  ep->events = PICO_SOCK_EV_CONN | PICO_SOCK_EV_ERR;
+  __critical_select(ep, osWaitForever);
   if (ep->revents & PICO_SOCK_EV_CONN) {
-    ptsock_dbg("Incoming connection...\n");
-    sa = pico_socket_accept(ep->s, &peer.addr, &port);
-    if (sa) {
-      ptsock_dbg("Accepted!\n");
-      aep = (struct stack_endpoint *)pico_zalloc(sizeof(struct stack_endpoint));
-      if (!aep) {
-        send_error(ep);
-        return;
-      }
-      
-      aep->sock_fd = (uint16_t)pico_rand();
-      aep->s = sa;
-      aep->connected = 1;
-      aep->peer = peer;
-      aep->peer_port = port;
-      aep->addr = ep->addr;//copy parent's address
-      aep->port = ep->port;
-      aep->pending = NO_COMMAND;
-      aep->revents |= PICO_SOCK_EV_WR;
-      ep->revents &= (~PICO_SOCK_EV_CONN);
-      aep->CallResponseQueue = new Queue<struct stack_endpoint,2>();
-      aep->CallActivateQueue = new Queue<struct stack_endpoint,2>();
-      aep->state = SOCK_CONNECTED;
-      stack_Add(aep);
-      ep->retval = 0;
-      ep->CallResponseQueue->put(aep);
-    } else {
-      send_error(ep);
-    }
-    return;
+    aep->s = pico_socket_accept(ep->s, (struct pico_ip4 *)(&cli_addr->sin_addr.s_addr), &cli_addr->sin_port);
+    ep->revents &= (~PICO_SOCK_EV_CONN);
+    aep->revents |= PICO_SOCK_EV_WR;
+    aep->s->priv = aep;
+    aep->queue = new Queue<void,1>();
+    *len = sizeof(struct sockaddr_in);
+    ptsock_dbg("Established. sock state: %x\n", aep->s->state);
+  } else {
+    pico_free(aep);
+    aep = NULL;
   }
-  ep->events |= PICO_SOCK_EV_CONN;
-  check_timer_expired(ep);
-}
-
-static void retry_close(struct stack_endpoint *ep)
-{
-  if (ep) {
-    pico_socket_close(ep->s);
-    send_retval(ep, 0);
-    stack_Del(ep);
-  }
+  PicoTcpLock->unlock();
+  return aep;
 }
 
-static void retry_write(struct stack_endpoint *ep)
+int picotcp_select(struct stack_endpoint *ep, struct timeval *timeout, int read, int write)
 {
-
-  if (ep->pending == NO_COMMAND)
-    return;
-
-  if (!ep->buffer) {
-    send_error(ep);
-    return;
+  int ret;
+  ep->timeout |= timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+  ep->events = PICO_SOCK_EV_ERR;
+  ep->events |= PICO_SOCK_EV_FIN;
+  ep->events |= PICO_SOCK_EV_CLOSE;
+  ep->events |= PICO_SOCK_EV_CONN;
+  if (read) {
+    ep->events |= PICO_SOCK_EV_RD;
   }
-
-  if (ep->pending == TOK_SENDTO) {    
-    ep->size = pico_socket_sendto(ep->s, ep->buffer, ep->size, &ep->addr, ep->port);
-  } else {
-    ep->size = pico_socket_write(ep->s, ep->buffer, ep->size);
-  }
-  ep->revents &= (~PICO_SOCK_EV_WR);
-  if (ep->size < 0)
-    send_error(ep);
-  else if (ep->size > 0)
-    send_retval(ep, ep->size);
-  else {
+  if (write)
     ep->events |= PICO_SOCK_EV_WR;
-    return;
-  }
+  ret = __critical_select(ep, ep->timeout);
+  return ret;
 }
 
-static void retry_read(struct stack_endpoint *ep)
+int picotcp_send(struct stack_endpoint *ep,void * buff, int len, int flags)
 {
-  int len;
-  if (ep->pending == NO_COMMAND)
-    return;
-
-  ptsock_dbg("in retry-read, len: %d \n", len);
-  
-  
-  
-  if (!ep->buffer) {
-    send_error(ep);
-    return;
-  } else {
-    if (ep->pending == TOK_RECVFROM)
-      len = pico_socket_recvfrom(ep->s, ep->buffer, ep->size, &ep->addr, &ep->port);
-    else {
-      len = pico_socket_read(ep->s, ep->buffer, ep->size);
-    }
-  }
-  
-  if (ep->size > len)
-    ep->revents &= (~PICO_SOCK_EV_RD);
-  
-  if (len == 0) {
-    ptsock_dbg("Read returned 0.");
-    ep->events |= PICO_SOCK_EV_RD;
-    return;
-  } 
-  send_retval(ep, len);
+  /* TODO */
+  return -1;
 }
 
-void retry_poll(struct stack_endpoint *ep)
+int picotcp_recv(struct stack_endpoint *ep,void * buff, int len, int flags)
 {
-  if (ep->pending == NO_COMMAND)
-    return;
-
-  set_timer(ep);
+  /* TODO */
+  return -1;
+}
 
-  if ((ep->events & ep->revents) != 0) {
-    send_retval(ep, 1);
-    return;
-  }
-
-  check_timer_expired(ep);
+int picotcp_sendto(struct stack_endpoint *ep,void * buff, int len, struct sockaddr *a, socklen_t l)
+{
+  /* TODO */
+  return -1;
 }
 
-static void retry_token(struct stack_endpoint *ep)
+int picotcp_recvfrom(struct stack_endpoint *ep,void * buff, int len, struct sockaddr *a, socklen_t *l)
 {
-  if (ep->pending == NO_COMMAND)
-    return;
-  ptsock_dbg("in retry-token, cmd: %04x\n", ep->pending);
-  switch(ep->pending) {
-    case TOK_POLL:
-      retry_poll(ep);
-      break;
-    case TOK_CONNECT:
-      retry_connect(ep);
-      break;
-    case TOK_ACCEPT:
-      retry_accept(ep);
-      break;
-
-    case TOK_READ:
-    case TOK_RECV:
-    case TOK_RECVFROM:
-      retry_read(ep);
-      break;
-
-    case TOK_WRITE:
-    case TOK_SEND:
-    case TOK_SENDTO:
-      retry_write(ep);
-      break;
-
-    case TOK_CLOSE:
-      retry_close(ep);
-      break;
-    default:
-      break;
-    }
+  /* TODO */
+  return -1;
 }
 
-static void wakeup(uint16_t ev, struct pico_socket *s)
+int picotcp_read(struct stack_endpoint *ep,void *buf, int len)
 {
-  int t;
-  struct stack_endpoint *ep = GET_SOCK_BY_PICOSOCK(s);
-  
-  if (!ep) {
-    ptsock_dbg("WAKEUP: no socket :(\n");
-    return;
+  int retval = 0;
+  int tot_len = 0;
+  if (!buf || (len <= 0))
+     return  0;
+  PicoTcpLock->lock();
+  while (tot_len < len) {
+    retval = pico_socket_read(ep->s, ((uint8_t *)buf) + tot_len ,  len - tot_len);
+    if (retval <= 0) {
+        ep->revents &= ~PICO_SOCK_EV_RD;
+        break;
+    }
+    tot_len += retval;
   }
-  t = ep->pending;
-  ptsock_dbg("Wake up event: %04x\n", ev);
-  ep->revents |= ev;
-  
-  
-  
-  if (ev & (PICO_SOCK_EV_CLOSE | PICO_SOCK_EV_FIN)){
-    printf("** CLOSE\n");
-    ep->connected = 0;
-  }
-  
-  if (ev & PICO_SOCK_EV_ERR) {
-    ep->revents = PICO_SOCK_EV_ERR;
-    send_error(ep);
-    return;
-  }
-  
-  if ((ev & PICO_SOCK_EV_CONN) || (ev & PICO_SOCK_EV_RD)) {
-    if ((ev & PICO_SOCK_EV_CONN) && ((ep->pending == TOK_CONNECT) || (ep->pending == TOK_ACCEPT))) {
-      printf("** Connected\n");
-      ep->connected = 1;
-    }
-  }
-  ep->revents = ev;  
-  if ( (ep->pending != 0) && ((ep->events & ep->revents)!=0) )
-    retry_token(ep);
+  PicoTcpLock->unlock();
+  return tot_len;
 }
 
-static int stack_parse_requests(void)
+int picotcp_write(struct stack_endpoint *ep,void *buf, int len)
 {
-  struct stack_endpoint *ep = NULL;
-  struct picotcp_socketcall *skc;
-  osEvent event; // used to see the status of queue get
-  struct pico_tree_node * index = NULL;
-  uint16_t proto,net;
-  int ret = 0;
-  int yes = 1;
-  // first check if the global queue has something in it
-  // and open a new socket if so
-  do
-  {
-    stack_endpoint *stack_ep = NULL;
-    
-    event = picotcp_socketcall_queue.get(0); // non blocking get
-    if(event.status == osEventMessage) {
-        ret = 1;
-        // Get the arguments
-        skc = (struct picotcp_socketcall *)event.value.p;
-    
-        // open new socket and send the response
-        stack_ep = (struct stack_endpoint *)pico_zalloc(sizeof(struct stack_endpoint));
-        if(!stack_ep)
-        {
-            ptsock_dbg("Out of memory\n");
-            return -1;
-        }
-        stack_ep->CallActivateQueue = new Queue<struct stack_endpoint,2>();
-        stack_ep->CallResponseQueue = new Queue<struct stack_endpoint,2>();
+  int retval = 0;
+  int tot_len = 0;
+  if (!buf || (len <= 0))
+     return  0;
+  PicoTcpLock->lock();
+  while (tot_len < len) {
+    retval = pico_socket_write(ep->s, ((uint8_t *)buf) + tot_len ,  len - tot_len);
+    if (retval <= 0) {
+        ep->revents &= ~PICO_SOCK_EV_WR;
+        break;
+    }
+    tot_len += retval;
+    picotcp_async_interrupt();
+  }
+  PicoTcpLock->unlock();
+  return tot_len; 
+}
 
-        net = ((skc->family == AF_INET6)?PICO_PROTO_IPV6:PICO_PROTO_IPV4);
-        proto = ((skc->proto == SOCK_DGRAM)?PICO_PROTO_UDP:PICO_PROTO_TCP);
-        stack_ep->s = pico_socket_open( net, proto, &wakeup );
-        
-        if (!stack_ep->s)
-            stack_ep->retval = -1;
-        //pico_socket_setoption(stack_ep->s, PICO_SOCKET_OPT_TCPNODELAY, &yes);
 
-        //stack_ep->pending = NO_COMMAND;  
-        stack_Add(stack_ep);
-        // send the response back to the client
-        sendOpenResponse(stack_ep);
-        ptsock_dbg("New socket added: %p\n", stack_ep->s);
-    }
-  }while(event.status == osEventMessage); 
+int picotcp_setsockopt(struct stack_endpoint *ep, int option, void *value)
+{
+  /* TODO */
+  return -1;
+}
+
+int picotcp_getsockopt(struct stack_endpoint *ep, int option, void *value)
+{
+  /* TODO */
+  return -1;
+}
 
-  // go through all the sockets and check if there is a request from someone
-  // call to the get function has timeout 0, must be non blocking
-  // if a request has come from someone parse it
-  pico_tree_foreach(index,&stack_ep_tree)
-  {
-    ep = (struct stack_endpoint *)index->keyValue;
-    // check if data has arrived
-    event = ep->CallActivateQueue->get(0); // again non blocking
-    if(event.status == osEventMessage)
-    {
-        ret = 1;
-        //printf("Socket contacted. CMD: %X\n", ep->pending);
-        // check command sent
-        switch(ep->pending)
-        {
-            case TOK_BIND:
-              if(pico_socket_bind(ep->s, &ep->addr, &ep->port) == 0) {
-                ptsock_dbg("stack: bind success (addr: %08x, port %d)!\n", ep->addr.addr, ep->port);
-                send_retval(ep, 0);
-              } else {
-                ptsock_dbg("stack: bind error (pico_s: %p, addr: %08x, port %d err: %d)!\n", ep->s, ep->addr.addr, ep->port, pico_err);
-                send_error(ep);
-              }
-              break;
-            case TOK_LISTEN:
-              if(pico_socket_listen(ep->s, ep->size) == 0)
-                send_retval(ep, 0);
-              else
-                send_error(ep);
-              break;
-            default:
-              retry_token(ep);  
-        }
-        break;
-     }
-  }
-  return ret;
+int picotcp_close(struct stack_endpoint *ep)
+{
+  PicoTcpLock->lock();
+  pico_socket_close(ep->s);
+  ep->s->priv = NULL;
+  printf("Socket closed!\n");
+  delete(ep->queue);
+  pico_free(ep);
+  PicoTcpLock->unlock();
 }
 
+int picotcp_join_multicast(struct stack_endpoint *ep,const char* address,const char* local)
+{
+  /* TODO */
+  return -1;
+}
+
+
+
 void pico_wrapper_loop(const void * arg)
 {
   (void)arg;
   int ret = 0;
   while(1) {
-    ret = stack_parse_requests();
-    pico_stack_tick();
-    //Thread::wait(1);
-    Thread::wait(1);
+    PicoTcpEvents->get(2);
+    if (PicoTcpLock->trylock()) {
+      pico_stack_tick();
+      PicoTcpLock->unlock();
+    }
   }
 }
 
 void picotcp_start(void)
 {
-  Ticker *picotcpTicker = new Ticker();
   if (serverThread == NULL) {
+    PicoTcpLock = new Mutex();
+    PicoTcpEvents = new Queue<void,10>();
     printf (" *** PicoTCP initialized *** \n");
     serverThread = new Thread(pico_wrapper_loop);
     serverThread->set_priority(osPriorityIdle);
-    //picotcpTicker->attach(&pico_stack_tick, 0.001);
   }
 }
+
+void picotcp_init(void)
+{
+  picotcp_start(); 
+}
+
+int picotcp_async_interrupt(void)
+{
+    PicoTcpEvents->put((void *)0);
+}
\ No newline at end of file