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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers stack_endpoint.cpp Source File

stack_endpoint.cpp

00001 /*********************************************************************
00002 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
00003 See LICENSE and COPYING for usage.
00004 
00005 Authors: Daniele Lacamera
00006 *********************************************************************/
00007 
00008 #include "wrapper.h"
00009 #include "rtos.h"
00010 #include "cmsis_os.h"
00011 #include "mbed.h"
00012 #include "Socket.h"
00013 #include "Mutex.h"
00014 //#include "PicoTerm.h"
00015 
00016 extern "C"
00017 {
00018     #include "pico_mbed.h"
00019     #include "pico_dns_client.h"
00020     #include "pico_dhcp_server.h"
00021 }
00022 
00023 //#define ptsock_dbg ptm_dbg
00024 #define ptsock_dbg(...)
00025 #define SCHEDULER_BASE  4u
00026 #define SCHEDULER_MAX   10
00027 
00028 int scheduler_timeout = 0;
00029 int in_the_stack = 0;
00030 Mutex *PicoTcpLock;
00031 Queue<void,32> *PicoTcpEvents;
00032 
00033 static Thread * serverThread = NULL;
00034 
00035 /* Testing ng blocking mechanism */
00036 
00037 /* 
00038  * backend of select function, used in blocking (like picotcp_read()...) 
00039  * calls. Sleeps on the message queue 
00040  * 
00041  *
00042  * WARNING: PicoTcpLock (big stack lock) must be acquired before entering this.
00043  */
00044 void picotcp_async_clean(struct pico_device * dev);
00045 static inline int __critical_select(struct stack_endpoint *ep, uint32_t time, uint8_t lock)
00046 {
00047   uint32_t in_time = PICO_TIME_MS();
00048   ptsock_dbg("Critical_select on endpoint.\n");
00049   if(lock) PicoTcpLock->unlock();
00050   while ((ep->events & ep->revents) == 0) {
00051     ep->queue->get(time);
00052     ptsock_dbg("In while loop.\n");
00053     if ((time != osWaitForever) && (PICO_TIME_MS() > in_time + time)) {
00054         ptsock_dbg("TIMEOUT in critical select... (ev:%04x rev:%04x \n", ep->events, ep->revents);
00055         if(lock) PicoTcpLock->lock();
00056         return 0;
00057     }
00058   }
00059   ptsock_dbg("After while loop.\n");
00060   if(lock) PicoTcpLock->lock();
00061   ptsock_dbg("After while loop, returning now.\n");
00062   return 1;
00063 }
00064 
00065 static void wakeup(uint16_t ev, struct pico_socket *s)
00066 {
00067   struct stack_endpoint *ep = (struct stack_endpoint *)s->priv;
00068   if (!ep) {
00069     ptsock_dbg("WAKEUP: socket not found! ev=%04x\n", ev);
00070     return;
00071   }
00072   //if (((ep->revents & PICO_SOCK_EV_RD) == 0) && (ev & PICO_SOCK_EV_RD))
00073   //  printf("Activating RD\n");
00074   if(!ep->s || !ep->queue)
00075   {
00076     ptsock_dbg("Endpoint null warning : ep=%p, ep->s=%p, ep->queue=%p\n",ep,ep->s,ep->queue);
00077     return;
00078   }
00079 
00080   ptsock_dbg("RECEIVED EVENT: %d\n",ev);
00081 
00082   ep->revents |= ev;
00083     
00084   if(ev & PICO_SOCK_EV_ERR)
00085   {
00086     if(pico_err == PICO_ERR_ECONNRESET)
00087     {   
00088       ptsock_dbg("Connection reset by peer...\n");
00089       ep->state = SOCK_RESET_BY_PEER;
00090       pico_socket_close(ep->s);
00091       ep->s->priv = NULL;
00092     }
00093   }
00094   if ((ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN)) {
00095     ptsock_dbg("GOT FIN or CLOSE event.\n");
00096     ep->connected = 0;
00097     pico_socket_close(ep->s);
00098     ep->s->priv = NULL;
00099     ep->state = SOCK_CLOSED;
00100   }
00101   if (ev & PICO_SOCK_EV_CONN) {
00102       ep->connected = 1;
00103       ep->state = SOCK_CONNECTED;
00104   }
00105   ep->queue->put((void *)0);
00106 }
00107 
00108 
00109 struct stack_endpoint *picotcp_socket(uint16_t net, uint16_t proto, uint16_t timeout)
00110 {
00111   struct stack_endpoint *ep = (struct stack_endpoint *)pico_zalloc(sizeof(struct stack_endpoint));
00112   uint16_t p_net = ((net == AF_INET6)?PICO_PROTO_IPV6:PICO_PROTO_IPV4);
00113   uint16_t p_proto = ((proto == SOCK_DGRAM)?PICO_PROTO_UDP:PICO_PROTO_TCP);
00114   PicoTcpLock->lock();
00115   ep->s = pico_socket_open( p_net, p_proto, &wakeup );
00116   if (ep->s == NULL) {
00117     delete(ep->queue);
00118     pico_free(ep);
00119     ep = NULL;
00120     ptsock_dbg("Error opening socket!\n");
00121   } else {
00122     ep->s->priv = ep;
00123     ptsock_dbg("Added socket (open)\n");
00124     ep->state = SOCK_OPEN;
00125     ep->queue = new Queue<void,1>();
00126   }
00127   PicoTcpLock->unlock();
00128   return ep;
00129 }
00130 
00131 
00132 int picotcp_state(struct stack_endpoint *ep)
00133 {
00134     return ep->state;
00135 }
00136 
00137 int picotcp_bind(struct stack_endpoint *ep, struct sockaddr *_local_addr, socklen_t len)
00138 {
00139   int ret;
00140   struct sockaddr_in *local_addr;
00141   local_addr = (struct sockaddr_in *)_local_addr;
00142   
00143   PicoTcpLock->lock();
00144   ret = pico_socket_bind(ep->s, (struct pico_ip4 *)(&local_addr->sin_addr.s_addr), &local_addr->sin_port);
00145   if(ret == 0)
00146     ep->state = SOCK_BOUND;
00147   PicoTcpLock->unlock();
00148   return ret;
00149 }
00150 
00151 int picotcp_listen(struct stack_endpoint *ep, int queue)
00152 {
00153   int ret;
00154   PicoTcpLock->lock();
00155   ret = pico_socket_listen(ep->s, queue);
00156   
00157   if(ret == 0)
00158     ep->state = SOCK_LISTEN;
00159   PicoTcpLock->unlock();
00160   return ret;
00161 }
00162 
00163 int picotcp_connect(struct stack_endpoint *ep, struct sockaddr *_srv_addr, socklen_t len)
00164 {
00165   int retval;
00166   struct sockaddr_in *srv_addr;
00167   srv_addr = (struct sockaddr_in *)_srv_addr;
00168   PicoTcpLock->lock();
00169   pico_socket_connect(ep->s, (struct pico_ip4 *)(&srv_addr->sin_addr.s_addr), srv_addr->sin_port);
00170   ep->events = PICO_SOCK_EV_CONN | PICO_SOCK_EV_ERR | PICO_SOCK_EV_FIN;
00171   ptsock_dbg("Going to perform cirital_select on endpoint.\n");
00172   __critical_select(ep, osWaitForever, 1);
00173   if ((ep->revents & PICO_SOCK_EV_CONN) && ep->connected) {
00174     ep->revents &= (~PICO_SOCK_EV_CONN);
00175     ep->revents |= PICO_SOCK_EV_WR;
00176     ptsock_dbg("Established. sock state: %x\n", ep->s->state);
00177     ep->state = SOCK_CONNECTED;
00178     retval = 0;
00179   } else {
00180     retval = -1;
00181   }
00182   ptsock_dbg("Returning %d from picotcp_connect.\n", retval);
00183   PicoTcpLock->unlock();
00184   return retval;
00185 }
00186 
00187 struct stack_endpoint *picotcp_accept(struct stack_endpoint *ep, struct sockaddr *_cli_addr, socklen_t *len)
00188 {
00189   struct sockaddr_in *cli_addr = (struct sockaddr_in *)_cli_addr;
00190   struct stack_endpoint *aep = (struct stack_endpoint *) pico_zalloc(sizeof(struct stack_endpoint));
00191   if (aep)
00192     aep->queue = new Queue<void,1>();
00193   else
00194     return aep;
00195   
00196   PicoTcpLock->lock();
00197   ep->events = PICO_SOCK_EV_CONN | PICO_SOCK_EV_ERR;
00198   __critical_select(ep, osWaitForever, 1);
00199   if (ep->revents & PICO_SOCK_EV_CONN) {
00200     ptsock_dbg("Calling Accept\n");
00201     aep->s = pico_socket_accept(ep->s, (struct pico_ip4 *)(&cli_addr->sin_addr.s_addr), &cli_addr->sin_port);
00202     ptsock_dbg("Accept returned\n");
00203     aep->s->priv = aep;
00204     ep->revents &= (~PICO_SOCK_EV_CONN);
00205     aep->revents = 0; // set this to 0 to allow seq connections
00206     aep->revents |= PICO_SOCK_EV_WR;
00207     aep->state = SOCK_CONNECTED;
00208     ptsock_dbg("Added socket (accept)\n");
00209     
00210     *len = sizeof(struct sockaddr_in);
00211     ptsock_dbg("Established. sock state: %x\n", aep->s->state);
00212   } else {
00213     pico_free(aep);
00214     aep = NULL;
00215   }
00216   PicoTcpLock->unlock();
00217   return aep;
00218 }
00219 
00220 int picotcp_select(struct stack_endpoint *ep, struct timeval *timeout, int read, int write)
00221 {
00222   int ret;
00223   ep->timeout |= timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
00224   ep->events = PICO_SOCK_EV_ERR;
00225   ep->events |= PICO_SOCK_EV_FIN;
00226   ep->events |= PICO_SOCK_EV_CLOSE;
00227   ep->events |= PICO_SOCK_EV_CONN;
00228   if (read) {
00229     ep->events |= PICO_SOCK_EV_RD;
00230   }
00231   if (write)
00232     ep->events |= PICO_SOCK_EV_WR;
00233   ret = __critical_select(ep, ep->timeout, 0);
00234   return ret;
00235 }
00236 
00237 int picotcp_send(struct stack_endpoint *ep,void * buf, int len, int flags)
00238 {
00239   int retval = 0;
00240   int tot_len = 0;
00241   if (!buf || (len <= 0))
00242      return  0;
00243   PicoTcpLock->lock();
00244   while (tot_len < len) {
00245     retval = pico_socket_send(ep->s, ((uint8_t *)buf) + tot_len ,  len - tot_len);
00246     if (retval == 0) {
00247         if (tot_len < len)
00248             ep->revents &= ~PICO_SOCK_EV_WR;
00249         break;
00250     }
00251     if (retval < 0) {
00252        if(tot_len == 0) tot_len = -1;
00253        break;
00254     }
00255     tot_len += retval;
00256   }
00257   PicoTcpLock->unlock();
00258   picotcp_async_interrupt(NULL);
00259   return tot_len; 
00260 }
00261 
00262 int picotcp_recv(struct stack_endpoint *ep,void * buf, int len, int flags)
00263 {
00264   int retval = 0;
00265   int tot_len = 0;
00266   if (!buf || (len <= 0))
00267      return  0;
00268   PicoTcpLock->lock();
00269   while (tot_len < len) {
00270     retval = pico_socket_recv(ep->s, ((uint8_t *)buf) + tot_len ,  len - tot_len);
00271     if (retval == 0) {
00272         if (tot_len < len)
00273             ep->revents &= ~PICO_SOCK_EV_RD;
00274         break;
00275     }
00276     if (retval < 0) {
00277        if(tot_len == 0) tot_len = -1;
00278        break;
00279     }
00280     tot_len += retval;
00281   }
00282   PicoTcpLock->unlock();
00283   picotcp_async_interrupt(NULL);
00284   return tot_len;
00285 }
00286 
00287 int picotcp_sendto(struct stack_endpoint * ep,void * buf, int len, struct sockaddr* a,socklen_t size)
00288 {
00289   int retval = 0;
00290   int tot_len = 0;
00291   struct sockaddr_in * in = (struct sockaddr_in *)a;
00292   if (!buf || (len <= 0))
00293      return  0;
00294   if(!ep->broadcast && pico_ipv4_is_broadcast(in->sin_addr.s_addr))
00295      return -1;
00296      
00297   PicoTcpLock->lock();
00298   while (tot_len < len) {
00299     retval = pico_socket_sendto(ep->s, ((uint8_t *)buf) + tot_len ,  len - tot_len,(struct pico_ip4 *)&in->sin_addr.s_addr, in->sin_port);
00300     
00301     if (retval == 0)
00302         break;
00303     
00304     if (retval < 0) {
00305        if(tot_len == 0) tot_len = -1;
00306        break;
00307     }
00308     tot_len += retval;
00309   }
00310   PicoTcpLock->unlock();
00311   picotcp_async_interrupt(NULL);
00312   return tot_len; 
00313 }
00314 
00315 int picotcp_recvfrom(struct stack_endpoint *ep,void * buf, int len, struct sockaddr *a, socklen_t * size)
00316 {
00317   (void)len;
00318   int retval = 0;
00319   int tot_len = 0;
00320   struct sockaddr_in * in = (struct sockaddr_in *)a;
00321   if (!buf || (len <= 0))
00322      return  0;
00323   PicoTcpLock->lock();
00324   while (tot_len < len) {
00325     retval = pico_socket_recvfrom(ep->s, ((uint8_t *)buf) + tot_len ,  len - tot_len,(struct pico_ip4 *)&(in->sin_addr.s_addr),&in->sin_port);
00326     if (retval == 0) {
00327         if (tot_len < len)
00328             ep->revents &= ~PICO_SOCK_EV_RD;
00329         break;
00330     }
00331     if (retval < 0) {
00332        if(tot_len == 0) tot_len = -1;
00333        break;
00334     }
00335     tot_len += retval;
00336     break;
00337   }
00338   PicoTcpLock->unlock();
00339   picotcp_async_interrupt(NULL);
00340   return tot_len;
00341 }
00342 
00343 int picotcp_read(struct stack_endpoint *ep,void *buf, int len)
00344 {
00345   int retval = 0;
00346   int tot_len = 0;
00347   if (!buf || (len <= 0))
00348      return  0;
00349   PicoTcpLock->lock();
00350   while (tot_len < len) {
00351     retval = pico_socket_read(ep->s, ((uint8_t *)buf) + tot_len ,  len - tot_len);
00352     if (retval == 0) {
00353         if (tot_len < len)
00354             ep->revents &= ~PICO_SOCK_EV_RD;
00355         break;
00356     }
00357     if (retval < 0) {
00358        if(tot_len == 0) tot_len = -1;
00359        break;
00360     }
00361     tot_len += retval;
00362   }
00363   PicoTcpLock->unlock();
00364   picotcp_async_interrupt(NULL);
00365   return tot_len;
00366 }
00367 
00368 int picotcp_write(struct stack_endpoint *ep,void *buf, int len)
00369 {
00370   int retval = 0;
00371   int tot_len = 0;
00372   if (!buf || (len <= 0))
00373      return  0;
00374   PicoTcpLock->lock();
00375   while (tot_len < len) {
00376     retval = pico_socket_write(ep->s, ((uint8_t *)buf) + tot_len ,  len - tot_len);
00377     
00378     if (retval == 0) {
00379         if (tot_len < len)
00380             ep->revents &= ~PICO_SOCK_EV_WR;
00381         break;
00382     }
00383     if (retval < 0) {
00384        if(tot_len == 0) tot_len = -1;
00385        break;
00386     }
00387     tot_len += retval;
00388   }
00389   PicoTcpLock->unlock();
00390   picotcp_async_interrupt(NULL);
00391   return tot_len; 
00392 }
00393 
00394 
00395 int picotcp_setsockopt(struct stack_endpoint *ep, int option, void *value)
00396 {
00397   int ret;
00398   
00399   PicoTcpLock->lock();
00400   if(option == SO_BROADCAST)
00401   {
00402     ep->broadcast = *(int *)value;
00403     ret = 0;
00404   }
00405   else
00406     ret = pico_socket_setoption(ep->s,option,value);
00407   PicoTcpLock->unlock();
00408   
00409   return ret; 
00410 }
00411 
00412 int picotcp_getsockopt(struct stack_endpoint *ep, int option, void *value)
00413 {
00414   int ret;
00415   
00416   PicoTcpLock->lock();
00417   ret = pico_socket_getoption(ep->s,option,value);
00418   PicoTcpLock->unlock();
00419   
00420   return ret;
00421 }
00422 
00423 int picotcp_close(struct stack_endpoint *ep)
00424 {
00425   int ret = 0;
00426   PicoTcpLock->lock();
00427   if(ep->state != SOCK_RESET_BY_PEER && ep->state != SOCK_CLOSED)
00428   {
00429     pico_socket_close(ep->s);
00430     // wait for fin, but timeout
00431     if( !(ep->revents & PICO_SOCK_EV_FIN) && !(ep->revents & PICO_SOCK_EV_CLOSE))
00432     {
00433         ep->events = (PICO_SOCK_EV_FIN | PICO_SOCK_EV_CLOSE | PICO_SOCK_EV_ERR);
00434         __critical_select(ep,3000u,1);// wait for 3 seconds
00435         ret = ((ep->revents & PICO_SOCK_EV_FIN) || (ep->revents & PICO_SOCK_EV_CLOSE) ? 0:-1);
00436     }
00437     ep->s->priv = NULL;
00438   }
00439   ptsock_dbg("Socket closed!\n");
00440   delete(ep->queue);
00441   pico_free(ep);
00442   PicoTcpLock->unlock();
00443   return ret;
00444 }
00445 
00446 int picotcp_join_multicast(struct stack_endpoint *ep,const char* address,const char* local)
00447 {
00448   int ret;
00449   struct pico_ip_mreq mreq={};
00450   
00451   PicoTcpLock->lock();
00452   pico_string_to_ipv4(address,&mreq.mcast_group_addr.ip4.addr);
00453   pico_string_to_ipv4(local,&mreq.mcast_link_addr.ip4.addr);
00454   ret = pico_socket_setoption(ep->s, PICO_IP_ADD_MEMBERSHIP, &mreq);
00455   PicoTcpLock->unlock();
00456   
00457   return ret; 
00458 }
00459 
00460 void pico_wrapper_loop(const void * arg)
00461 {
00462 #ifdef PICO_MEASURE_STACK
00463     stack_fill_pattern((void *)&arg);
00464 #else
00465   (void)arg;
00466 #endif  
00467 
00468   struct pico_device *dev;
00469   while(1) {
00470     
00471     osEvent evt = PicoTcpEvents->get(SCHEDULER_BASE<<scheduler_timeout);
00472     
00473     if (evt.status == osEventMessage) {
00474         dev = (struct pico_device *)evt.value.p;
00475         scheduler_timeout = 0;
00476     } else {
00477         dev = NULL;
00478         if(scheduler_timeout < SCHEDULER_MAX) 
00479             scheduler_timeout++;
00480     }
00481     PicoTcpLock->lock();
00482     if (dev && dev->dsr)
00483       dev->dsr(dev, 5);
00484     picotcp_async_clean(dev);
00485     pico_stack_tick();
00486     pico_stack_tick();
00487 #ifdef PICO_MEASURE_STACK
00488     stack_count_free_words((void *)&arg);
00489 #endif
00490     PicoTcpLock->unlock();
00491   }
00492 }
00493 
00494 void picotcp_start(void)
00495 {
00496   if (serverThread == NULL) {
00497     PicoTcpLock = new Mutex();
00498     PicoTcpEvents = new Queue<void,32>();
00499     ptsock_dbg (" *** PicoTCP initialized *** \n");
00500     serverThread = new Thread(pico_wrapper_loop,NULL,osPriorityNormal,4096);
00501     serverThread->set_priority(osPriorityIdle);
00502   }
00503 }
00504 
00505 void picotcp_init(void)
00506 {
00507   picotcp_start(); 
00508 }
00509 
00510 int picotcp_dhcp_server_start(struct pico_dhcp_server_setting *setting)
00511 {
00512   int ret;
00513 
00514   PicoTcpLock->lock();
00515   ret = pico_dhcp_server_initiate(setting);
00516   PicoTcpLock->unlock();
00517   picotcp_async_interrupt(NULL);
00518 
00519   return ret;
00520 }
00521 
00522 /****** Asynchronous event handling ******/
00523 static int appEvents = 0;
00524 static Mutex asyncMutex;
00525 void picotcp_async_interrupt(void *arg)
00526 {
00527     asyncMutex.lock();
00528     if(!arg)
00529     {
00530         if(!appEvents) // add NULL to queue
00531             PicoTcpEvents->put(NULL);
00532         appEvents++;
00533     }
00534     else
00535     {
00536         struct pico_device * dev = (struct pico_device *)arg;
00537         if(!dev->eventCnt) // put arg to queue
00538             PicoTcpEvents->put(dev);
00539         dev->eventCnt++;
00540     }
00541     asyncMutex.unlock();
00542 }
00543 
00544 void picotcp_async_clean(struct pico_device * dev)
00545 {
00546     asyncMutex.lock();
00547     if(!dev)
00548         appEvents = 0;
00549     else
00550         dev->eventCnt=0;
00551     asyncMutex.unlock();
00552 }
00553 
00554 /*******************************/
00555 
00556 
00557 // *************** DNS part *************** 
00558 
00559 int picotcp_dns_client_nameserver(const char *ip, int flag)
00560 {
00561     int ret;
00562     struct pico_ip4 addr;
00563     pico_string_to_ipv4(ip, &addr.addr);
00564 
00565     PicoTcpLock->lock();
00566     ret = pico_dns_client_nameserver(&addr, flag);
00567     PicoTcpLock->unlock();
00568 
00569     return ret;
00570 }
00571 
00572 void dns_cb(char *ip,void *arg)
00573 {
00574   if(!arg)
00575     goto fail;
00576     // send the result back  
00577     ((Queue<void,1> *)arg)->put((void *)ip);
00578     return;
00579     
00580 fail:
00581     if(ip) pico_free(ip);    
00582 }
00583 
00584 // dns get host
00585 struct hostent *picotcp_gethostbyname(const char *name)
00586 {
00587     Queue<void,1> *dnsResult = new Queue<void,1>();
00588     struct hostent * hostdata = NULL;
00589     char *ip;
00590     
00591     if(!dnsResult)
00592         return NULL;
00593     PicoTcpLock->lock();
00594     pico_dns_client_getaddr(name,dns_cb,dnsResult);
00595     PicoTcpLock->unlock();
00596     picotcp_async_interrupt(NULL);
00597     
00598     osEvent evt = dnsResult->get(7000);// 7 seconds timeout
00599     if (evt.status == osEventMessage){
00600         ip = (char *)evt.value.p;
00601         hostdata = new struct hostent;
00602         hostdata->h_name = new char[strlen(name)+1];
00603         strcpy(hostdata->h_name,name);
00604         hostdata->h_aliases=NULL;
00605         hostdata->h_addrtype = AF_INET;
00606         hostdata->h_length = strlen(ip);
00607         hostdata->h_addr_list = new char*[2];
00608         hostdata->h_addr_list[0] = ip;
00609         hostdata->h_addr_list[1] = NULL;
00610     }
00611     free(dnsResult);
00612     return hostdata;
00613 }