diff options
Diffstat (limited to '3rdparty/openpgm-svn-r1085/pgm/recv_unittest.c')
-rw-r--r-- | 3rdparty/openpgm-svn-r1085/pgm/recv_unittest.c | 1600 |
1 files changed, 1600 insertions, 0 deletions
diff --git a/3rdparty/openpgm-svn-r1085/pgm/recv_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/recv_unittest.c new file mode 100644 index 0000000..2719897 --- /dev/null +++ b/3rdparty/openpgm-svn-r1085/pgm/recv_unittest.c @@ -0,0 +1,1600 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for transport recv api + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _GNU_SOURCE +#include <signal.h> +#include <stdbool.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <netinet/in.h> /* _GNU_SOURCE for in6_pktinfo */ +#include <arpa/inet.h> +#include <glib.h> +#include <check.h> + + +/* mock state */ + +#define TEST_NETWORK "" +#define TEST_DPORT 7500 +#define TEST_SPORT 1000 +#define TEST_SRC_ADDR "127.0.0.1" +#define TEST_END_ADDR "127.0.0.2" +#define TEST_GROUP_ADDR "239.192.0.1" +#define TEST_PEER_ADDR "127.0.0.6" +#define TEST_DLR_ADDR "127.0.0.9" +#define TEST_MAX_TPDU 1500 +#define TEST_TXW_SQNS 32 +#define TEST_RXW_SQNS 32 +#define TEST_HOPS 16 +#define TEST_SPM_AMBIENT ( pgm_secs(30) ) +#define TEST_SPM_HEARTBEAT_INIT { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) } +#define TEST_PEER_EXPIRY ( pgm_secs(300) ) +#define TEST_SPMR_EXPIRY ( pgm_msecs(250) ) +#define TEST_NAK_BO_IVL ( pgm_msecs(50) ) +#define TEST_NAK_RPT_IVL ( pgm_secs(2) ) +#define TEST_NAK_RDATA_IVL ( pgm_secs(2) ) +#define TEST_NAK_DATA_RETRIES 5 +#define TEST_NAK_NCF_RETRIES 2 + +struct mock_recvmsg_t { + struct msghdr* mr_msg; + ssize_t mr_retval; + int mr_errno; +}; + +struct pgm_peer_t; + +GList* mock_recvmsg_list = NULL; +static int mock_pgm_type = -1; +static gboolean mock_reset_on_spmr = FALSE; +static gboolean mock_data_on_spmr = FALSE; +static struct pgm_peer_t* mock_peer = NULL; +GList* mock_data_list = NULL; +unsigned mock_pgm_loss_rate = 0; + + +static ssize_t mock_recvmsg (int, struct msghdr*, int); + +#define pgm_parse_raw mock_pgm_parse_raw +#define pgm_parse_udp_encap mock_pgm_parse_udp_encap +#define pgm_verify_spm mock_pgm_verify_spm +#define pgm_verify_nak mock_pgm_verify_nak +#define pgm_verify_ncf mock_pgm_verify_ncf +#define pgm_poll_info mock_pgm_poll_info +#define pgm_set_reset_error mock_pgm_set_reset_error +#define pgm_flush_peers_pending mock_pgm_flush_peers_pending +#define pgm_peer_has_pending mock_pgm_peer_has_pending +#define pgm_peer_set_pending mock_pgm_peer_set_pending +#define pgm_txw_retransmit_is_empty mock_pgm_txw_retransmit_is_empty +#define pgm_rxw_create mock_pgm_rxw_create +#define pgm_rxw_readv mock_pgm_rxw_readv +#define pgm_new_peer mock_pgm_new_peer +#define pgm_on_data mock_pgm_on_data +#define pgm_on_spm mock_pgm_on_spm +#define pgm_on_ack mock_pgm_on_ack +#define pgm_on_nak mock_pgm_on_nak +#define pgm_on_deferred_nak mock_pgm_on_deferred_nak +#define pgm_on_peer_nak mock_pgm_on_peer_nak +#define pgm_on_nnak mock_pgm_on_nnak +#define pgm_on_ncf mock_pgm_on_ncf +#define pgm_on_spmr mock_pgm_on_spmr +#define pgm_sendto mock_pgm_sendto +#define pgm_timer_prepare mock_pgm_timer_prepare +#define pgm_timer_check mock_pgm_timer_check +#define pgm_timer_expiration mock_pgm_timer_expiration +#define pgm_timer_dispatch mock_pgm_timer_dispatch +#define pgm_time_now mock_pgm_time_now +#define pgm_time_update_now mock_pgm_time_update_now +#define recvmsg mock_recvmsg +#define pgm_loss_rate mock_pgm_loss_rate + +#define RECV_DEBUG +#include "recv.c" + + +pgm_rxw_t* mock_pgm_rxw_create (const pgm_tsi_t*, const uint16_t, const unsigned, const unsigned, const ssize_t, const uint32_t); +static pgm_time_t _mock_pgm_time_update_now (void); +pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; + + +static +void +mock_setup (void) +{ + if (!g_thread_supported ()) g_thread_init (NULL); +} + +static +struct pgm_sock_t* +generate_sock (void) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, g_htons(TEST_SPORT) }; + struct pgm_sock_t* sock = g_new0 (struct pgm_sock_t, 1); + sock->window = g_new0 (pgm_txw_t, 1); + memcpy (&sock->tsi, &tsi, sizeof(pgm_tsi_t)); + sock->is_bound = TRUE; + sock->rx_buffer = pgm_alloc_skb (TEST_MAX_TPDU); + sock->max_tpdu = TEST_MAX_TPDU; + sock->rxw_sqns = TEST_RXW_SQNS; + sock->dport = g_htons(TEST_DPORT); + sock->can_send_data = TRUE; + sock->can_send_nak = TRUE; + sock->can_recv_data = TRUE; + sock->peers_hashtable = pgm_hashtable_new (pgm_tsi_hash, pgm_tsi_equal); + pgm_rand_create (&sock->rand_); + sock->nak_bo_ivl = 100*1000; + pgm_notify_init (&sock->pending_notify); + pgm_notify_init (&sock->rdata_notify); + return sock; +} + +static +struct pgm_sk_buff_t* +generate_packet (void) +{ + struct pgm_sk_buff_t* skb; + + skb = pgm_alloc_skb (TEST_MAX_TPDU); + skb->data = skb->head; + skb->len = sizeof(struct pgm_ip) + sizeof(struct pgm_header); + skb->tail = (guint8*)skb->data + skb->len; + +/* add IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_hl = sizeof(struct pgm_ip) / 4; + iphdr->ip_v = 4; + iphdr->ip_tos = 0; + iphdr->ip_id = 0; + iphdr->ip_off = 0; + iphdr->ip_ttl = 16; + iphdr->ip_p = IPPROTO_PGM; + iphdr->ip_sum = 0; + iphdr->ip_src.s_addr = inet_addr (TEST_SRC_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_GROUP_ADDR); + +/* add PGM header */ + struct pgm_header* pgmhdr = (gpointer)(iphdr + 1); + pgmhdr->pgm_sport = g_htons ((guint16)TEST_SPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_options = 0; + pgmhdr->pgm_gsi[0] = 1; + pgmhdr->pgm_gsi[1] = 2; + pgmhdr->pgm_gsi[2] = 3; + pgmhdr->pgm_gsi[3] = 4; + pgmhdr->pgm_gsi[4] = 5; + pgmhdr->pgm_gsi[5] = 6; + pgmhdr->pgm_tsdu_length = 0; + pgmhdr->pgm_checksum = 0; + + skb->pgm_header = pgmhdr; + return skb; +} + +static +void +generate_odata ( + const char* source, + const guint source_len, + const guint32 data_sqn, + const guint32 data_trail, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_data) + source_len); + +/* add ODATA header */ + struct pgm_data* datahdr = (gpointer)(skb->pgm_header + 1); + datahdr->data_sqn = g_htonl (data_sqn); + datahdr->data_trail = g_htonl (data_trail); + +/* add payload */ + gpointer data = (gpointer)(datahdr + 1); + memcpy (data, source, source_len); + +/* finalize PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_type = PGM_ODATA; + pgmhdr->pgm_tsdu_length = g_htons (source_len); + +/* finalize IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_spm ( + const guint32 spm_sqn, + const guint32 spm_trail, + const guint32 spm_lead, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_spm)); + +/* add SPM header */ + struct pgm_spm* spm = (gpointer)(skb->pgm_header + 1); + spm->spm_sqn = g_htonl (spm_sqn); + spm->spm_trail = g_htonl (spm_trail); + spm->spm_lead = g_htonl (spm_lead); + +/* finalize PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_type = PGM_SPM; + +/* finalize IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_nak ( + const guint32 nak_sqn, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_spm)); + +/* update IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_src.s_addr = inet_addr (TEST_END_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_SRC_ADDR); + +/* update PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); + +/* add NAK header */ + struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); + nak->nak_sqn = g_htonl (nak_sqn); + +/* finalize PGM header */ + pgmhdr->pgm_type = PGM_NAK; + +/* finalize IP header */ + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_peer_nak ( + const guint32 nak_sqn, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_spm)); + +/* update IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_src.s_addr = inet_addr (TEST_PEER_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_GROUP_ADDR); + +/* update PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); + +/* add NAK header */ + struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); + nak->nak_sqn = g_htonl (nak_sqn); + +/* finalize PGM header */ + pgmhdr->pgm_type = PGM_NAK; + +/* finalize IP header */ + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_nnak ( + const guint32 nak_sqn, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_nak)); + +/* update IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_src.s_addr = inet_addr (TEST_DLR_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_SRC_ADDR); + +/* update PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); + +/* add NNAK header */ + struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); + nak->nak_sqn = g_htonl (nak_sqn); + +/* finalize PGM header */ + pgmhdr->pgm_type = PGM_NNAK; + +/* finalize IP header */ + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_ncf ( + const guint32 nak_sqn, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_nak)); + +/* add NAK header */ + struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); + nak->nak_sqn = g_htonl (nak_sqn); + +/* finalize PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_type = PGM_NCF; + +/* finalize IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_spmr ( + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + +/* update IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_src.s_addr = inet_addr (TEST_END_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_SRC_ADDR); + +/* update PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); + +/* finalize PGM header */ + pgmhdr->pgm_type = PGM_SPMR; + +/* finalize IP header */ + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_peer_spmr ( + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + +/* update IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_src.s_addr = inet_addr (TEST_PEER_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_GROUP_ADDR); + +/* update PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); + +/* finalize PGM header */ + pgmhdr->pgm_type = PGM_SPMR; + +/* finalize IP header */ + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_msghdr ( + const gpointer packet, + const gsize packet_len + ) +{ + struct pgm_ip* iphdr = packet; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = iphdr->ip_src.s_addr + }; + struct iovec iov = { + .iov_base = packet, + .iov_len = packet_len + }; + struct cmsghdr* packet_cmsg = g_malloc0 (sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)); + packet_cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo); + packet_cmsg->cmsg_level = IPPROTO_IP; + packet_cmsg->cmsg_type = IP_PKTINFO; + struct in_pktinfo packet_info = { + .ipi_ifindex = 2, + .ipi_spec_dst = iphdr->ip_src.s_addr, /* local address */ + .ipi_addr = iphdr->ip_dst.s_addr /* destination address */ + }; + memcpy ((char*)(packet_cmsg + 1), &packet_info, sizeof(struct in_pktinfo)); + struct msghdr packet_msg = { + .msg_name = g_memdup (&addr, sizeof(addr)), /* source address */ + .msg_namelen = sizeof(addr), + .msg_iov = g_memdup (&iov, sizeof(iov)), + .msg_iovlen = 1, + .msg_control = &packet_cmsg, + .msg_controllen = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), + .msg_flags = 0 + }; + + struct mock_recvmsg_t* mr = g_malloc (sizeof(struct mock_recvmsg_t)); + mr->mr_msg = g_memdup (&packet_msg, sizeof(packet_msg)); + mr->mr_errno = 0; + mr->mr_retval = packet_len; + mock_recvmsg_list = g_list_append (mock_recvmsg_list, mr); +} + +static +void +push_block_event (void) +{ +/* block */ + struct mock_recvmsg_t* mr = g_malloc (sizeof(struct mock_recvmsg_t)); + mr->mr_msg = NULL; + mr->mr_errno = EAGAIN; + mr->mr_retval = -1; + mock_recvmsg_list = g_list_append (mock_recvmsg_list, mr); +} + +/** packet module */ +bool +mock_pgm_parse_raw ( + struct pgm_sk_buff_t* const skb, + struct sockaddr* const dst, + pgm_error_t** error + ) +{ + const struct pgm_ip* ip = (struct pgm_ip*)skb->data; + struct sockaddr_in* sin = (struct sockaddr_in*)dst; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = ip->ip_dst.s_addr; + const gsize ip_header_length = ip->ip_hl * 4; + skb->pgm_header = (gpointer)( (guint8*)skb->data + ip_header_length ); + skb->data = skb->pgm_header; + skb->len -= ip_header_length; + memcpy (&skb->tsi.gsi, skb->pgm_header->pgm_gsi, sizeof(pgm_gsi_t)); + skb->tsi.sport = skb->pgm_header->pgm_sport; + return TRUE; +} + +bool +mock_pgm_parse_udp_encap ( + struct pgm_sk_buff_t* const skb, + pgm_error_t** error + ) +{ + skb->pgm_header = skb->data; + memcpy (&skb->tsi.gsi, skb->pgm_header->pgm_gsi, sizeof(pgm_gsi_t)); + skb->tsi.sport = skb->pgm_header->pgm_sport; + return TRUE; +} + +bool +mock_pgm_verify_spm ( + const struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +bool +mock_pgm_verify_nak ( + const struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +bool +mock_pgm_verify_ncf ( + const struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +/** socket module */ +int +mock_pgm_poll_info ( + pgm_sock_t* const sock, + struct pollfd* fds, + int* n_fds, + int events + ) +{ +} + +pgm_peer_t* +mock__pgm_peer_ref ( + pgm_peer_t* peer + ) +{ + pgm_atomic_inc32 (&peer->ref_count); + return peer; +} + +PGM_GNUC_INTERNAL +pgm_peer_t* +mock_pgm_new_peer ( + pgm_sock_t* const sock, + const pgm_tsi_t* const tsi, + const struct sockaddr* const src_addr, + const socklen_t src_addr_len, + const struct sockaddr* const dst_addr, + const socklen_t dst_addr_len, + const pgm_time_t now + ) +{ + pgm_peer_t* peer = g_malloc0 (sizeof(pgm_peer_t)); + peer->expiry = now + sock->peer_expiry; + peer->sock = sock; + memcpy (&peer->tsi, tsi, sizeof(pgm_tsi_t)); + memcpy (&peer->group_nla, dst_addr, dst_addr_len); + memcpy (&peer->local_nla, src_addr, src_addr_len); + ((struct sockaddr_in*)&peer->local_nla)->sin_port = g_htons (sock->udp_encap_ucast_port); + ((struct sockaddr_in*)&peer->nla)->sin_port = g_htons (sock->udp_encap_ucast_port); + peer->window = mock_pgm_rxw_create (&peer->tsi, + sock->max_tpdu, + sock->rxw_sqns, + sock->rxw_secs, + sock->rxw_max_rte, + sock->ack_c_p); + peer->spmr_expiry = now + sock->spmr_expiry; + gpointer entry = mock__pgm_peer_ref(peer); + pgm_hashtable_insert (sock->peers_hashtable, &peer->tsi, entry); + peer->peers_link.next = sock->peers_list; + peer->peers_link.data = peer; + if (sock->peers_list) + sock->peers_list->prev = &peer->peers_link; + sock->peers_list = &peer->peers_link; + return peer; +} + +PGM_GNUC_INTERNAL +void +mock_pgm_set_reset_error ( + pgm_sock_t* const sock, + pgm_peer_t* const source, + struct pgm_msgv_t* const msgv + ) +{ +} + +PGM_GNUC_INTERNAL +int +mock_pgm_flush_peers_pending ( + pgm_sock_t* const sock, + struct pgm_msgv_t** pmsg, + const struct pgm_msgv_t* const msg_end, + size_t* const bytes_read, + unsigned* const data_read + ) +{ + if (mock_data_list) { + size_t len = 0; + unsigned count = 0; + while (mock_data_list && *pmsg <= msg_end) { + struct pgm_msgv_t* mock_msgv = mock_data_list->data; + (*pmsg)->msgv_len = mock_msgv->msgv_len; + for (unsigned i = 0; i < mock_msgv->msgv_len; i++) { + (*pmsg)->msgv_skb[i] = mock_msgv->msgv_skb[i]; + len += mock_msgv->msgv_skb[i]->len; + } + count++; + (*pmsg)++; + mock_data_list = g_list_delete_link (mock_data_list, mock_data_list); + } + *bytes_read = len; + *data_read = count; + if (*pmsg > msg_end) + return -ENOBUFS; + } + return 0; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_peer_has_pending ( + pgm_peer_t* const peer + ) +{ + return FALSE; +} + +PGM_GNUC_INTERNAL +void +mock_pgm_peer_set_pending ( + pgm_sock_t* const sock, + pgm_peer_t* const peer + ) +{ + g_assert (NULL != sock); + g_assert (NULL != peer); + if (peer->pending_link.data) return; + peer->pending_link.data = peer; + peer->pending_link.next = sock->peers_pending; + sock->peers_pending = &peer->pending_link; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_data ( + pgm_sock_t* const sock, + pgm_peer_t* const sender, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_data (sock:%p sender:%p skb:%p)", + (gpointer)sock, (gpointer)sender, (gpointer)skb); + mock_pgm_type = PGM_ODATA; + ((pgm_rxw_t*)sender->window)->has_event = 1; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_ack ( + pgm_sock_t* const sock, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_ack (sock:%p skb:%p)", + (gpointer)sock, (gpointer)skb); + mock_pgm_type = PGM_ACK; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_deferred_nak ( + pgm_sock_t* const sock + ) +{ + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_nak ( + pgm_sock_t* const sock, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_nak (sock:%p skb:%p)", + (gpointer)sock, (gpointer)skb); + mock_pgm_type = PGM_NAK; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_peer_nak ( + pgm_sock_t* const sock, + pgm_peer_t* const sender, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_peer_nak (sock:%p sender:%p skb:%p)", + (gpointer)sock, (gpointer)sender, (gpointer)skb); + mock_pgm_type = PGM_NAK; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_ncf ( + pgm_sock_t* const sock, + pgm_peer_t* const sender, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_ncf (sock:%p sender:%p skb:%p)", + (gpointer)sock, (gpointer)sender, (gpointer)skb); + mock_pgm_type = PGM_NCF; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_nnak ( + pgm_sock_t* const sock, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_nnak (sock:%p skb:%p)", + (gpointer)sock, (gpointer)skb); + mock_pgm_type = PGM_NNAK; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_spm ( + pgm_sock_t* const sock, + pgm_peer_t* const sender, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_spm (sock:%p sender:%p skb:%p)", + (gpointer)sock, (gpointer)sender, (gpointer)skb); + mock_pgm_type = PGM_SPM; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_spmr ( + pgm_sock_t* const sock, + pgm_peer_t* const peer, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_spmr (sock:%p peer:%p skb:%p)", + (gpointer)sock, (gpointer)peer, (gpointer)skb); + mock_pgm_type = PGM_SPMR; + if (mock_reset_on_spmr) { + sock->is_reset = TRUE; + mock_pgm_peer_set_pending (sock, mock_peer); + } + if (mock_data_on_spmr) { + mock_pgm_peer_set_pending (sock, mock_peer); + } + return TRUE; +} + +/** transmit window */ +PGM_GNUC_INTERNAL +bool +mock_pgm_txw_retransmit_is_empty ( + const pgm_txw_t*const window + ) +{ + return TRUE; +} + +/** receive window */ +pgm_rxw_t* +mock_pgm_rxw_create ( + const pgm_tsi_t* tsi, + const uint16_t tpdu_size, + const unsigned sqns, + const unsigned secs, + const ssize_t max_rte, + const uint32_t ack_c_p + ) +{ + return g_new0 (pgm_rxw_t, 1); +} + +ssize_t +mock_pgm_rxw_readv ( + pgm_rxw_t* const window, + struct pgm_msgv_t** pmsg, + const unsigned pmsglen + ) +{ + return -1; +} + +/** net module */ +PGM_GNUC_INTERNAL +ssize_t +mock_pgm_sendto ( + pgm_sock_t* sock, + bool use_rate_limit, + bool use_router_alert, + const void* buf, + size_t len, + const struct sockaddr* to, + socklen_t tolen + ) +{ + return len; +} + +/** timer module */ +PGM_GNUC_INTERNAL +bool +mock_pgm_timer_prepare ( + pgm_sock_t* const sock + ) +{ + return FALSE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_timer_check ( + pgm_sock_t* const sock + ) +{ + return FALSE; +} + +PGM_GNUC_INTERNAL +pgm_time_t +mock_pgm_timer_expiration ( + pgm_sock_t* const sock + ) +{ + return 100L; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_timer_dispatch ( + pgm_sock_t* const sock + ) +{ + return TRUE; +} + +/** time module */ +static pgm_time_t mock_pgm_time_now = 0x1; + +static +pgm_time_t +_mock_pgm_time_update_now (void) +{ + return mock_pgm_time_now; +} + +/** libc */ +static +ssize_t +mock_recvmsg ( + int s, + struct msghdr* msg, + int flags + ) +{ + g_assert (NULL != msg); + g_assert (NULL != mock_recvmsg_list); + + g_debug ("mock_recvmsg (s:%d msg:%p flags:%d)", + s, (gpointer)msg, flags); + + struct mock_recvmsg_t* mr = mock_recvmsg_list->data; + struct msghdr* mock_msg = mr->mr_msg; + ssize_t mock_retval = mr->mr_retval; + int mock_errno = mr->mr_errno; + mock_recvmsg_list = g_list_delete_link (mock_recvmsg_list, mock_recvmsg_list); + if (mock_msg) { + g_assert_cmpuint (mock_msg->msg_namelen, <=, msg->msg_namelen); + g_assert_cmpuint (mock_msg->msg_iovlen, <=, msg->msg_iovlen); + g_assert_cmpuint (mock_msg->msg_controllen, <=, msg->msg_controllen); + if (mock_msg->msg_namelen) + memcpy (msg->msg_name, mock_msg->msg_name, mock_msg->msg_namelen); + if (mock_msg->msg_iovlen) { + for (unsigned i = 0; i < mock_msg->msg_iovlen; i++) { + g_assert (mock_msg->msg_iov[i].iov_len <= msg->msg_iov[i].iov_len); + memcpy (msg->msg_iov[i].iov_base, mock_msg->msg_iov[i].iov_base, mock_msg->msg_iov[i].iov_len); + } + } + if (mock_msg->msg_controllen) + memcpy (msg->msg_control, mock_msg->msg_control, mock_msg->msg_controllen); + msg->msg_flags = mock_msg->msg_flags; + } + errno = mock_errno; + return mock_retval; +} + + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + + +/* target: + * int + * pgm_recv ( + * pgm_sock_t* sock, + * void* data, + * size_t len, + * int flags, + * size_t* bytes_read, + * pgm_error_t** error + * ) + * + * Most tests default to PGM_IO_STATUS_TIMER_PENDING, PGM_IO_STATUS_WOULD_BLOCK is not expected due + * to peer state engine and SPM broadcasts. + */ + +START_TEST (test_block_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* recv -> on_data */ +START_TEST (test_data_pass_001) +{ + const char source[] = "i am not a string"; + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_odata (source, sizeof(source), 0 /* sqn */, -1 /* trail */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_ODATA == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_spm */ +START_TEST (test_spm_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_spm (200 /* spm-sqn */, -1 /* trail */, 0 /* lead */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_SPM == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_nak */ +START_TEST (test_nak_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_nak (0 /* sqn */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_NAK == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_peer_nak */ +START_TEST (test_peer_nak_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_peer_nak (0 /* sqn */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_NAK == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_nnak */ +START_TEST (test_nnak_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_nnak (0 /* sqn */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_NNAK == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_ncf */ +START_TEST (test_ncf_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_ncf (0 /* sqn */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_NCF == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_spmr */ +START_TEST (test_spmr_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_SPMR == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on (peer) spmr */ +START_TEST (test_peer_spmr_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_peer_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_SPMR == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> lost data */ +START_TEST (test_lost_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_reset = TRUE; + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + pgm_peer_t* peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == peer, "new_peer failed"); + mock_pgm_peer_set_pending (sock, peer); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + if (err) { + g_message ("%s", err->message); + pgm_error_free (err); + err = NULL; + } + push_block_event (); + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* recv -> lost data and abort transport */ +START_TEST (test_abort_on_lost_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_reset = TRUE; + sock->is_abort_on_reset = TRUE; + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + pgm_peer_t* peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == peer, "new_peer failed"); + mock_pgm_peer_set_pending (sock, peer); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + if (err) { + g_message ("%s", err->message); + pgm_error_free (err); + err = NULL; + } + push_block_event (); + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* recv -> (spmr) & loss */ +START_TEST (test_then_lost_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + mock_reset_on_spmr = TRUE; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == mock_peer, "new_peer failed"); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + if (err) { + g_message ("%s", err->message); + pgm_error_free (err); + err = NULL; + } + push_block_event (); + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* recv -> data & loss & abort transport */ +START_TEST (test_then_abort_on_lost_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + mock_reset_on_spmr = TRUE; + sock->is_abort_on_reset = TRUE; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == mock_peer, "new_peer failed"); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + if (err) { + g_message ("%s", err->message); + pgm_error_free (err); + err = NULL; + } + push_block_event (); + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* new waiting peer -> return data */ +START_TEST (test_on_data_pass_001) +{ + const char source[] = "i am not a string"; + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + mock_data_on_spmr = TRUE; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == mock_peer, "new_peer failed"); + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_put (skb, sizeof(source)); + memcpy (skb->data, source, sizeof(source)); + struct pgm_msgv_t* msgv = g_new0 (struct pgm_msgv_t, 1); + msgv->msgv_len = 1; + msgv->msgv_skb[0] = skb; + mock_data_list = g_list_append (mock_data_list, msgv); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (NULL == err, "error raised"); + fail_unless ((gsize)sizeof(source) == bytes_read, "unexpected data length"); + push_block_event (); + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* zero length data waiting */ +START_TEST (test_on_zero_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + mock_data_on_spmr = TRUE; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == mock_peer, "new_peer failed"); + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); + struct pgm_msgv_t* msgv = g_new0 (struct pgm_msgv_t, 1); + msgv->msgv_len = 1; + msgv->msgv_skb[0] = skb; + mock_data_list = g_list_append (mock_data_list, msgv); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (NULL == err, "error raised"); + fail_unless ((gsize)0 == bytes_read, "unexpected data length"); + push_block_event (); + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* more than vector length data waiting */ +START_TEST (test_on_many_data_pass_001) +{ + const char* source[] = { + "i am not a string", + "i am not an iguana", + "i am not a peach" + }; + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + mock_data_on_spmr = TRUE; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == mock_peer, "new_peer failed"); + struct pgm_sk_buff_t* skb; + struct pgm_msgv_t* msgv; +/* #1 */ + msgv = g_new0 (struct pgm_msgv_t, 1); + skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_put (skb, strlen(source[0]) + 1); + memcpy (skb->data, source[0], strlen(source[0])); + msgv->msgv_len = 1; + msgv->msgv_skb[0] = skb; + mock_data_list = g_list_append (mock_data_list, msgv); +/* #2 */ + msgv = g_new0 (struct pgm_msgv_t, 1); + skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_put (skb, strlen(source[1]) + 1); + memcpy (skb->data, source[1], strlen(source[1])); + msgv->msgv_len = 1; + msgv->msgv_skb[0] = skb; + mock_data_list = g_list_append (mock_data_list, msgv); +/* #3 */ + msgv = g_new0 (struct pgm_msgv_t, 1); + skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_put (skb, strlen(source[2]) + 1); + memcpy (skb->data, source[2], strlen(source[2])); + msgv->msgv_len = 1; + msgv->msgv_skb[0] = skb; + mock_data_list = g_list_append (mock_data_list, msgv); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (NULL == err, "error raised"); + fail_unless ((gsize)(strlen(source[0]) + 1) == bytes_read, "unexpected data length"); + g_message ("#1 = \"%s\"", buffer); + fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (NULL == err, "error raised"); + fail_unless ((gsize)(strlen(source[1]) + 1) == bytes_read, "unexpected data length"); + g_message ("#2 = \"%s\"", buffer); + fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (NULL == err, "error raised"); + fail_unless ((gsize)(strlen(source[2]) + 1) == bytes_read, "unexpected data length"); + g_message ("#3 = \"%s\"", buffer); + push_block_event (); + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +START_TEST (test_recv_fail_001) +{ + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + fail_unless (PGM_IO_STATUS_ERROR == pgm_recv (NULL, buffer, sizeof(buffer), 0, NULL, NULL), "recv faied"); +} +END_TEST + +/* target: + * int + * pgm_recvfrom ( + * pgm_sock_t* sock, + * void* data, + * size_t len, + * int flags, + * size_t* bytes_read, + * struct pgm_sockaddr_t* from, + * socklen_t* fromlen, + * pgm_error_t** error + * ) + */ + +START_TEST (test_recvfrom_fail_001) +{ + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + struct pgm_sockaddr_t from; + socklen_t fromlen = sizeof(from); + fail_unless (PGM_IO_STATUS_ERROR == pgm_recvfrom (NULL, buffer, sizeof(buffer), 0, NULL, &from, &fromlen, NULL), "recvfrom failed"); +} +END_TEST + +/* target: + * int + * pgm_recvmsg ( + * pgm_sock_t* sock, + * pgm_msgv_t* msgv, + * int flags, + * size_t* bytes_read, + * pgm_error_t** error + * ) + */ + +START_TEST (test_recvmsg_fail_001) +{ + struct pgm_msgv_t msgv; + fail_unless (PGM_IO_STATUS_ERROR == pgm_recvmsg (NULL, &msgv, 0, NULL, NULL), "recvmsg failed"); +} +END_TEST + +/* target: + * int + * pgm_recvmsgv ( + * pgm_sock_t* sock, + * pgm_msgv_t* msgv, + * unsigned msgv_length, + * int flags, + * size_t* bytes_read, + * pgm_error_t** error + * ) + */ + +START_TEST (test_recvmsgv_fail_001) +{ + struct pgm_msgv_t msgv[1]; + fail_unless (PGM_IO_STATUS_ERROR == pgm_recvmsgv (NULL, msgv, G_N_ELEMENTS(msgv), 0, NULL, NULL), "recvmsgv failed"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_block = tcase_create ("block"); + suite_add_tcase (s, tc_block); + tcase_add_checked_fixture (tc_block, mock_setup, NULL); + tcase_add_test (tc_block, test_block_pass_001); + + TCase* tc_data = tcase_create ("data"); + suite_add_tcase (s, tc_data); + tcase_add_checked_fixture (tc_data, mock_setup, NULL); + tcase_add_test (tc_data, test_data_pass_001); + + TCase* tc_spm = tcase_create ("spm"); + suite_add_tcase (s, tc_spm); + tcase_add_checked_fixture (tc_spm, mock_setup, NULL); + tcase_add_test (tc_spm, test_spm_pass_001); + + TCase* tc_nak = tcase_create ("nak"); + suite_add_tcase (s, tc_nak); + tcase_add_checked_fixture (tc_nak, mock_setup, NULL); + tcase_add_test (tc_nak, test_nak_pass_001); + + TCase* tc_peer_nak = tcase_create ("peer-nak"); + suite_add_tcase (s, tc_peer_nak); + tcase_add_checked_fixture (tc_peer_nak, mock_setup, NULL); + tcase_add_test (tc_peer_nak, test_peer_nak_pass_001); + + TCase* tc_nnak = tcase_create ("nnak"); + suite_add_tcase (s, tc_nnak); + tcase_add_checked_fixture (tc_nnak, mock_setup, NULL); + tcase_add_test (tc_nnak, test_nnak_pass_001); + + TCase* tc_ncf = tcase_create ("ncf"); + suite_add_tcase (s, tc_ncf); + tcase_add_checked_fixture (tc_ncf, mock_setup, NULL); + tcase_add_test (tc_ncf, test_ncf_pass_001); + + TCase* tc_spmr = tcase_create ("spmr"); + suite_add_tcase (s, tc_spmr); + tcase_add_checked_fixture (tc_spmr, mock_setup, NULL); + tcase_add_test (tc_spmr, test_spmr_pass_001); + + TCase* tc_peer_spmr = tcase_create ("peer-spmr"); + suite_add_tcase (s, tc_peer_spmr); + tcase_add_checked_fixture (tc_peer_spmr, mock_setup, NULL); + tcase_add_test (tc_peer_spmr, test_peer_spmr_pass_001); + + TCase* tc_lost = tcase_create ("lost"); + suite_add_tcase (s, tc_lost); + tcase_add_checked_fixture (tc_lost, mock_setup, NULL); + tcase_add_test (tc_lost, test_lost_pass_001); + + TCase* tc_abort_on_lost = tcase_create ("abort-on-lost"); + suite_add_tcase (s, tc_abort_on_lost); + tcase_add_checked_fixture (tc_abort_on_lost, mock_setup, NULL); + tcase_add_test (tc_abort_on_lost, test_abort_on_lost_pass_001); + + TCase* tc_then_lost = tcase_create ("then-lost"); + suite_add_tcase (s, tc_then_lost); + tcase_add_checked_fixture (tc_then_lost, mock_setup, NULL); + tcase_add_test (tc_then_lost, test_then_lost_pass_001); + + TCase* tc_then_abort_on_lost = tcase_create ("then-abort-on-lost"); + suite_add_tcase (s, tc_then_abort_on_lost); + tcase_add_checked_fixture (tc_then_abort_on_lost, mock_setup, NULL); + tcase_add_test (tc_then_abort_on_lost, test_then_abort_on_lost_pass_001); + + TCase* tc_on_data = tcase_create ("on-data"); + suite_add_tcase (s, tc_on_data); + tcase_add_checked_fixture (tc_on_data, mock_setup, NULL); + tcase_add_test (tc_on_data, test_on_data_pass_001); + + TCase* tc_on_zero = tcase_create ("on-zero"); + suite_add_tcase (s, tc_on_zero); + tcase_add_checked_fixture (tc_on_zero, mock_setup, NULL); + tcase_add_test (tc_on_zero, test_on_zero_pass_001); + + TCase* tc_on_many_data = tcase_create ("on-many-data"); + suite_add_tcase (s, tc_on_many_data); + tcase_add_checked_fixture (tc_on_many_data, mock_setup, NULL); + tcase_add_test (tc_on_many_data, test_on_many_data_pass_001); + + TCase* tc_recv = tcase_create ("recv"); + suite_add_tcase (s, tc_recv); + tcase_add_checked_fixture (tc_recv, mock_setup, NULL); + tcase_add_test (tc_recv, test_recv_fail_001); + + TCase* tc_recvfrom = tcase_create ("recvfrom"); + suite_add_tcase (s, tc_recvfrom); + tcase_add_checked_fixture (tc_recvfrom, mock_setup, NULL); + tcase_add_test (tc_recvfrom, test_recvfrom_fail_001); + + TCase* tc_recvmsg = tcase_create ("recvmsg"); + suite_add_tcase (s, tc_recvmsg); + tcase_add_checked_fixture (tc_recvmsg, mock_setup, NULL); + tcase_add_test (tc_recvmsg, test_recvmsg_fail_001); + + TCase* tc_recvmsgv = tcase_create ("recvmsgv"); + suite_add_tcase (s, tc_recvmsgv); + tcase_add_checked_fixture (tc_recvmsgv, mock_setup, NULL); + tcase_add_test (tc_recvmsgv, test_recvmsgv_fail_001); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ |