Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more
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 }
Generated on Tue Jul 12 2022 15:59:22 by
1.7.2