Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers test_sockets.c Source File

test_sockets.c

00001 #include "test_sockets.h"
00002 
00003 #include "lwip/mem.h"
00004 #include "lwip/opt.h"
00005 #include "lwip/sockets.h"
00006 #include "lwip/priv/sockets_priv.h"
00007 #include "lwip/stats.h"
00008 
00009 #include "lwip/tcpip.h"
00010 #include "lwip/priv/tcp_priv.h"
00011 #include "lwip/api.h"
00012 
00013 
00014 static int
00015 test_sockets_get_used_count(void)
00016 {
00017   int used = 0;
00018   int i;
00019 
00020   for (i = 0; i < NUM_SOCKETS; i++) {
00021     struct lwip_sock* s = lwip_socket_dbg_get_socket(i);
00022     if (s != NULL) {
00023       if (s->fd_used) {
00024         used++;
00025       }
00026     }
00027   }
00028   return used;
00029 }
00030 
00031 
00032 /* Setups/teardown functions */
00033 
00034 static void
00035 sockets_setup(void)
00036 {
00037   /* expect full free heap */
00038   lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
00039 }
00040 
00041 static void
00042 sockets_teardown(void)
00043 {
00044   fail_unless(test_sockets_get_used_count() == 0);
00045   /* poll until all memory is released... */
00046   tcpip_thread_poll_one();
00047   while (tcp_tw_pcbs) {
00048     tcp_abort(tcp_tw_pcbs);
00049     tcpip_thread_poll_one();
00050   }
00051   tcpip_thread_poll_one();
00052   /* ensure full free heap */
00053   lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
00054 }
00055 
00056 #ifndef NUM_SOCKETS
00057 #define NUM_SOCKETS MEMP_NUM_NETCONN
00058 #endif
00059 
00060 #if LWIP_SOCKET
00061 static int
00062 test_sockets_alloc_socket_nonblocking(int domain, int type)
00063 {
00064   int s = lwip_socket(domain, type, 0);
00065   if (s >= 0) {
00066     int ret = lwip_fcntl(s, F_SETFL, O_NONBLOCK);
00067     fail_unless(ret == 0);
00068   }
00069   return s;
00070 }
00071 
00072 /* Verify basic sockets functionality
00073  */
00074 START_TEST(test_sockets_basics)
00075 {
00076   int s, i, ret;
00077   int s2[NUM_SOCKETS];
00078   LWIP_UNUSED_ARG(_i);
00079 
00080   s = lwip_socket(AF_INET, SOCK_STREAM, 0);
00081   fail_unless(s >= 0);
00082   lwip_close(s);
00083 
00084   for (i = 0; i < NUM_SOCKETS; i++) {
00085     s2[i] = lwip_socket(AF_INET, SOCK_STREAM, 0);
00086     fail_unless(s2[i] >= 0);
00087   }
00088 
00089   /* all sockets used, now it should fail */
00090   s = lwip_socket(AF_INET, SOCK_STREAM, 0);
00091   fail_unless(s == -1);
00092   /* close one socket */
00093   ret = lwip_close(s2[0]);
00094   fail_unless(ret == 0);
00095   /* now it should succeed */
00096   s2[0] = lwip_socket(AF_INET, SOCK_STREAM, 0);
00097   fail_unless(s2[0] >= 0);
00098 
00099   /* close all sockets */
00100   for (i = 0; i < NUM_SOCKETS; i++) {
00101     ret = lwip_close(s2[i]);
00102     fail_unless(ret == 0);
00103   }
00104 }
00105 END_TEST
00106 
00107 static void test_sockets_allfunctions_basic_domain(int domain)
00108 {
00109   int s, s2, s3, ret;
00110   struct sockaddr_storage addr, addr2;
00111   socklen_t addrlen, addr2len;
00112   char buf[4];
00113   /* listen socket */
00114   s = lwip_socket(domain, SOCK_STREAM, 0);
00115   fail_unless(s >= 0);
00116 
00117   ret = lwip_listen(s, 0);
00118   fail_unless(ret == 0);
00119 
00120   addrlen = sizeof(addr);
00121   ret = lwip_getsockname(s, (struct sockaddr*)&addr, &addrlen);
00122   fail_unless(ret == 0);
00123 
00124   s2 = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
00125   fail_unless(s2 >= 0);
00126   /* nonblocking connect s2 to s (but use loopback address) */
00127   if (domain == AF_INET) {
00128 #if LWIP_IPV4
00129     struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
00130     addr4->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
00131 #endif
00132   } else {
00133 #if LWIP_IPV6
00134     struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
00135     struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
00136     addr6->sin6_addr = lo6;
00137 #endif
00138   }
00139   ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
00140   fail_unless(ret == -1);
00141   fail_unless(errno == EINPROGRESS);
00142   ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
00143   fail_unless(ret == -1);
00144   fail_unless(errno == EALREADY);
00145 
00146   while(tcpip_thread_poll_one());
00147 
00148   s3 = lwip_accept(s, (struct sockaddr*)&addr2, &addr2len);
00149   fail_unless(s3 >= 0);
00150 
00151   ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
00152   fail_unless(ret == -1);
00153   fail_unless(errno == EISCONN);
00154 
00155   /* write from server to client */
00156   ret = write(s3, "test", 4);
00157   fail_unless(ret == 4);
00158 
00159   ret = lwip_shutdown(s3, SHUT_WR);
00160   fail_unless(ret == 0);
00161 
00162   while(tcpip_thread_poll_one());
00163 
00164   ret = lwip_recv(s2, buf, 3, MSG_PEEK);
00165   fail_unless(ret == 3);
00166 
00167   ret = lwip_recv(s2, buf, 3, MSG_PEEK);
00168   fail_unless(ret == 3);
00169 
00170   ret = lwip_read(s2, buf, 4);
00171   fail_unless(ret == 4);
00172 
00173   ret = lwip_read(s2, buf, 1);
00174   fail_unless(ret == 0);
00175 
00176   ret = lwip_read(s2, buf, 1);
00177   fail_unless(ret == -1);
00178 
00179   ret = lwip_write(s2, "foo", 3);
00180   fail_unless(ret == 3);
00181 
00182   ret = lwip_close(s2);
00183   fail_unless(ret == 0);
00184 
00185   while(tcpip_thread_poll_one());
00186 
00187   /* read one byte more than available to check handling FIN */
00188   ret = lwip_read(s3, buf, 4);
00189   fail_unless(ret == 3);
00190 
00191   ret = lwip_read(s3, buf, 1);
00192   fail_unless(ret == 0);
00193 
00194   ret = lwip_read(s3, buf, 1);
00195   fail_unless(ret == -1);
00196 
00197   while(tcpip_thread_poll_one());
00198 
00199   ret = lwip_close(s);
00200   fail_unless(ret == 0);
00201   ret = lwip_close(s3);
00202   fail_unless(ret == 0);
00203 }
00204 
00205 /* Try to step through all sockets functions once...
00206  */
00207 START_TEST(test_sockets_allfunctions_basic)
00208 {
00209   LWIP_UNUSED_ARG(_i);
00210 #if LWIP_IPV4
00211   test_sockets_allfunctions_basic_domain(AF_INET);
00212 #endif
00213 #if LWIP_IPV6
00214   test_sockets_allfunctions_basic_domain(AF_INET6);
00215 #endif
00216 }
00217 END_TEST
00218 
00219 static void test_sockets_init_loopback_addr(int domain, struct sockaddr_storage *addr_st, socklen_t *sz)
00220 {
00221   memset(addr_st, 0, sizeof(*addr_st));
00222   switch(domain) {
00223 #if LWIP_IPV6
00224     case AF_INET6: {
00225       struct sockaddr_in6 *addr = (struct sockaddr_in6*)addr_st;
00226       struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
00227       addr->sin6_family = AF_INET6;
00228       addr->sin6_port = 0; /* use ephemeral port */
00229       addr->sin6_addr = lo6;
00230       *sz = sizeof(*addr);
00231    }
00232       break;
00233 #endif /* LWIP_IPV6 */
00234 #if LWIP_IPV4
00235     case AF_INET: {
00236       struct sockaddr_in *addr = (struct sockaddr_in*)addr_st;
00237       addr->sin_family = AF_INET;
00238       addr->sin_port = 0; /* use ephemeral port */
00239       addr->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
00240       *sz = sizeof(*addr);
00241     }
00242       break;
00243 #endif /* LWIP_IPV4 */
00244     default:
00245       *sz = 0;
00246       fail();
00247       break;
00248   }
00249 }
00250 
00251 static void test_sockets_msgapi_update_iovs(struct msghdr *msg, size_t bytes)
00252 {
00253   int i;
00254 
00255   /* note: this modifies the underyling iov_base and iov_len for a partial
00256      read for an individual vector. This updates the msg->msg_iov pointer
00257      to skip fully consumed vecotrs */
00258   
00259   /* process fully consumed vectors */
00260   for (i = 0; i < msg->msg_iovlen; i++) {
00261     if (msg->msg_iov[i].iov_len <= bytes) {
00262       /* reduce bytes by amount of this vector */
00263       bytes -= msg->msg_iov[i].iov_len;
00264     } else {
00265       break; /* iov not fully consumed */
00266     }
00267   }
00268 
00269   /* slide down over fully consumed vectors */
00270   msg->msg_iov = &msg->msg_iov[i];
00271   msg->msg_iovlen -= i;
00272 
00273   /* update new first vector with any remaining amount */
00274   msg->msg_iov[0].iov_base = ((u8_t *)msg->msg_iov[0].iov_base + bytes);
00275   msg->msg_iov[0].iov_len -= bytes;
00276 }
00277 
00278 static void test_sockets_msgapi_tcp(int domain)
00279 {
00280   #define BUF_SZ          (TCP_SND_BUF/4)
00281   #define TOTAL_DATA_SZ   (BUF_SZ*8) /* ~(TCP_SND_BUF*2) that accounts for integer rounding */
00282   #define NEED_TRAILER    (BUF_SZ % 4 != 0)
00283   int listnr, s1, s2, i, ret, opt;
00284   int bytes_written, bytes_read;
00285   struct sockaddr_storage addr_storage;
00286   socklen_t addr_size;
00287   struct iovec siovs[8];
00288   struct msghdr smsg;
00289   u8_t * snd_buf;
00290   struct iovec riovs[5];
00291   struct iovec riovs_tmp[5];
00292   struct msghdr rmsg;
00293   u8_t * rcv_buf;
00294   int    rcv_off;
00295   int    rcv_trailer = 0;
00296   u8_t val;
00297 
00298   test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
00299 
00300   listnr = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
00301   fail_unless(listnr >= 0);
00302   s1 = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
00303   fail_unless(s1 >= 0);
00304 
00305   /* setup a listener socket on loopback with ephemeral port */
00306   ret = lwip_bind(listnr, (struct sockaddr*)&addr_storage, addr_size);
00307   fail_unless(ret == 0);
00308   ret = lwip_listen(listnr, 0);
00309   fail_unless(ret == 0);
00310 
00311   /* update address with ephemeral port */
00312   ret = lwip_getsockname(listnr, (struct sockaddr*)&addr_storage, &addr_size);
00313   fail_unless(ret == 0);
00314 
00315   /* connect, won't complete until we accept it */
00316   ret = lwip_connect(s1, (struct sockaddr*)&addr_storage, addr_size);
00317   fail_unless(ret == -1);
00318   fail_unless(errno == EINPROGRESS);
00319 
00320   while (tcpip_thread_poll_one());
00321 
00322   /* accept, creating the other side of the connection */
00323   s2 = lwip_accept(listnr, NULL, NULL);
00324   fail_unless(s2 >= 0);
00325 
00326   /* double check s1 is connected */
00327   ret = lwip_connect(s1, (struct sockaddr*)&addr_storage, addr_size);
00328   fail_unless(ret == -1);
00329   fail_unless(errno == EISCONN);
00330 
00331   /* set s2 to non-blocking, not inherited from listener */
00332   opt = lwip_fcntl(s2, F_GETFL, 0);
00333   fail_unless(opt == 6);
00334   opt = O_NONBLOCK;
00335   ret = lwip_fcntl(s2, F_SETFL, opt);
00336   fail_unless(ret == 0);
00337 
00338   /* we are done with listener, close it */
00339   ret = lwip_close(listnr);
00340   fail_unless(ret == 0);
00341 
00342   /* allocate a buffer for a stream of incrementing hex (0x00..0xFF) which we will use
00343      to create an input vector set that is larger than the TCP's send buffer. This will
00344      force execution of the partial IO vector send case */
00345   snd_buf = (u8_t*)mem_malloc(BUF_SZ);
00346   val = 0x00;
00347   fail_unless(snd_buf != NULL);
00348   for (i = 0; i < BUF_SZ; i++,val++) {
00349     snd_buf[i] = val;
00350   }
00351 
00352   /* send the buffer 8 times in one message, equating to TOTAL_DATA_SZ */
00353   for (i = 0; i < 8; i++) {
00354     siovs[i].iov_base = snd_buf;
00355     siovs[i].iov_len = BUF_SZ;
00356   }
00357 
00358   /* allocate a receive buffer, same size as snd_buf for easy verification */
00359   rcv_buf = (u8_t*)mem_calloc(1, BUF_SZ);
00360   fail_unless(rcv_buf != NULL);
00361   /* split across iovs */
00362   for (i = 0; i < 4; i++) {
00363     riovs[i].iov_base = &rcv_buf[i*(BUF_SZ/4)];
00364     riovs[i].iov_len = BUF_SZ/4;
00365   }
00366   /* handling trailing bytes if buffer doesn't evenly divide by 4 */
00367 #if NEED_TRAILER
00368   if ((BUF_SZ % 4) != 0) {
00369     riovs[5].iov_base = &rcv_buf[4*(BUF_SZ/4)];
00370     riovs[5].iov_len = BUF_SZ - (4*(BUF_SZ/4));
00371     rcv_trailer = 1;
00372   }
00373 #endif /* NEED_TRAILER */
00374 
00375   /* we use a copy of riovs since we'll be modifying base and len during
00376      receiving. This gives us an easy way to reset the iovs for next recvmsg */
00377   memcpy(riovs_tmp, riovs, sizeof(riovs));
00378 
00379   memset(&smsg, 0, sizeof(smsg));
00380   smsg.msg_iov = siovs;
00381   smsg.msg_iovlen = 8;
00382 
00383   memset(&rmsg, 0, sizeof(rmsg));
00384   rmsg.msg_iov = riovs_tmp;
00385   rmsg.msg_iovlen = (rcv_trailer ? 5 : 4);
00386 
00387   bytes_written = 0;
00388   bytes_read = 0;
00389   rcv_off = 0;
00390 
00391   while (bytes_written < TOTAL_DATA_SZ && (bytes_read < TOTAL_DATA_SZ)) {
00392     /* send data */
00393     if (bytes_written < TOTAL_DATA_SZ) {
00394       ret = lwip_sendmsg(s1, &smsg, 0);
00395       /* note: since we always receive after sending, there will be open
00396          space in the send buffer */
00397       fail_unless(ret > 0);
00398     
00399       bytes_written += ret;
00400       if (bytes_written < TOTAL_DATA_SZ) {
00401         test_sockets_msgapi_update_iovs(&smsg, (size_t)ret);
00402       }
00403     }
00404 
00405     while (tcpip_thread_poll_one());
00406 
00407     /* receive and verify data */
00408     do {
00409       if (bytes_read < TOTAL_DATA_SZ) {
00410         ret = lwip_recvmsg(s2, &rmsg, 0);
00411         fail_unless(ret > 0 || (ret == -1 && errno == EWOULDBLOCK));
00412 
00413         if (ret > 0) {
00414           rcv_off += ret;
00415           /* we have received a full buffer */
00416           if (rcv_off == BUF_SZ) {
00417             /* note: since iovs are just pointers, compare underlying buf */
00418             fail_unless(!memcmp(snd_buf, rcv_buf, BUF_SZ));
00419             bytes_read += BUF_SZ;
00420             /* reset receive state for next buffer */
00421             rcv_off = 0;
00422             memset(rcv_buf, 0, BUF_SZ);
00423             memcpy(riovs_tmp, riovs, sizeof(riovs));
00424             rmsg.msg_iov = riovs_tmp;
00425             rmsg.msg_iovlen = (rcv_trailer ? 5 : 4);
00426           } else { /* partial read */
00427             test_sockets_msgapi_update_iovs(&rmsg, (size_t)ret);
00428           }
00429         }
00430       } else {
00431         break;
00432       }
00433     } while(ret > 0);
00434   }
00435   
00436   ret = lwip_close(s1);
00437   fail_unless(ret == 0);
00438   ret = lwip_close(s2);
00439   fail_unless(ret == 0);
00440   mem_free(snd_buf);
00441   mem_free(rcv_buf);
00442 }
00443 
00444 static void test_sockets_msgapi_udp_send_recv_loop(int s, struct msghdr *smsg, struct msghdr *rmsg)
00445 {
00446   int i, ret;
00447 
00448   /* send/receive our datagram of IO vectors 10 times */
00449   for (i = 0; i < 10; i++) {
00450     ret = lwip_sendmsg(s, smsg, 0);
00451     fail_unless(ret == 4);
00452 
00453     while (tcpip_thread_poll_one());
00454 
00455     /* receive the datagram split across 4 buffers */
00456     ret = lwip_recvmsg(s, rmsg, 0);
00457     fail_unless(ret == 4);
00458 
00459     /* verify data */
00460     fail_unless(*((u8_t*)rmsg->msg_iov[0].iov_base) == 0xDE);
00461     fail_unless(*((u8_t*)rmsg->msg_iov[1].iov_base) == 0xAD);
00462     fail_unless(*((u8_t*)rmsg->msg_iov[2].iov_base) == 0xBE);
00463     fail_unless(*((u8_t*)rmsg->msg_iov[3].iov_base) == 0xEF);
00464 
00465     /* clear rcv_buf to ensure no data is being skipped */
00466     *((u8_t*)rmsg->msg_iov[0].iov_base) = 0x00;
00467     *((u8_t*)rmsg->msg_iov[1].iov_base) = 0x00;
00468     *((u8_t*)rmsg->msg_iov[2].iov_base) = 0x00;
00469     *((u8_t*)rmsg->msg_iov[3].iov_base) = 0x00;
00470   }
00471 }
00472 
00473 static void test_sockets_msgapi_udp(int domain)
00474 {
00475   int s, i, ret;
00476   struct sockaddr_storage addr_storage;
00477   socklen_t addr_size;
00478   struct iovec riovs[4];
00479   struct msghdr rmsg;
00480   u8_t rcv_buf[4];
00481   struct iovec siovs[4];
00482   struct msghdr smsg;
00483   u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF};
00484 
00485   /* initialize IO vectors with data */
00486   for (i = 0; i < 4; i++) {
00487     siovs[i].iov_base = &snd_buf[i];
00488     siovs[i].iov_len = sizeof(u8_t);
00489     riovs[i].iov_base = &rcv_buf[i];
00490     riovs[i].iov_len = sizeof(u8_t);
00491   }
00492 
00493   test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
00494 
00495   s = test_sockets_alloc_socket_nonblocking(domain, SOCK_DGRAM);
00496   fail_unless(s >= 0);
00497 
00498   ret = lwip_bind(s, (struct sockaddr*)&addr_storage, addr_size);
00499   fail_unless(ret == 0);
00500 
00501   /* Update addr with epehermal port */
00502   ret = lwip_getsockname(s, (struct sockaddr*)&addr_storage, &addr_size);
00503   fail_unless(ret == 0);
00504   switch(domain) {
00505 #if LWIP_IPV6
00506     case AF_INET6:
00507       fail_unless(addr_size == sizeof(struct sockaddr_in6));
00508       break;
00509 #endif /* LWIP_IPV6 */
00510 #if LWIP_IPV4
00511     case AF_INET:
00512         fail_unless(addr_size == sizeof(struct sockaddr_in));
00513         break;
00514 #endif /* LWIP_IPV6 */
00515     default:
00516       fail();
00517       break;
00518   }
00519 
00520   /* send and receive the datagram in 4 pieces */
00521   memset(&smsg, 0, sizeof(smsg));
00522   smsg.msg_iov = siovs;
00523   smsg.msg_iovlen = 4;
00524   memset(&rmsg, 0, sizeof(rmsg));
00525   rmsg.msg_iov = riovs;
00526   rmsg.msg_iovlen = 4;
00527 
00528   /* perform a sendmsg with remote host (self) */
00529   smsg.msg_name = &addr_storage;
00530   smsg.msg_namelen = addr_size;
00531 
00532   test_sockets_msgapi_udp_send_recv_loop(s, &smsg, &rmsg);
00533 
00534   /* Connect to self, allowing us to not pass message name */
00535   ret = lwip_connect(s, (struct sockaddr*)&addr_storage, addr_size);
00536   fail_unless(ret == 0);
00537 
00538   smsg.msg_name = NULL;
00539   smsg.msg_namelen = 0;
00540 
00541   test_sockets_msgapi_udp_send_recv_loop(s, &smsg, &rmsg);
00542 
00543   ret = lwip_close(s);
00544   fail_unless(ret == 0);
00545 }
00546 
00547 #if LWIP_IPV4
00548 static void test_sockets_msgapi_cmsg(int domain)
00549 {
00550   int s, ret, enable;
00551   struct sockaddr_storage addr_storage;
00552   socklen_t addr_size;
00553   struct iovec iov;
00554   struct msghdr msg;
00555   struct cmsghdr *cmsg;
00556   struct in_pktinfo *pktinfo;
00557   u8_t rcv_buf[4];
00558   u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF};
00559   u8_t cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
00560 
00561   test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
00562 
00563   s = test_sockets_alloc_socket_nonblocking(domain, SOCK_DGRAM);
00564   fail_unless(s >= 0);
00565 
00566   ret = lwip_bind(s, (struct sockaddr*)&addr_storage, addr_size);
00567   fail_unless(ret == 0);
00568 
00569   /* Update addr with epehermal port */
00570   ret = lwip_getsockname(s, (struct sockaddr*)&addr_storage, &addr_size);
00571   fail_unless(ret == 0);
00572 
00573   enable = 1;
00574   ret = lwip_setsockopt(s, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable));
00575   fail_unless(ret == 0);
00576 
00577   /* Receive full message, including control message */
00578   iov.iov_base = rcv_buf;
00579   iov.iov_len = sizeof(rcv_buf);
00580   msg.msg_control = cmsg_buf;
00581   msg.msg_controllen = sizeof(cmsg_buf);
00582   msg.msg_flags = 0;
00583   msg.msg_iov = &iov;
00584   msg.msg_iovlen = 1;
00585   msg.msg_name = NULL;
00586   msg.msg_namelen = 0;
00587 
00588   memset(rcv_buf, 0, sizeof(rcv_buf));
00589   ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size);
00590   fail_unless(ret == sizeof(snd_buf));
00591   
00592   tcpip_thread_poll_one();
00593 
00594   ret = lwip_recvmsg(s, &msg, 0);
00595   fail_unless(ret == sizeof(rcv_buf));
00596   fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf)));
00597   
00598   /* Verify message header */
00599   cmsg = CMSG_FIRSTHDR(&msg);
00600   fail_unless(cmsg != NULL);
00601   fail_unless(cmsg->cmsg_len > 0);
00602   fail_unless(cmsg->cmsg_level == IPPROTO_IP);
00603   fail_unless(cmsg->cmsg_type == IP_PKTINFO);
00604 
00605   /* Verify message data */
00606   pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
00607   /* We only have loopback interface enabled */
00608   fail_unless(pktinfo->ipi_ifindex == 1);
00609   fail_unless(pktinfo->ipi_addr.s_addr == PP_HTONL(INADDR_LOOPBACK));
00610 
00611   /* Verify there are no additional messages */
00612   cmsg = CMSG_NXTHDR(&msg, cmsg);
00613   fail_unless(cmsg == NULL);
00614 
00615   /* Send datagram again, testing truncation */
00616   memset(rcv_buf, 0, sizeof(rcv_buf));
00617   ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size);
00618   fail_unless(ret == sizeof(snd_buf));
00619 
00620   tcpip_thread_poll_one();
00621 
00622   msg.msg_controllen = 1;
00623   msg.msg_flags = 0;
00624   ret = lwip_recvmsg(s, &msg, 0);
00625   fail_unless(ret == sizeof(rcv_buf));
00626   fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf)));
00627   /* Ensure truncation was returned */
00628   fail_unless(msg.msg_flags & MSG_CTRUNC);
00629   /* Ensure no control messages were returned */
00630   fail_unless(msg.msg_controllen == 0);
00631 
00632   ret = lwip_close(s);
00633   fail_unless(ret == 0);
00634 }
00635 #endif /* LWIP_IPV4 */
00636 
00637 START_TEST(test_sockets_msgapis)
00638 {
00639   LWIP_UNUSED_ARG(_i);
00640 #if LWIP_IPV4
00641   test_sockets_msgapi_udp(AF_INET);
00642   test_sockets_msgapi_tcp(AF_INET);
00643   test_sockets_msgapi_cmsg(AF_INET);
00644 #endif
00645 #if LWIP_IPV6
00646   test_sockets_msgapi_udp(AF_INET6);
00647   test_sockets_msgapi_tcp(AF_INET6);
00648 #endif
00649 }
00650 END_TEST
00651 
00652 START_TEST(test_sockets_select)
00653 {
00654 #if LWIP_SOCKET_SELECT
00655   int s;
00656   int ret;
00657   fd_set readset;
00658   fd_set writeset;
00659   fd_set errset;
00660   struct timeval tv;
00661 
00662   fail_unless(test_sockets_get_used_count() == 0);
00663 
00664   s = lwip_socket(AF_INET, SOCK_STREAM, 0);
00665   fail_unless(s >= 0);
00666   fail_unless(test_sockets_get_used_count() == 0);
00667 
00668   FD_ZERO(&readset);
00669   FD_SET(s, &readset);
00670   FD_ZERO(&writeset);
00671   FD_SET(s, &writeset);
00672   FD_ZERO(&errset);
00673   FD_SET(s, &errset);
00674 
00675   tv.tv_sec = tv.tv_usec = 0;
00676   ret = lwip_select(s + 1, &readset, &writeset, &errset, &tv);
00677   fail_unless(ret == 0);
00678   fail_unless(test_sockets_get_used_count() == 0);
00679 
00680   ret = lwip_close(s);
00681   fail_unless(ret == 0);
00682 
00683 #endif
00684   LWIP_UNUSED_ARG(_i);
00685 }
00686 END_TEST
00687 
00688 START_TEST(test_sockets_recv_after_rst)
00689 {
00690   int sl, sact;
00691   int spass = -1;
00692   int ret;
00693   struct sockaddr_in sa_listen;
00694   const u16_t port = 1234;
00695   int arg;
00696   const char txbuf[] = "something";
00697   char rxbuf[16];
00698   struct lwip_sock *sact_sock;
00699   int err;
00700   LWIP_UNUSED_ARG(_i);
00701 
00702   fail_unless(test_sockets_get_used_count() == 0);
00703 
00704   memset(&sa_listen, 0, sizeof(sa_listen));
00705   sa_listen.sin_family = AF_INET;
00706   sa_listen.sin_port = PP_HTONS(port);
00707   sa_listen.sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
00708 
00709   /* set up the listener */
00710   sl = lwip_socket(AF_INET, SOCK_STREAM, 0);
00711   fail_unless(sl >= 0);
00712   fail_unless(test_sockets_get_used_count() == 0);
00713 
00714   ret = lwip_bind(sl, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
00715   fail_unless(ret == 0);
00716   ret = lwip_listen(sl, 0);
00717   fail_unless(ret == 0);
00718 
00719   /* set up the client */
00720   sact = lwip_socket(AF_INET, SOCK_STREAM, 0);
00721   fail_unless(sact >= 0);
00722   fail_unless(test_sockets_get_used_count() == 0);
00723   /* set the client to nonblocking to simplify this test */
00724   arg = 1;
00725   ret = lwip_ioctl(sact, FIONBIO, &arg);
00726   fail_unless(ret == 0);
00727   /* connect */
00728   do {
00729     ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
00730     err = errno;
00731     fail_unless((ret == 0) || (ret == -1));
00732     if (ret != 0) {
00733       if (err == EISCONN) {
00734         /* Although this is not valid, use EISCONN as an indicator for successful connection.
00735            This marks us as "connect phase is done". On error, we would either have a different
00736            errno code or "send" fails later... -> good enough for this test. */
00737         ret = 0;
00738       } else {
00739         fail_unless(err == EINPROGRESS);
00740         if (err != EINPROGRESS) {
00741           goto cleanup;
00742         }
00743         /* we're in progress: little side check: test for EALREADY */
00744         ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
00745         err = errno;
00746         fail_unless(ret == -1);
00747         fail_unless(err == EALREADY);
00748         if ((ret != -1) || (err != EALREADY)) {
00749           goto cleanup;
00750         }
00751       }
00752       tcpip_thread_poll_one();
00753       tcpip_thread_poll_one();
00754       tcpip_thread_poll_one();
00755       tcpip_thread_poll_one();
00756     }
00757   } while (ret != 0);
00758   fail_unless(ret == 0);
00759 
00760   /* accept the server connection part */
00761   spass = lwip_accept(sl, NULL, NULL);
00762   fail_unless(spass >= 0);
00763 
00764   /* write data from client */
00765   ret = lwip_send(sact, txbuf, sizeof(txbuf), 0);
00766   fail_unless(ret == sizeof(txbuf));
00767 
00768   tcpip_thread_poll_one();
00769   tcpip_thread_poll_one();
00770 
00771   /* issue RST (This is a HACK, don't try this in your own app!) */
00772   sact_sock = lwip_socket_dbg_get_socket(sact);
00773   fail_unless(sact_sock != NULL);
00774   if (sact_sock != NULL) {
00775     struct netconn *sact_conn = sact_sock->conn;
00776     fail_unless(sact_conn != NULL);
00777     if (sact_conn != NULL) {
00778       struct tcp_pcb *pcb = sact_conn->pcb.tcp;
00779       fail_unless(pcb != NULL);
00780       if (pcb != NULL) {
00781         tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
00782                      pcb->local_port, pcb->remote_port);
00783       }
00784     }
00785   }
00786   tcpip_thread_poll_one();
00787   tcpip_thread_poll_one();
00788 
00789   /* expect to receive data first */
00790   ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
00791   fail_unless(ret > 0);
00792   tcpip_thread_poll_one();
00793   tcpip_thread_poll_one();
00794 
00795   /* expect to receive RST indication */
00796   ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
00797   fail_unless(ret == -1);
00798   err = errno;
00799   fail_unless(err == ECONNRESET);
00800   tcpip_thread_poll_one();
00801   tcpip_thread_poll_one();
00802 
00803   /* expect to receive ENOTCONN indication */
00804   ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
00805   fail_unless(ret == -1);
00806   err = errno;
00807   fail_unless(err == ENOTCONN);
00808   tcpip_thread_poll_one();
00809   tcpip_thread_poll_one();
00810 
00811   /* expect to receive ENOTCONN indication */
00812   ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
00813   fail_unless(ret == -1);
00814   err = errno;
00815   fail_unless(err == ENOTCONN);
00816   tcpip_thread_poll_one();
00817   tcpip_thread_poll_one();
00818 
00819 cleanup:
00820   ret = lwip_close(sl);
00821   fail_unless(ret == 0);
00822   ret = lwip_close(sact);
00823   fail_unless(ret == 0);
00824   if (spass >= 0) {
00825     ret = lwip_close(spass);
00826     fail_unless(ret == 0);
00827   }
00828 }
00829 END_TEST
00830 
00831 /** Create the suite including all tests for this module */
00832 Suite *
00833 sockets_suite(void)
00834 {
00835   testfunc tests[] = {
00836     TESTFUNC(test_sockets_basics),
00837     TESTFUNC(test_sockets_allfunctions_basic),
00838     TESTFUNC(test_sockets_msgapis),
00839     TESTFUNC(test_sockets_select),
00840     TESTFUNC(test_sockets_recv_after_rst),
00841   };
00842   return create_suite("SOCKETS", tests, sizeof(tests)/sizeof(testfunc), sockets_setup, sockets_teardown);
00843 }
00844 
00845 #else /* LWIP_SOCKET */
00846 
00847 Suite *
00848 sockets_suite(void)
00849 {
00850   return create_suite("SOCKETS", NULL, 0, NULL, NULL);
00851 }
00852 #endif /* LWIP_SOCKET */