| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "os/mynewt.h" |
| #include "testutil/testutil.h" |
| |
| #include "mn_socket/mn_socket.h" |
| |
| struct os_sem test_sem; |
| |
| void |
| sock_open_close(void) |
| { |
| struct mn_socket *sock; |
| int rc; |
| |
| rc = mn_socket(&sock, MN_PF_INET, MN_SOCK_DGRAM, 0); |
| TEST_ASSERT(sock); |
| TEST_ASSERT(rc == 0); |
| mn_close(sock); |
| |
| rc = mn_socket(&sock, MN_PF_INET, MN_SOCK_STREAM, 0); |
| TEST_ASSERT(sock); |
| TEST_ASSERT(rc == 0); |
| mn_close(sock); |
| |
| rc = mn_socket(&sock, MN_PF_INET6, MN_SOCK_DGRAM, 0); |
| TEST_ASSERT(sock); |
| TEST_ASSERT(rc == 0); |
| mn_close(sock); |
| |
| rc = mn_socket(&sock, MN_PF_INET6, MN_SOCK_STREAM, 0); |
| TEST_ASSERT(sock); |
| TEST_ASSERT(rc == 0); |
| mn_close(sock); |
| } |
| |
| void |
| sock_listen(void) |
| { |
| struct mn_socket *sock; |
| struct mn_sockaddr_in msin; |
| int rc; |
| |
| rc = mn_socket(&sock, MN_PF_INET, MN_SOCK_STREAM, 0); |
| TEST_ASSERT(rc == 0); |
| |
| msin.msin_family = MN_PF_INET; |
| msin.msin_len = sizeof(msin); |
| msin.msin_port = htons(12444); |
| |
| mn_inet_pton(MN_PF_INET, "127.0.0.1", &msin.msin_addr); |
| |
| rc = mn_bind(sock, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_listen(sock, 2); |
| TEST_ASSERT(rc == 0); |
| |
| mn_close(sock); |
| } |
| |
| void |
| stc_writable(void *cb_arg, int err) |
| { |
| int *i; |
| |
| TEST_ASSERT(err == 0); |
| i = (int *)cb_arg; |
| *i = *i + 1; |
| |
| /* |
| * The first instance of writability indicates an established connection. |
| * Unblock the test case. |
| */ |
| if (*i == 1) { |
| os_sem_release(&test_sem); |
| } |
| } |
| |
| int |
| stc_newconn(void *cb_arg, struct mn_socket *new) |
| { |
| struct mn_socket **r_sock; |
| |
| r_sock = cb_arg; |
| *r_sock = new; |
| |
| os_sem_release(&test_sem); |
| return 0; |
| } |
| |
| void |
| sock_tcp_connect(void) |
| { |
| struct mn_socket *listen_sock; |
| struct mn_socket *sock; |
| struct mn_sockaddr_in msin; |
| struct mn_sockaddr_in msin2; |
| int rc; |
| union mn_socket_cb listen_cbs = { |
| .listen.newconn = stc_newconn, |
| }; |
| union mn_socket_cb sock_cbs = { |
| .socket.writable = stc_writable |
| }; |
| int connected = 0; |
| struct mn_socket *new_sock = NULL; |
| |
| rc = mn_socket(&listen_sock, MN_PF_INET, MN_SOCK_STREAM, 0); |
| TEST_ASSERT(rc == 0); |
| |
| msin.msin_family = MN_PF_INET; |
| msin.msin_len = sizeof(msin); |
| msin.msin_port = htons(12445); |
| |
| mn_inet_pton(MN_PF_INET, "127.0.0.1", &msin.msin_addr); |
| |
| mn_socket_set_cbs(listen_sock, &new_sock, &listen_cbs); |
| rc = mn_bind(listen_sock, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_listen(listen_sock, 2); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_socket(&sock, MN_PF_INET, MN_SOCK_STREAM, 0); |
| TEST_ASSERT(rc == 0); |
| |
| mn_socket_set_cbs(sock, &connected, &sock_cbs); |
| |
| rc = mn_connect(sock, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| /* |
| * Wait for both connections to be established. |
| */ |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == 0); |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == 0); |
| |
| TEST_ASSERT(connected == 1); |
| TEST_ASSERT(new_sock != NULL); |
| |
| /* |
| * Check endpoint data matches |
| */ |
| rc = mn_getsockname(sock, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| rc = mn_getpeername(new_sock, (struct mn_sockaddr *)&msin2); |
| TEST_ASSERT(rc == 0); |
| TEST_ASSERT(!memcmp(&msin, &msin2, sizeof(msin))); |
| |
| rc = mn_getsockname(new_sock, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| rc = mn_getpeername(sock, (struct mn_sockaddr *)&msin2); |
| TEST_ASSERT(rc == 0); |
| TEST_ASSERT(!memcmp(&msin, &msin2, sizeof(msin))); |
| |
| |
| if (new_sock) { |
| mn_close(new_sock); |
| } |
| mn_close(sock); |
| mn_close(listen_sock); |
| } |
| |
| void |
| sud_readable(void *cb_arg, int err) |
| { |
| os_sem_release(&test_sem); |
| } |
| |
| void |
| sock_udp_data(void) |
| { |
| struct mn_socket *sock1; |
| struct mn_socket *sock2; |
| struct mn_sockaddr_in msin; |
| struct mn_sockaddr_in msin2; |
| int rc; |
| union mn_socket_cb sock_cbs = { |
| .socket.readable = sud_readable |
| }; |
| struct os_mbuf *m; |
| char data[] = "1234567890"; |
| |
| rc = mn_socket(&sock1, MN_PF_INET, MN_SOCK_DGRAM, 0); |
| TEST_ASSERT(rc == 0); |
| mn_socket_set_cbs(sock1, NULL, &sock_cbs); |
| |
| rc = mn_socket(&sock2, MN_PF_INET, MN_SOCK_DGRAM, 0); |
| TEST_ASSERT(rc == 0); |
| mn_socket_set_cbs(sock2, NULL, &sock_cbs); |
| |
| msin.msin_family = MN_PF_INET; |
| msin.msin_len = sizeof(msin); |
| msin.msin_port = htons(12445); |
| |
| mn_inet_pton(MN_PF_INET, "127.0.0.1", &msin.msin_addr); |
| |
| rc = mn_bind(sock1, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| msin2.msin_family = MN_PF_INET; |
| msin2.msin_len = sizeof(msin2); |
| msin2.msin_port = 0; |
| msin2.msin_addr.s_addr = 0; |
| rc = mn_bind(sock2, (struct mn_sockaddr *)&msin2); |
| TEST_ASSERT(rc == 0); |
| |
| m = os_msys_get(sizeof(data), 0); |
| TEST_ASSERT(m); |
| rc = os_mbuf_copyinto(m, 0, data, sizeof(data)); |
| TEST_ASSERT(rc == 0); |
| rc = mn_sendto(sock2, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| /* |
| * Wait for the packet. |
| */ |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_recvfrom(sock1, &m, (struct mn_sockaddr *)&msin2); |
| TEST_ASSERT(rc == 0); |
| TEST_ASSERT(m != NULL); |
| TEST_ASSERT(msin2.msin_family == MN_AF_INET); |
| TEST_ASSERT(msin2.msin_len == sizeof(msin2)); |
| TEST_ASSERT(msin2.msin_port != 0); |
| TEST_ASSERT(msin2.msin_addr.s_addr != 0); |
| |
| if (m) { |
| TEST_ASSERT(OS_MBUF_IS_PKTHDR(m)); |
| TEST_ASSERT(OS_MBUF_PKTLEN(m) == sizeof(data)); |
| TEST_ASSERT(m->om_len == sizeof(data)); |
| TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data))); |
| } |
| |
| rc = mn_sendto(sock1, m, (struct mn_sockaddr *)&msin2); |
| TEST_ASSERT(rc == 0); |
| |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_recvfrom(sock2, &m, (struct mn_sockaddr *)&msin2); |
| TEST_ASSERT(rc == 0); |
| TEST_ASSERT(m != NULL); |
| if (m) { |
| TEST_ASSERT(OS_MBUF_IS_PKTHDR(m)); |
| TEST_ASSERT(OS_MBUF_PKTLEN(m) == sizeof(data)); |
| TEST_ASSERT(m->om_len == sizeof(data)); |
| TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data))); |
| os_mbuf_free_chain(m); |
| } |
| |
| mn_close(sock1); |
| mn_close(sock2); |
| } |
| |
| void |
| std_writable(void *cb_arg, int err) |
| { |
| int *i; |
| |
| TEST_ASSERT(err == 0); |
| |
| i = (int *)cb_arg; |
| TEST_ASSERT_FATAL(i != NULL); |
| |
| *i = *i + 1; |
| |
| /* |
| * The first instance of writability indicates an established connection. |
| * Unblock the test case. |
| */ |
| if (*i == 1) { |
| os_sem_release(&test_sem); |
| } |
| } |
| |
| void |
| std_readable(void *cb_arg, int err) |
| { |
| os_sem_release(&test_sem); |
| } |
| |
| static union mn_socket_cb sud_sock_cbs = { |
| .socket.writable = std_writable, |
| .socket.readable = std_readable |
| }; |
| |
| int |
| std_newconn(void *cb_arg, struct mn_socket *new) |
| { |
| struct mn_socket **r_sock; |
| |
| r_sock = cb_arg; |
| *r_sock = new; |
| |
| mn_socket_set_cbs(new, NULL, &sud_sock_cbs); |
| |
| os_sem_release(&test_sem); |
| return 0; |
| } |
| |
| void |
| sock_tcp_data(void) |
| { |
| struct mn_socket *listen_sock; |
| struct mn_socket *sock; |
| struct mn_sockaddr_in msin; |
| int rc; |
| union mn_socket_cb listen_cbs = { |
| .listen.newconn = std_newconn, |
| }; |
| int connected = 0; |
| struct mn_socket *new_sock = NULL; |
| struct os_mbuf *m; |
| char data[] = "1234567890"; |
| |
| rc = mn_socket(&listen_sock, MN_PF_INET, MN_SOCK_STREAM, 0); |
| TEST_ASSERT(rc == 0); |
| |
| msin.msin_family = MN_PF_INET; |
| msin.msin_len = sizeof(msin); |
| msin.msin_port = htons(12447); |
| |
| mn_inet_pton(MN_PF_INET, "127.0.0.1", &msin.msin_addr); |
| |
| mn_socket_set_cbs(listen_sock, &new_sock, &listen_cbs); |
| rc = mn_bind(listen_sock, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_listen(listen_sock, 2); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_socket(&sock, MN_PF_INET, MN_SOCK_STREAM, 0); |
| TEST_ASSERT(rc == 0); |
| |
| mn_socket_set_cbs(sock, &connected, &sud_sock_cbs); |
| |
| rc = mn_connect(sock, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| /* |
| * Wait for both connections to be established. |
| */ |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == 0); |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == 0); |
| |
| TEST_ASSERT(connected == 1); |
| TEST_ASSERT(new_sock != NULL); |
| |
| m = os_msys_get(sizeof(data), 0); |
| TEST_ASSERT(m); |
| rc = os_mbuf_copyinto(m, 0, data, sizeof(data)); |
| TEST_ASSERT(rc == 0); |
| rc = mn_sendto(new_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| /* |
| * Wait for the packet. |
| */ |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == 0); |
| |
| memset(&msin, 0, sizeof(msin)); |
| rc = mn_recvfrom(sock, &m, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| TEST_ASSERT(m != NULL); |
| TEST_ASSERT(msin.msin_family == MN_AF_INET); |
| TEST_ASSERT(msin.msin_len == sizeof(msin)); |
| TEST_ASSERT(msin.msin_port != 0); |
| TEST_ASSERT(msin.msin_addr.s_addr != 0); |
| os_mbuf_free_chain(m); |
| |
| mn_close(new_sock); |
| mn_close(sock); |
| mn_close(listen_sock); |
| } |
| |
| void |
| sock_itf_list(void) |
| { |
| struct mn_itf itf; |
| struct mn_itf_addr itf_addr; |
| int if_cnt = 0; |
| int seen_127 = 0; |
| struct mn_in_addr addr127; |
| char addr_str[64]; |
| int rc; |
| |
| mn_inet_pton(MN_PF_INET, "127.0.0.1", &addr127); |
| |
| memset(&itf, 0, sizeof(itf)); |
| |
| while (1) { |
| rc = mn_itf_getnext(&itf); |
| if (rc) { |
| break; |
| } |
| printf("%d: %x %s\n", itf.mif_idx, itf.mif_flags, itf.mif_name); |
| memset(&itf_addr, 0, sizeof(itf_addr)); |
| while (1) { |
| rc = mn_itf_addr_getnext(&itf, &itf_addr); |
| if (rc) { |
| break; |
| } |
| if (itf_addr.mifa_family == MN_AF_INET && |
| !memcmp(&itf_addr.mifa_addr, &addr127, sizeof(addr127))) { |
| seen_127 = 1; |
| } |
| addr_str[0] = '\0'; |
| mn_inet_ntop(itf_addr.mifa_family, &itf_addr.mifa_addr, |
| addr_str, sizeof(addr_str)); |
| printf(" %s/%d\n", addr_str, itf_addr.mifa_plen); |
| } |
| if_cnt++; |
| } |
| TEST_ASSERT(if_cnt > 0); |
| TEST_ASSERT(seen_127); |
| } |
| |
| static int |
| first_ll_addr(struct mn_sockaddr_in6 *ra) |
| { |
| struct mn_itf itf; |
| struct mn_itf_addr itf_addr; |
| int rc; |
| struct mn_in6_addr *addr; |
| |
| memset(&itf, 0, sizeof(itf)); |
| addr = (struct mn_in6_addr *)&itf_addr.mifa_addr; |
| while (1) { |
| rc = mn_itf_getnext(&itf); |
| if (rc) { |
| break; |
| } |
| memset(&itf_addr, 0, sizeof(itf_addr)); |
| while (1) { |
| rc = mn_itf_addr_getnext(&itf, &itf_addr); |
| if (rc) { |
| break; |
| } |
| if (itf_addr.mifa_family == MN_AF_INET6 && |
| addr->s_addr[0] == 0xfe && addr->s_addr[1] == 0x80) { |
| memset(ra, 0, sizeof(*ra)); |
| ra->msin6_family = MN_AF_INET6; |
| ra->msin6_len = sizeof(*ra); |
| ra->msin6_scope_id = itf.mif_idx; |
| memcpy(&ra->msin6_addr, addr, sizeof(*addr)); |
| return 0; |
| } |
| } |
| } |
| return -1; |
| } |
| |
| void |
| sul_readable(void *cb_arg, int err) |
| { |
| os_sem_release(&test_sem); |
| } |
| |
| void |
| sock_udp_ll(void) |
| { |
| struct mn_socket *sock1; |
| struct mn_socket *sock2; |
| struct mn_sockaddr_in6 msin; |
| struct mn_sockaddr_in6 msin2; |
| int rc; |
| union mn_socket_cb sock_cbs = { |
| .socket.readable = sul_readable |
| }; |
| struct os_mbuf *m; |
| char data[] = "1234567890"; |
| |
| rc = mn_socket(&sock1, MN_PF_INET6, MN_SOCK_DGRAM, 0); |
| TEST_ASSERT(rc == 0); |
| mn_socket_set_cbs(sock1, NULL, &sock_cbs); |
| |
| rc = mn_socket(&sock2, MN_PF_INET6, MN_SOCK_DGRAM, 0); |
| TEST_ASSERT(rc == 0); |
| mn_socket_set_cbs(sock2, NULL, &sock_cbs); |
| |
| rc = first_ll_addr(&msin); |
| if (rc != 0) { |
| printf("No ipv6 address present?\n"); |
| return; |
| } |
| msin.msin6_port = htons(12445); |
| |
| rc = mn_bind(sock1, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_getsockname(sock1, (struct mn_sockaddr *)&msin2); |
| TEST_ASSERT(rc == 0); |
| |
| m = os_msys_get(sizeof(data), 0); |
| TEST_ASSERT(m); |
| rc = os_mbuf_copyinto(m, 0, data, sizeof(data)); |
| TEST_ASSERT(rc == 0); |
| rc = mn_sendto(sock2, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin2); |
| TEST_ASSERT(rc == 0); |
| |
| /* |
| * Wait for the packet. |
| */ |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_recvfrom(sock1, &m, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| TEST_ASSERT(m != NULL); |
| |
| if (m) { |
| TEST_ASSERT(OS_MBUF_IS_PKTHDR(m)); |
| TEST_ASSERT(OS_MBUF_PKTLEN(m) == sizeof(data)); |
| TEST_ASSERT(m->om_len == sizeof(data)); |
| TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data))); |
| os_mbuf_free_chain(m); |
| } |
| |
| mn_close(sock1); |
| mn_close(sock2); |
| } |
| |
| static int |
| sock_find_multicast_if(void) |
| { |
| struct mn_itf itf; |
| |
| memset(&itf, 0, sizeof(itf)); |
| |
| while (1) { |
| if (mn_itf_getnext(&itf)) { |
| break; |
| } |
| if ((itf.mif_flags & MN_ITF_F_UP) == 0) { |
| continue; |
| } |
| |
| if ((itf.mif_flags & MN_ITF_F_LINK) == 0) { |
| continue; |
| } |
| |
| if (itf.mif_flags & MN_ITF_F_MULTICAST) { |
| return itf.mif_idx; |
| } |
| } |
| return -1; |
| } |
| |
| void |
| sum4_readable(void *cb_arg, int err) |
| { |
| os_sem_release(&test_sem); |
| } |
| |
| void |
| sock_udp_mcast_v4(void) |
| { |
| int loop_if_idx; |
| struct mn_socket *rx_sock; |
| struct mn_socket *tx_sock; |
| struct mn_sockaddr_in msin; |
| union mn_socket_cb sock_cbs = { |
| .socket.readable = sum4_readable |
| }; |
| struct os_mbuf *m; |
| char data[] = "1234567890"; |
| int rc; |
| struct mn_mreq mreq; |
| loop_if_idx = sock_find_multicast_if(); |
| TEST_ASSERT(loop_if_idx > 0); |
| |
| msin.msin_family = MN_AF_INET; |
| msin.msin_len = sizeof(msin); |
| msin.msin_port = htons(44344); |
| memset(&msin.msin_addr, 0, sizeof(msin.msin_addr)); |
| |
| rc = mn_socket(&rx_sock, MN_PF_INET, MN_SOCK_DGRAM, 0); |
| TEST_ASSERT(rc == 0); |
| mn_socket_set_cbs(rx_sock, NULL, &sock_cbs); |
| |
| rc = mn_bind(rx_sock, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_socket(&tx_sock, MN_PF_INET, MN_SOCK_DGRAM, 0); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_setsockopt(tx_sock, MN_SO_LEVEL, MN_MCAST_IF, &loop_if_idx); |
| TEST_ASSERT(rc == 0); |
| |
| m = os_msys_get(sizeof(data), 0); |
| rc = os_mbuf_copyinto(m, 0, data, sizeof(data)); |
| TEST_ASSERT(rc == 0); |
| |
| /* |
| * multicast tgt |
| */ |
| mn_inet_pton(MN_PF_INET, "224.0.2.241", &msin.msin_addr); |
| |
| rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| /* |
| * RX socket has not joined group yet. |
| */ |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC / 2); |
| TEST_ASSERT(rc == OS_TIMEOUT); |
| |
| mreq.mm_idx = loop_if_idx; |
| mreq.mm_family = MN_AF_INET; |
| mreq.mm_addr.v4.s_addr = msin.msin_addr.s_addr; |
| |
| /* |
| * Now join it. |
| */ |
| rc = mn_setsockopt(rx_sock, MN_SO_LEVEL, MN_MCAST_JOIN_GROUP, &mreq); |
| TEST_ASSERT(rc == 0); |
| |
| m = os_msys_get(sizeof(data), 0); |
| rc = os_mbuf_copyinto(m, 0, data, sizeof(data)); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_recvfrom(rx_sock, &m, NULL); |
| TEST_ASSERT(rc == 0); |
| TEST_ASSERT(m != NULL); |
| TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data))); |
| os_mbuf_free_chain(m); |
| |
| /* |
| * Then leave |
| */ |
| rc = mn_setsockopt(rx_sock, MN_SO_LEVEL, MN_MCAST_LEAVE_GROUP, &mreq); |
| TEST_ASSERT(rc == 0); |
| |
| m = os_msys_get(sizeof(data), 0); |
| TEST_ASSERT(m); |
| rc = os_mbuf_copyinto(m, 0, data, sizeof(data)); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin); |
| TEST_ASSERT(rc == 0); |
| |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == OS_TIMEOUT); |
| |
| mn_close(rx_sock); |
| mn_close(tx_sock); |
| } |
| |
| void |
| sock_udp_mcast_v6(void) |
| { |
| int loop_if_idx; |
| struct mn_socket *rx_sock; |
| struct mn_socket *tx_sock; |
| struct mn_sockaddr_in6 msin6; |
| union mn_socket_cb sock_cbs = { |
| .socket.readable = sum4_readable |
| }; |
| struct os_mbuf *m; |
| char data[] = "1234567890"; |
| int rc; |
| struct mn_mreq mreq; |
| uint8_t mcast_addr[16] = { |
| 0xff, 2, 0, 0, |
| 0, 0, 0, 0, |
| 0, 0, 0, 0, |
| 0, 0, 0, 2 |
| }; |
| |
| loop_if_idx = sock_find_multicast_if(); |
| TEST_ASSERT(loop_if_idx > 0); |
| |
| msin6.msin6_family = MN_AF_INET6; |
| msin6.msin6_len = sizeof(msin6); |
| msin6.msin6_port = htons(44344); |
| msin6.msin6_scope_id = 0; |
| memset(&msin6.msin6_addr, 0, sizeof(msin6.msin6_addr)); |
| |
| rc = mn_socket(&rx_sock, MN_PF_INET6, MN_SOCK_DGRAM, 0); |
| TEST_ASSERT(rc == 0); |
| mn_socket_set_cbs(rx_sock, NULL, &sock_cbs); |
| |
| rc = mn_bind(rx_sock, (struct mn_sockaddr *)&msin6); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_socket(&tx_sock, MN_PF_INET6, MN_SOCK_DGRAM, 0); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_setsockopt(tx_sock, MN_SO_LEVEL, MN_MCAST_IF, &loop_if_idx); |
| TEST_ASSERT(rc == 0); |
| |
| m = os_msys_get(sizeof(data), 0); |
| rc = os_mbuf_copyinto(m, 0, data, sizeof(data)); |
| TEST_ASSERT(rc == 0); |
| |
| /* |
| * multicast tgt |
| */ |
| memcpy(&msin6.msin6_addr, mcast_addr, sizeof(mcast_addr)); |
| |
| rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin6); |
| TEST_ASSERT(rc == 0); |
| |
| /* |
| * RX socket has not joined group yet. |
| */ |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC / 2); |
| TEST_ASSERT(rc == OS_TIMEOUT); |
| |
| mreq.mm_idx = loop_if_idx; |
| mreq.mm_family = MN_AF_INET6; |
| memcpy(&mreq.mm_addr.v6.s_addr, msin6.msin6_addr.s_addr, |
| sizeof(msin6.msin6_addr.s_addr)); |
| |
| /* |
| * Now join it. |
| */ |
| rc = mn_setsockopt(rx_sock, MN_SO_LEVEL, MN_MCAST_JOIN_GROUP, &mreq); |
| TEST_ASSERT(rc == 0); |
| |
| m = os_msys_get(sizeof(data), 0); |
| rc = os_mbuf_copyinto(m, 0, data, sizeof(data)); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin6); |
| TEST_ASSERT(rc == 0); |
| |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_recvfrom(rx_sock, &m, NULL); |
| TEST_ASSERT(rc == 0); |
| TEST_ASSERT(m != NULL); |
| TEST_ASSERT(!memcmp(m->om_data, data, sizeof(data))); |
| os_mbuf_free_chain(m); |
| |
| /* |
| * Then leave |
| */ |
| rc = mn_setsockopt(rx_sock, MN_SO_LEVEL, MN_MCAST_LEAVE_GROUP, &mreq); |
| TEST_ASSERT(rc == 0); |
| |
| m = os_msys_get(sizeof(data), 0); |
| TEST_ASSERT(m); |
| rc = os_mbuf_copyinto(m, 0, data, sizeof(data)); |
| TEST_ASSERT(rc == 0); |
| |
| rc = mn_sendto(tx_sock, (struct os_mbuf *)m, (struct mn_sockaddr *)&msin6); |
| TEST_ASSERT(rc == 0); |
| |
| rc = os_sem_pend(&test_sem, OS_TICKS_PER_SEC); |
| TEST_ASSERT(rc == OS_TIMEOUT); |
| |
| mn_close(rx_sock); |
| mn_close(tx_sock); |
| } |
| |
| void |
| mn_socket_test_handler(void *arg) |
| { |
| sock_open_close(); |
| sock_listen(); |
| sock_tcp_connect(); |
| sock_udp_data(); |
| sock_tcp_data(); |
| sock_itf_list(); |
| sock_udp_ll(); |
| sock_udp_mcast_v4(); |
| sock_udp_mcast_v6(); |
| tu_restart(); |
| } |