123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852 |
- #include "test_sockets.h"
- #include "lwip/mem.h"
- #include "lwip/opt.h"
- #include "lwip/sockets.h"
- #include "lwip/priv/sockets_priv.h"
- #include "lwip/stats.h"
- #include "lwip/tcpip.h"
- #include "lwip/priv/tcp_priv.h"
- #include "lwip/api.h"
- static int
- test_sockets_get_used_count(void)
- {
- int used = 0;
- int i;
- for (i = 0; i < NUM_SOCKETS; i++) {
- struct lwip_sock* s = lwip_socket_dbg_get_socket(i);
- if (s != NULL) {
- if (s->fd_used) {
- used++;
- }
- }
- }
- return used;
- }
- /* Setups/teardown functions */
- static void
- sockets_setup(void)
- {
- /* expect full free heap */
- lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
- }
- static void
- sockets_teardown(void)
- {
- fail_unless(test_sockets_get_used_count() == 0);
- /* poll until all memory is released... */
- tcpip_thread_poll_one();
- while (tcp_tw_pcbs) {
- tcp_abort(tcp_tw_pcbs);
- tcpip_thread_poll_one();
- }
- tcpip_thread_poll_one();
- /* ensure full free heap */
- lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
- }
- #ifndef NUM_SOCKETS
- #define NUM_SOCKETS MEMP_NUM_NETCONN
- #endif
- #if LWIP_SOCKET
- static int
- test_sockets_alloc_socket_nonblocking(int domain, int type)
- {
- int s = lwip_socket(domain, type, 0);
- if (s >= 0) {
- int ret = lwip_fcntl(s, F_SETFL, O_NONBLOCK);
- fail_unless(ret == 0);
- }
- return s;
- }
- /* Verify basic sockets functionality
- */
- START_TEST(test_sockets_basics)
- {
- int s, i, ret;
- int s2[NUM_SOCKETS];
- LWIP_UNUSED_ARG(_i);
- s = lwip_socket(AF_INET, SOCK_STREAM, 0);
- fail_unless(s >= 0);
- lwip_close(s);
- for (i = 0; i < NUM_SOCKETS; i++) {
- s2[i] = lwip_socket(AF_INET, SOCK_STREAM, 0);
- fail_unless(s2[i] >= 0);
- }
- /* all sockets used, now it should fail */
- s = lwip_socket(AF_INET, SOCK_STREAM, 0);
- fail_unless(s == -1);
- /* close one socket */
- ret = lwip_close(s2[0]);
- fail_unless(ret == 0);
- /* now it should succeed */
- s2[0] = lwip_socket(AF_INET, SOCK_STREAM, 0);
- fail_unless(s2[0] >= 0);
- /* close all sockets */
- for (i = 0; i < NUM_SOCKETS; i++) {
- ret = lwip_close(s2[i]);
- fail_unless(ret == 0);
- }
- }
- END_TEST
- static void test_sockets_allfunctions_basic_domain(int domain)
- {
- int s, s2, s3, ret;
- struct sockaddr_storage addr, addr2;
- socklen_t addrlen, addr2len;
- char buf[4];
- /* listen socket */
- s = lwip_socket(domain, SOCK_STREAM, 0);
- fail_unless(s >= 0);
- ret = lwip_listen(s, 0);
- fail_unless(ret == 0);
- addrlen = sizeof(addr);
- ret = lwip_getsockname(s, (struct sockaddr*)&addr, &addrlen);
- fail_unless(ret == 0);
- s2 = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
- fail_unless(s2 >= 0);
- /* nonblocking connect s2 to s (but use loopback address) */
- if (domain == AF_INET) {
- #if LWIP_IPV4
- struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
- addr4->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
- #endif
- } else {
- #if LWIP_IPV6
- struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
- struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
- addr6->sin6_addr = lo6;
- #endif
- }
- ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
- fail_unless(ret == -1);
- fail_unless(errno == EINPROGRESS);
- ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
- fail_unless(ret == -1);
- fail_unless(errno == EALREADY);
- while(tcpip_thread_poll_one());
- s3 = lwip_accept(s, (struct sockaddr*)&addr2, &addr2len);
- fail_unless(s3 >= 0);
- ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
- fail_unless(ret == -1);
- fail_unless(errno == EISCONN);
- /* write from server to client */
- ret = lwip_write(s3, "test", 4);
- fail_unless(ret == 4);
- ret = lwip_shutdown(s3, SHUT_WR);
- fail_unless(ret == 0);
- while(tcpip_thread_poll_one());
- ret = lwip_recv(s2, buf, 3, MSG_PEEK);
- fail_unless(ret == 3);
- ret = lwip_recv(s2, buf, 3, MSG_PEEK);
- fail_unless(ret == 3);
- ret = lwip_read(s2, buf, 4);
- fail_unless(ret == 4);
- ret = lwip_read(s2, buf, 1);
- fail_unless(ret == 0);
- ret = lwip_read(s2, buf, 1);
- fail_unless(ret == -1);
- ret = lwip_write(s2, "foo", 3);
- fail_unless(ret == 3);
- ret = lwip_close(s2);
- fail_unless(ret == 0);
- while(tcpip_thread_poll_one());
- /* read one byte more than available to check handling FIN */
- ret = lwip_read(s3, buf, 4);
- fail_unless(ret == 3);
- ret = lwip_read(s3, buf, 1);
- fail_unless(ret == 0);
- ret = lwip_read(s3, buf, 1);
- fail_unless(ret == -1);
- while(tcpip_thread_poll_one());
- ret = lwip_close(s);
- fail_unless(ret == 0);
- ret = lwip_close(s3);
- fail_unless(ret == 0);
- }
- /* Try to step through all sockets functions once...
- */
- START_TEST(test_sockets_allfunctions_basic)
- {
- LWIP_UNUSED_ARG(_i);
- #if LWIP_IPV4
- test_sockets_allfunctions_basic_domain(AF_INET);
- #endif
- #if LWIP_IPV6
- test_sockets_allfunctions_basic_domain(AF_INET6);
- #endif
- }
- END_TEST
- static void test_sockets_init_loopback_addr(int domain, struct sockaddr_storage *addr_st, socklen_t *sz)
- {
- memset(addr_st, 0, sizeof(*addr_st));
- switch(domain) {
- #if LWIP_IPV6
- case AF_INET6: {
- struct sockaddr_in6 *addr = (struct sockaddr_in6*)addr_st;
- struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
- addr->sin6_family = AF_INET6;
- addr->sin6_port = 0; /* use ephemeral port */
- addr->sin6_addr = lo6;
- *sz = sizeof(*addr);
- }
- break;
- #endif /* LWIP_IPV6 */
- #if LWIP_IPV4
- case AF_INET: {
- struct sockaddr_in *addr = (struct sockaddr_in*)addr_st;
- addr->sin_family = AF_INET;
- addr->sin_port = 0; /* use ephemeral port */
- addr->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
- *sz = sizeof(*addr);
- }
- break;
- #endif /* LWIP_IPV4 */
- default:
- *sz = 0;
- fail();
- break;
- }
- }
- static void test_sockets_msgapi_update_iovs(struct msghdr *msg, size_t bytes)
- {
- msg_iovlen_t i;
- /* note: this modifies the underyling iov_base and iov_len for a partial
- read for an individual vector. This updates the msg->msg_iov pointer
- to skip fully consumed vectors */
-
- /* process fully consumed vectors */
- for (i = 0; i < msg->msg_iovlen; i++) {
- if (msg->msg_iov[i].iov_len <= bytes) {
- /* reduce bytes by amount of this vector */
- bytes -= msg->msg_iov[i].iov_len;
- } else {
- break; /* iov not fully consumed */
- }
- }
- /* slide down over fully consumed vectors */
- msg->msg_iov = &msg->msg_iov[i];
- msg->msg_iovlen -= i;
- /* update new first vector with any remaining amount */
- msg->msg_iov[0].iov_base = ((u8_t *)msg->msg_iov[0].iov_base + bytes);
- msg->msg_iov[0].iov_len -= bytes;
- }
- static void test_sockets_msgapi_tcp(int domain)
- {
- #define BUF_SZ (TCP_SND_BUF/4)
- #define TOTAL_DATA_SZ (BUF_SZ*8) /* ~(TCP_SND_BUF*2) that accounts for integer rounding */
- #define NEED_TRAILER (BUF_SZ % 4 != 0)
- int listnr, s1, s2, i, ret, opt;
- int bytes_written, bytes_read;
- struct sockaddr_storage addr_storage;
- socklen_t addr_size;
- struct iovec siovs[8];
- struct msghdr smsg;
- u8_t * snd_buf;
- struct iovec riovs[5];
- struct iovec riovs_tmp[5];
- struct msghdr rmsg;
- u8_t * rcv_buf;
- int rcv_off;
- int rcv_trailer = 0;
- u8_t val;
- test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
- listnr = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
- fail_unless(listnr >= 0);
- s1 = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
- fail_unless(s1 >= 0);
- /* setup a listener socket on loopback with ephemeral port */
- ret = lwip_bind(listnr, (struct sockaddr*)&addr_storage, addr_size);
- fail_unless(ret == 0);
- ret = lwip_listen(listnr, 0);
- fail_unless(ret == 0);
- /* update address with ephemeral port */
- ret = lwip_getsockname(listnr, (struct sockaddr*)&addr_storage, &addr_size);
- fail_unless(ret == 0);
- /* connect, won't complete until we accept it */
- ret = lwip_connect(s1, (struct sockaddr*)&addr_storage, addr_size);
- fail_unless(ret == -1);
- fail_unless(errno == EINPROGRESS);
- while (tcpip_thread_poll_one());
- /* accept, creating the other side of the connection */
- s2 = lwip_accept(listnr, NULL, NULL);
- fail_unless(s2 >= 0);
- /* double check s1 is connected */
- ret = lwip_connect(s1, (struct sockaddr*)&addr_storage, addr_size);
- fail_unless(ret == -1);
- fail_unless(errno == EISCONN);
- /* set s2 to non-blocking, not inherited from listener */
- opt = lwip_fcntl(s2, F_GETFL, 0);
- fail_unless(opt == O_RDWR);
- opt = O_NONBLOCK;
- ret = lwip_fcntl(s2, F_SETFL, opt);
- fail_unless(ret == 0);
- /* we are done with listener, close it */
- ret = lwip_close(listnr);
- fail_unless(ret == 0);
- /* allocate a buffer for a stream of incrementing hex (0x00..0xFF) which we will use
- to create an input vector set that is larger than the TCP's send buffer. This will
- force execution of the partial IO vector send case */
- snd_buf = (u8_t*)mem_malloc(BUF_SZ);
- val = 0x00;
- fail_unless(snd_buf != NULL);
- for (i = 0; i < BUF_SZ; i++,val++) {
- snd_buf[i] = val;
- }
- /* send the buffer 8 times in one message, equating to TOTAL_DATA_SZ */
- for (i = 0; i < 8; i++) {
- siovs[i].iov_base = snd_buf;
- siovs[i].iov_len = BUF_SZ;
- }
- /* allocate a receive buffer, same size as snd_buf for easy verification */
- rcv_buf = (u8_t*)mem_calloc(1, BUF_SZ);
- fail_unless(rcv_buf != NULL);
- /* split across iovs */
- for (i = 0; i < 4; i++) {
- riovs[i].iov_base = &rcv_buf[i*(BUF_SZ/4)];
- riovs[i].iov_len = BUF_SZ/4;
- }
- /* handling trailing bytes if buffer doesn't evenly divide by 4 */
- #if NEED_TRAILER
- if ((BUF_SZ % 4) != 0) {
- riovs[5].iov_base = &rcv_buf[4*(BUF_SZ/4)];
- riovs[5].iov_len = BUF_SZ - (4*(BUF_SZ/4));
- rcv_trailer = 1;
- }
- #endif /* NEED_TRAILER */
- /* we use a copy of riovs since we'll be modifying base and len during
- receiving. This gives us an easy way to reset the iovs for next recvmsg */
- memcpy(riovs_tmp, riovs, sizeof(riovs));
- memset(&smsg, 0, sizeof(smsg));
- smsg.msg_iov = siovs;
- smsg.msg_iovlen = 8;
- memset(&rmsg, 0, sizeof(rmsg));
- rmsg.msg_iov = riovs_tmp;
- rmsg.msg_iovlen = (rcv_trailer ? 5 : 4);
- bytes_written = 0;
- bytes_read = 0;
- rcv_off = 0;
- while (bytes_written < TOTAL_DATA_SZ && (bytes_read < TOTAL_DATA_SZ)) {
- /* send data */
- if (bytes_written < TOTAL_DATA_SZ) {
- ret = lwip_sendmsg(s1, &smsg, 0);
- /* note: since we always receive after sending, there will be open
- space in the send buffer */
- fail_unless(ret > 0);
-
- bytes_written += ret;
- if (bytes_written < TOTAL_DATA_SZ) {
- test_sockets_msgapi_update_iovs(&smsg, (size_t)ret);
- }
- }
- while (tcpip_thread_poll_one());
- /* receive and verify data */
- do {
- if (bytes_read < TOTAL_DATA_SZ) {
- ret = lwip_recvmsg(s2, &rmsg, 0);
- fail_unless(ret > 0 || (ret == -1 && errno == EWOULDBLOCK));
- if (ret > 0) {
- rcv_off += ret;
- /* we have received a full buffer */
- if (rcv_off == BUF_SZ) {
- /* note: since iovs are just pointers, compare underlying buf */
- fail_unless(!memcmp(snd_buf, rcv_buf, BUF_SZ));
- bytes_read += BUF_SZ;
- /* reset receive state for next buffer */
- rcv_off = 0;
- memset(rcv_buf, 0, BUF_SZ);
- memcpy(riovs_tmp, riovs, sizeof(riovs));
- rmsg.msg_iov = riovs_tmp;
- rmsg.msg_iovlen = (rcv_trailer ? 5 : 4);
- } else { /* partial read */
- test_sockets_msgapi_update_iovs(&rmsg, (size_t)ret);
- }
- }
- } else {
- break;
- }
- } while(ret > 0);
- }
-
- ret = lwip_close(s1);
- fail_unless(ret == 0);
- ret = lwip_close(s2);
- fail_unless(ret == 0);
- mem_free(snd_buf);
- mem_free(rcv_buf);
- }
- static void test_sockets_msgapi_udp_send_recv_loop(int s, struct msghdr *smsg, struct msghdr *rmsg)
- {
- int i, ret;
- /* send/receive our datagram of IO vectors 10 times */
- for (i = 0; i < 10; i++) {
- ret = lwip_sendmsg(s, smsg, 0);
- fail_unless(ret == 4);
- while (tcpip_thread_poll_one());
- /* receive the datagram split across 4 buffers */
- ret = lwip_recvmsg(s, rmsg, 0);
- fail_unless(ret == 4);
- /* verify data */
- fail_unless(*((u8_t*)rmsg->msg_iov[0].iov_base) == 0xDE);
- fail_unless(*((u8_t*)rmsg->msg_iov[1].iov_base) == 0xAD);
- fail_unless(*((u8_t*)rmsg->msg_iov[2].iov_base) == 0xBE);
- fail_unless(*((u8_t*)rmsg->msg_iov[3].iov_base) == 0xEF);
- /* clear rcv_buf to ensure no data is being skipped */
- *((u8_t*)rmsg->msg_iov[0].iov_base) = 0x00;
- *((u8_t*)rmsg->msg_iov[1].iov_base) = 0x00;
- *((u8_t*)rmsg->msg_iov[2].iov_base) = 0x00;
- *((u8_t*)rmsg->msg_iov[3].iov_base) = 0x00;
- }
- }
- static void test_sockets_msgapi_udp(int domain)
- {
- int s, i, ret;
- struct sockaddr_storage addr_storage;
- socklen_t addr_size;
- struct iovec riovs[4];
- struct msghdr rmsg;
- u8_t rcv_buf[4];
- struct iovec siovs[4];
- struct msghdr smsg;
- u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF};
- /* initialize IO vectors with data */
- for (i = 0; i < 4; i++) {
- siovs[i].iov_base = &snd_buf[i];
- siovs[i].iov_len = sizeof(u8_t);
- riovs[i].iov_base = &rcv_buf[i];
- riovs[i].iov_len = sizeof(u8_t);
- }
- test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
- s = test_sockets_alloc_socket_nonblocking(domain, SOCK_DGRAM);
- fail_unless(s >= 0);
- ret = lwip_bind(s, (struct sockaddr*)&addr_storage, addr_size);
- fail_unless(ret == 0);
- /* Update addr with epehermal port */
- ret = lwip_getsockname(s, (struct sockaddr*)&addr_storage, &addr_size);
- fail_unless(ret == 0);
- switch(domain) {
- #if LWIP_IPV6
- case AF_INET6:
- fail_unless(addr_size == sizeof(struct sockaddr_in6));
- break;
- #endif /* LWIP_IPV6 */
- #if LWIP_IPV4
- case AF_INET:
- fail_unless(addr_size == sizeof(struct sockaddr_in));
- break;
- #endif /* LWIP_IPV6 */
- default:
- fail();
- break;
- }
- /* send and receive the datagram in 4 pieces */
- memset(&smsg, 0, sizeof(smsg));
- smsg.msg_iov = siovs;
- smsg.msg_iovlen = 4;
- memset(&rmsg, 0, sizeof(rmsg));
- rmsg.msg_iov = riovs;
- rmsg.msg_iovlen = 4;
- /* perform a sendmsg with remote host (self) */
- smsg.msg_name = &addr_storage;
- smsg.msg_namelen = addr_size;
- test_sockets_msgapi_udp_send_recv_loop(s, &smsg, &rmsg);
- /* Connect to self, allowing us to not pass message name */
- ret = lwip_connect(s, (struct sockaddr*)&addr_storage, addr_size);
- fail_unless(ret == 0);
- smsg.msg_name = NULL;
- smsg.msg_namelen = 0;
- test_sockets_msgapi_udp_send_recv_loop(s, &smsg, &rmsg);
- ret = lwip_close(s);
- fail_unless(ret == 0);
- }
- #if LWIP_IPV4
- static void test_sockets_msgapi_cmsg(int domain)
- {
- int s, ret, enable;
- struct sockaddr_storage addr_storage;
- socklen_t addr_size;
- struct iovec iov;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- struct in_pktinfo *pktinfo;
- u8_t rcv_buf[4];
- u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF};
- u8_t cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
- test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
- s = test_sockets_alloc_socket_nonblocking(domain, SOCK_DGRAM);
- fail_unless(s >= 0);
- ret = lwip_bind(s, (struct sockaddr*)&addr_storage, addr_size);
- fail_unless(ret == 0);
- /* Update addr with epehermal port */
- ret = lwip_getsockname(s, (struct sockaddr*)&addr_storage, &addr_size);
- fail_unless(ret == 0);
- enable = 1;
- ret = lwip_setsockopt(s, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable));
- fail_unless(ret == 0);
- /* Receive full message, including control message */
- iov.iov_base = rcv_buf;
- iov.iov_len = sizeof(rcv_buf);
- msg.msg_control = cmsg_buf;
- msg.msg_controllen = sizeof(cmsg_buf);
- msg.msg_flags = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- memset(rcv_buf, 0, sizeof(rcv_buf));
- ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size);
- fail_unless(ret == sizeof(snd_buf));
-
- tcpip_thread_poll_one();
- ret = lwip_recvmsg(s, &msg, 0);
- fail_unless(ret == sizeof(rcv_buf));
- fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf)));
-
- /* Verify message header */
- cmsg = CMSG_FIRSTHDR(&msg);
- fail_unless(cmsg != NULL);
- fail_unless(cmsg->cmsg_len > 0);
- fail_unless(cmsg->cmsg_level == IPPROTO_IP);
- fail_unless(cmsg->cmsg_type == IP_PKTINFO);
- /* Verify message data */
- pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
- /* We only have loopback interface enabled */
- fail_unless(pktinfo->ipi_ifindex == 1);
- fail_unless(pktinfo->ipi_addr.s_addr == PP_HTONL(INADDR_LOOPBACK));
- /* Verify there are no additional messages */
- cmsg = CMSG_NXTHDR(&msg, cmsg);
- fail_unless(cmsg == NULL);
- /* Send datagram again, testing truncation */
- memset(rcv_buf, 0, sizeof(rcv_buf));
- ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size);
- fail_unless(ret == sizeof(snd_buf));
- tcpip_thread_poll_one();
- msg.msg_controllen = 1;
- msg.msg_flags = 0;
- ret = lwip_recvmsg(s, &msg, 0);
- fail_unless(ret == sizeof(rcv_buf));
- fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf)));
- /* Ensure truncation was returned */
- fail_unless(msg.msg_flags & MSG_CTRUNC);
- /* Ensure no control messages were returned */
- fail_unless(msg.msg_controllen == 0);
- ret = lwip_close(s);
- fail_unless(ret == 0);
- }
- #endif /* LWIP_IPV4 */
- START_TEST(test_sockets_msgapis)
- {
- LWIP_UNUSED_ARG(_i);
- #if LWIP_IPV4
- test_sockets_msgapi_udp(AF_INET);
- test_sockets_msgapi_tcp(AF_INET);
- test_sockets_msgapi_cmsg(AF_INET);
- #endif
- #if LWIP_IPV6
- test_sockets_msgapi_udp(AF_INET6);
- test_sockets_msgapi_tcp(AF_INET6);
- #endif
- }
- END_TEST
- START_TEST(test_sockets_select)
- {
- #if LWIP_SOCKET_SELECT
- int s;
- int ret;
- fd_set readset;
- fd_set writeset;
- fd_set errset;
- struct timeval tv;
- fail_unless(test_sockets_get_used_count() == 0);
- s = lwip_socket(AF_INET, SOCK_STREAM, 0);
- fail_unless(s >= 0);
- fail_unless(test_sockets_get_used_count() == 0);
- FD_ZERO(&readset);
- FD_SET(s, &readset);
- FD_ZERO(&writeset);
- FD_SET(s, &writeset);
- FD_ZERO(&errset);
- FD_SET(s, &errset);
- tv.tv_sec = tv.tv_usec = 0;
- ret = lwip_select(s + 1, &readset, &writeset, &errset, &tv);
- fail_unless(ret == 0);
- fail_unless(test_sockets_get_used_count() == 0);
- ret = lwip_close(s);
- fail_unless(ret == 0);
- #endif
- LWIP_UNUSED_ARG(_i);
- }
- END_TEST
- START_TEST(test_sockets_recv_after_rst)
- {
- int sl, sact;
- int spass = -1;
- int ret;
- struct sockaddr_in sa_listen;
- const u16_t port = 1234;
- int arg;
- const char txbuf[] = "something";
- char rxbuf[16];
- struct lwip_sock *sact_sock;
- int err;
- LWIP_UNUSED_ARG(_i);
- fail_unless(test_sockets_get_used_count() == 0);
- memset(&sa_listen, 0, sizeof(sa_listen));
- sa_listen.sin_family = AF_INET;
- sa_listen.sin_port = PP_HTONS(port);
- sa_listen.sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
- /* set up the listener */
- sl = lwip_socket(AF_INET, SOCK_STREAM, 0);
- fail_unless(sl >= 0);
- fail_unless(test_sockets_get_used_count() == 0);
- ret = lwip_bind(sl, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
- fail_unless(ret == 0);
- ret = lwip_listen(sl, 0);
- fail_unless(ret == 0);
- /* set up the client */
- sact = lwip_socket(AF_INET, SOCK_STREAM, 0);
- fail_unless(sact >= 0);
- fail_unless(test_sockets_get_used_count() == 0);
- /* set the client to nonblocking to simplify this test */
- arg = 1;
- ret = lwip_ioctl(sact, FIONBIO, &arg);
- fail_unless(ret == 0);
- /* connect */
- do {
- ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
- err = errno;
- fail_unless((ret == 0) || (ret == -1));
- if (ret != 0) {
- if (err == EISCONN) {
- /* Although this is not valid, use EISCONN as an indicator for successful connection.
- This marks us as "connect phase is done". On error, we would either have a different
- errno code or "send" fails later... -> good enough for this test. */
- ret = 0;
- } else {
- fail_unless(err == EINPROGRESS);
- if (err != EINPROGRESS) {
- goto cleanup;
- }
- /* we're in progress: little side check: test for EALREADY */
- ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
- err = errno;
- fail_unless(ret == -1);
- fail_unless(err == EALREADY);
- if ((ret != -1) || (err != EALREADY)) {
- goto cleanup;
- }
- }
- tcpip_thread_poll_one();
- tcpip_thread_poll_one();
- tcpip_thread_poll_one();
- tcpip_thread_poll_one();
- }
- } while (ret != 0);
- fail_unless(ret == 0);
- /* accept the server connection part */
- spass = lwip_accept(sl, NULL, NULL);
- fail_unless(spass >= 0);
- /* write data from client */
- ret = lwip_send(sact, txbuf, sizeof(txbuf), 0);
- fail_unless(ret == sizeof(txbuf));
- tcpip_thread_poll_one();
- tcpip_thread_poll_one();
- /* issue RST (This is a HACK, don't try this in your own app!) */
- sact_sock = lwip_socket_dbg_get_socket(sact);
- fail_unless(sact_sock != NULL);
- if (sact_sock != NULL) {
- struct netconn *sact_conn = sact_sock->conn;
- fail_unless(sact_conn != NULL);
- if (sact_conn != NULL) {
- struct tcp_pcb *pcb = sact_conn->pcb.tcp;
- fail_unless(pcb != NULL);
- if (pcb != NULL) {
- tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
- pcb->local_port, pcb->remote_port);
- }
- }
- }
- tcpip_thread_poll_one();
- tcpip_thread_poll_one();
- /* expect to receive data first */
- ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
- fail_unless(ret > 0);
- tcpip_thread_poll_one();
- tcpip_thread_poll_one();
- /* expect to receive RST indication */
- ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
- fail_unless(ret == -1);
- err = errno;
- fail_unless(err == ECONNRESET);
- tcpip_thread_poll_one();
- tcpip_thread_poll_one();
- /* expect to receive ENOTCONN indication */
- ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
- fail_unless(ret == -1);
- err = errno;
- fail_unless(err == ENOTCONN);
- tcpip_thread_poll_one();
- tcpip_thread_poll_one();
- /* expect to receive ENOTCONN indication */
- ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
- fail_unless(ret == -1);
- err = errno;
- fail_unless(err == ENOTCONN);
- tcpip_thread_poll_one();
- tcpip_thread_poll_one();
- cleanup:
- ret = lwip_close(sl);
- fail_unless(ret == 0);
- ret = lwip_close(sact);
- fail_unless(ret == 0);
- if (spass >= 0) {
- ret = lwip_close(spass);
- fail_unless(ret == 0);
- }
- }
- END_TEST
- /** Create the suite including all tests for this module */
- Suite *
- sockets_suite(void)
- {
- testfunc tests[] = {
- TESTFUNC(test_sockets_basics),
- TESTFUNC(test_sockets_allfunctions_basic),
- TESTFUNC(test_sockets_msgapis),
- TESTFUNC(test_sockets_select),
- TESTFUNC(test_sockets_recv_after_rst),
- };
- return create_suite("SOCKETS", tests, sizeof(tests)/sizeof(testfunc), sockets_setup, sockets_teardown);
- }
- #else /* LWIP_SOCKET */
- Suite *
- sockets_suite(void)
- {
- return create_suite("SOCKETS", NULL, 0, NULL, NULL);
- }
- #endif /* LWIP_SOCKET */
|