summaryrefslogtreecommitdiff
path: root/cleopatre/devkit/tests/libmme
diff options
context:
space:
mode:
authorsave2009-08-17 09:07:32 +0000
committersave2009-08-17 09:07:32 +0000
commite4128345bbbda42b7c5d23cc5c68218750c44338 (patch)
tree8b4ad9f3d3410c133e39aae9dbdc9c0fab297447 /cleopatre/devkit/tests/libmme
parente7c2d314f3d5c03ae620ddf03758d517044778d2 (diff)
[CLEO][TESTS]Moved libmme and spidlib tests under devkit tests
git-svn-id: svn+ssh://pessac/svn/cesar/trunk@5245 017c9cb6-072f-447c-8318-d5b54f68fe89
Diffstat (limited to 'cleopatre/devkit/tests/libmme')
-rw-r--r--cleopatre/devkit/tests/libmme/utests/Makefile5
-rw-r--r--cleopatre/devkit/tests/libmme/utests/inc/mme_utests.h19
-rw-r--r--cleopatre/devkit/tests/libmme/utests/src/mme_utests.c1014
3 files changed, 1038 insertions, 0 deletions
diff --git a/cleopatre/devkit/tests/libmme/utests/Makefile b/cleopatre/devkit/tests/libmme/utests/Makefile
new file mode 100644
index 0000000000..4ee22c68d4
--- /dev/null
+++ b/cleopatre/devkit/tests/libmme/utests/Makefile
@@ -0,0 +1,5 @@
+PRJ_BASE = ../../../../application/libmme
+FILES = mme
+
+include ../../utests_makerules
+
diff --git a/cleopatre/devkit/tests/libmme/utests/inc/mme_utests.h b/cleopatre/devkit/tests/libmme/utests/inc/mme_utests.h
new file mode 100644
index 0000000000..d3bebac8eb
--- /dev/null
+++ b/cleopatre/devkit/tests/libmme/utests/inc/mme_utests.h
@@ -0,0 +1,19 @@
+#ifndef mme_utests_h
+#define mme_utests_h
+/* Cleopatre project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file mme_utests.h
+ * \brief interfaces for unitary tests of libMME
+ * \ingroup Cleopatre - LibMME
+ *
+ * this file content interfaces and exported macros, variables... For the
+ * unitary tests of libMME
+ */
+
+#endif /* mme_utests_h */
diff --git a/cleopatre/devkit/tests/libmme/utests/src/mme_utests.c b/cleopatre/devkit/tests/libmme/utests/src/mme_utests.c
new file mode 100644
index 0000000000..1865f9f5c9
--- /dev/null
+++ b/cleopatre/devkit/tests/libmme/utests/src/mme_utests.c
@@ -0,0 +1,1014 @@
+/* Cleopatre project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file mme_utests.c
+ * \brief Unitary tests for libMME
+ * \ingroup Cleopatre - LibMME
+ *
+ * This file content all the unitary tests for libMME,
+ * this library will provide all mechanisms to manage an MME frame.
+ */
+
+#include <check.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <errno.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <netinet/ether.h>
+
+#include <inttypes.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <unistd.h>
+#include <pthread.h>
+#include <linux/if_tun.h>
+
+#include "libmme.h"
+
+//#define DEBUG 1
+
+/** local defines */
+#define BUFF_LEN 1024
+#define BIG_BUFF_LEN 4096 /* to force message fragmenting */
+#define DATA_SIZE 256
+#define IFACE "tap0"
+#define DST_ADDR_STR "aa:bb:cc:dd:ee:ff"
+
+#define HEAD 256
+#define MSG_LEN 3200 /* more than 2 packets */
+//#define MSG_LEN 2
+#define TAIL ( HEAD + MSG_LEN )
+
+#ifdef DEBUG
+ #define TRACE(...) printf(__VA_ARGS__)
+#else
+ #define TRACE(...)
+#endif
+
+/** local variables */
+mme_ctx_t s_ctx;
+mme_ctx_t *ctx = &s_ctx;
+const unsigned short mmtype = 0x0; /* CC_CCO_APPOINT.REQ */
+const unsigned int len = BUFF_LEN;
+unsigned char buffer[BUFF_LEN] = {0};
+
+
+unsigned char *thread_buff = NULL;
+MME_t hdr;
+mme_ctx_t s_rcv_ctx, s_snd_ctx;
+mme_ctx_t *rcv_ctx = &s_rcv_ctx; /* where we collect CNF from the server */
+mme_ctx_t *snd_ctx = &s_snd_ctx; /* where we put REQ to the server */
+
+mme_ctx_t s_thr_ctx;
+mme_ctx_t *thr_ctx = &s_thr_ctx; /* server (thread) temporary data - where it generates what will send back */
+static unsigned char thr_buff[BIG_BUFF_LEN];
+
+static unsigned char frame_tx[PKTSIZE];
+static int tuntap_fd;
+int thread_ending = 0;
+
+unsigned char snd_buff[BIG_BUFF_LEN] = {0};
+unsigned char rcv_buff[BIG_BUFF_LEN] = {0};
+unsigned char dst_addr[6];
+
+#define DATA_SIZE_PUSH 512 /* will force payload move right; HEAD + 512 = 768; free space until the end of the buff 1024 - 768 = 256*/
+#define DATA_SIZE_PUT 512 /* to force move left of the head for 256 bytes */
+unsigned char data_push[DATA_SIZE_PUSH];
+unsigned char data_put[DATA_SIZE_PUT];
+#define FAKE_PAYLOAD_LEN 256
+unsigned char fake_payload[FAKE_PAYLOAD_LEN];
+
+int listen_var = 0;
+int thread_receiver_end = 0;
+pthread_mutex_t thread_receiver_end_mutex;
+int thread_sender_end = 0;
+pthread_mutex_t thread_sender_end_mutex;
+
+int thread_receiver_flag;
+pthread_mutex_t thread_receiver_flag_mutex;
+int thread_sender_flag;
+pthread_mutex_t thread_sender_flag_mutex;
+
+
+#if 0
+/* fixtures - run before and after each unit test */
+void setup(void)
+{
+}
+
+void teardown(void)
+{
+}
+#endif
+
+/* --- UTILITY FUNCTIONS (TUN/TAP and threads) --- */
+/**
+ * Create TUN/TAP mechanism
+ *
+ * \param init intitialization structure.
+ * \return error code.
+ */
+static int create_tuntap(void)
+{
+ int fd;
+ struct ifreq ifr;
+ char default_name[] = "tap0";
+ int error;
+
+ //Open TUN device
+ if((fd = open("/dev/net/tun", O_RDWR)) < 0)
+ {
+ printf("open /dev/net/tun failed");
+ return -1;
+ }
+
+ //Prepare TUN/TAP name
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strncpy(ifr.ifr_name, default_name, IFNAMSIZ);
+
+ //Create a TUN/TAP interface
+ if((error = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0)
+ {
+ close(fd);
+ if (error == EPERM)
+ printf("TUN/TAP creation error.\nYou need to be root to create an network interface.\n");
+ else
+ printf("TUN/TAP creation error(%d).\n",error);
+ return -1;
+ }
+
+ error = system("ifconfig tap0 up");
+
+ //sleep(20);
+
+ tuntap_fd = fd;
+
+ return 0;
+}
+
+/**
+ * Close TUN/TAP mechanism
+ *
+ * \param fd TUN/TAP file descriptor.
+ */
+static inline void close_tuntap(int fd)
+{
+ close(fd);
+}
+
+static int send_message()
+{
+ MME_t *mh = &hdr;
+ int nbpkt;
+ unsigned short hfmi;
+ int fo; /* current fragment offset */
+ int fs; /* current fragment size */
+ int i;
+ unsigned char *pkt = NULL;
+ int pkt_len;
+ int sent;
+
+ /* copy prepared header in the begining of the packet */
+ memcpy(frame_tx, mh, sizeof(MME_t));
+
+ /* set mh pointer to point to packet begining */
+ mh = (MME_t *)frame_tx;
+
+ /* we will be sending the same num of packets as we received */
+ nbpkt = ( mh->fmi & 0x0f ) + 1; /* clear out higher bits, keep only bits 0-3 */
+
+ /* set fragmentation info, nb of fragments */
+ hfmi = nbpkt - 1;
+ /* initialize fragment offset to the begining of the payload*/
+ fo = thr_ctx->head;
+
+ /* prepare and send out packets */
+ for (i=0; i<nbpkt; i++)
+ {
+ /*
+ * --- Set per-message fragmentation info, current fragment number ---
+ */
+ /* clear out higher bits, keep only bits 0-3 */
+ hfmi &= 0x0f;
+ /* set bits 4-7 to a new value */
+ hfmi |= i << 4 ;
+
+ /* We now have correct hfmi, so we can set our pkg field (in network byteorder) */
+ mh->fmi = hfmi;
+
+ /*
+ * --- Append payload ---
+ */
+ /* skip the MME header */
+ pkt = (unsigned char *)frame_tx + sizeof(MME_t);
+ /* calculate the size of the current fragment */
+ fs = ( thr_ctx->tail - fo < PKTSIZE - sizeof(MME_t) ) ? thr_ctx->tail - fo : PKTSIZE - sizeof(MME_t);
+
+ /* copy the content into packet buffer */
+ memcpy(pkt, thr_ctx->buffer + fo, fs);
+ /* update fo */
+ fo += fs;
+
+ /* zero-pad the rest if last packet fs < MME_MIN_SIZE, which is minimum size for mme packet */
+ if (fs < MME_MIN_SIZE - sizeof(MME_t))
+ {
+ memset(thr_ctx->buffer + fo, 0x0, MME_MIN_SIZE - sizeof(MME_t) - fs);
+ fs = MME_MIN_SIZE - sizeof(MME_t);
+ }
+
+ /*
+ * --- Send raw packet ---
+ */
+ /* determine the size of whole packet (header + data) */
+ pkt_len = sizeof(MME_t) + fs;
+
+
+#ifdef DEBUG
+ printf ("\n\n*************************************************** SEND function (THREAD) packet %d of %d\n", i + 1, nbpkt);
+ {
+ uint32_t *check_frame;
+ int i;
+
+ check_frame = (uint32_t*)frame_tx;
+ TRACE("\nTHREAD IS SENDING a Frame (%d bytes) : \n", pkt_len);
+ for(i=0;i<((pkt_len/4)+1);i++)
+ {
+ if((i%4 == 0) && i)
+ printf("\n");
+ printf("%08X ",*(check_frame+i));
+ }
+ printf("\n");
+ }
+#endif
+
+ if( (sent = write(tuntap_fd, frame_tx, pkt_len)) != pkt_len )
+ {
+ /* Error */
+ printf("Could only send %d bytes of packet of length %d\n", sent, pkt_len);
+ return 1;
+ }
+ } /* for */
+
+ return 0;
+}
+
+static void* thread_sender(void *unused)
+{
+ int end = 0;
+
+ TRACE("Thread 'sender' starting...\n");
+
+ while (1)
+ {
+ /*
+ * Check if we should finish
+ */
+ /* lock the mutex before accessing the flag value */
+ pthread_mutex_lock(&thread_sender_end_mutex);
+ end = thread_sender_end;
+ pthread_mutex_unlock(&thread_sender_end_mutex);
+
+ if (end)
+ break;
+
+ /*
+ * Now you can do the work
+ */
+ /* form the thread MME context */
+ thr_ctx->buffer = thr_buff;
+ thr_ctx->mmtype = mmtype; /* type of MME that server thread will be sending */
+ thr_ctx->length = sizeof(thr_buff);
+ thr_ctx->head = HEAD;
+ thr_ctx->tail = HEAD + MSG_LEN;
+ thr_ctx->status = MME_STATUS_OK;
+
+ /* clean temporary buffer */
+ memset(thr_buff, 0x0, sizeof(thr_buff));
+
+ /* write in it server thread message */
+ /* we will form test payload like this :
+ * |MME_HEADER|00...00|cc...ccee...ee|00..00|
+ * head tail
+ */
+ memset(thr_buff + HEAD, 0xcc, MSG_LEN/2);
+ memset(thr_buff+ HEAD + MSG_LEN/2, 0xee, MSG_LEN/2);
+
+ /* send the payload */
+ send_message();
+ } /* while */
+
+ TRACE("Thread 'sender' stop\n");
+ pthread_exit(NULL);
+}
+
+
+/**
+ * Send a packet, after received it from TUN/TAP.
+ */
+static void* thread_receiver(void *unused)
+{
+ int last_pkt = 0;
+ MME_t *mh = NULL;
+ unsigned char *to;
+#ifdef DEBUG
+ uint32_t *check_frame;
+ int i;
+#endif
+ unsigned short hfmi; /* fmi in host byte order */
+ int rcv_len = 0;
+ unsigned char *pkt;
+ int nbpkt;
+ unsigned char tmp_addr[6];
+ int end = 0;
+ struct timeval timeout; /* When we should time out */
+ struct timeval now;
+ struct timeval waittime;
+ fd_set fds;
+ int res;
+
+ TRACE("Thread 'receiver' starting...\n");
+
+ /* Calculate into 'timeout' when we should time out */
+ gettimeofday(&timeout, 0);
+ timeout.tv_sec += MME_TOUT;
+
+ while(1)
+ {
+ /* initialize pointer to where we will put payload */
+ to = thr_buff;
+ do /* receive the payload packages */
+ {
+ pkt = frame_tx;
+ for(;;) /* listen until we get package from our proper source */
+ {
+ /*
+ * Check if we should finish
+ */
+ /* lock the mutex before accessing the flag value */
+ pthread_mutex_lock(&thread_receiver_end_mutex);
+ end = thread_receiver_end;
+ pthread_mutex_unlock(&thread_receiver_end_mutex);
+
+ if (end)
+ {
+ goto end_receiver;
+ }
+
+ /* Force timeout if we ran out of time */
+ gettimeofday(&now, 0);
+ if ( timercmp(&now, &timeout, >) != 0 )
+ {
+ //close(tuntap_fd);
+ printf("THREAD_RECEIVER has been waiting too long withouth receiving message.\n");
+ goto end_receiver;
+ }
+
+ /* Calculate into 'waittime' how long to wait */
+ timersub(&timeout, &now, &waittime); /* wait = timeout - now */
+
+ /* Init fds with 'sock' as the only fd */
+ FD_ZERO(&fds);
+ FD_SET(tuntap_fd, &fds);
+
+ /* fds fd_set is containing only our socket, so no need to check with FD_ISSET() */
+ res = select(tuntap_fd + 1, &fds, NULL, NULL, &waittime);
+ if (res < 0)
+ {
+ perror("select() failed");
+ }
+ else if (res == 0) /* timeout */
+ {
+ TRACE("THREAD_RECEIVER has seen timeout (it was waiting on message it did not receive).\n");
+ goto end_receiver;
+ }
+
+ //Recover the frame from the TUN/TAP interface
+ TRACE("Before read (THREAD_RECEIVER)\n");
+ rcv_len = read(tuntap_fd, pkt, PKTSIZE);
+
+#ifdef DEBUG
+ if (rcv_len >= 0)
+ {
+ check_frame = (uint32_t*)frame_tx;
+ TRACE("\n\nTHREAD RECEIVED a Frame (%d bytes) : \n", rcv_len);
+ for(i=0;i<((rcv_len/4)+1);i++)
+ {
+ if((i%4 == 0) && i)
+ printf("\n");
+ printf("%08X ",*(check_frame+i));
+ }
+ printf("\n");
+ }
+#endif
+ TRACE("After read\n");
+ mh = (MME_t *)frame_tx;
+
+ if ( (rcv_len > 0) &&
+ (rcv_len >= sizeof(MME_t)) &&
+ (memcmp(mh->mme_dest, dst_addr, 6) == 0) &&
+ (mh->mmtype == mmtype)
+ ) /* if packet was ment for us and mmetype is expected*/
+ break;
+ } /* for */
+
+ /* check if the packet we received is the last one */
+ hfmi = mh->fmi;
+ if ( hfmi >> 4 == (hfmi & 0x0f) )
+ last_pkt = 1;
+
+ /* skip the MME header */
+ pkt += sizeof(MME_t);
+ rcv_len -= sizeof(MME_t);
+
+
+ /* copy the packet into the thread temporary buffer */
+ memcpy( to, pkt, rcv_len );
+ to += rcv_len;
+
+ } while (!last_pkt);
+
+ /* fill hdr header, we can do struct assignment because MME_t is packed */
+ hdr = *mh;
+ /* now move mh to point to hdr, for easier manipulation */
+ mh = &hdr;
+ /* change REQ to CNF */
+ mh->mmtype++;
+
+ /* form the thread MME context */
+ thr_ctx->buffer = thr_buff;
+ thr_ctx->mmtype = mh->mmtype; /* copy mmtype from the prepared header */
+ thr_ctx->length = sizeof(thr_buff);
+ thr_ctx->head = HEAD;
+ thr_ctx->tail = HEAD + MSG_LEN;
+ thr_ctx->status = MME_STATUS_OK;
+
+
+ /* clean temporary buffer */
+ memset(thr_buff, 0x0, sizeof(thr_buff));
+
+ /* write in it server thread message */
+ /* we will form test payload like this :
+ * |MME_HEADER|00...00|aa...aabb...bb|00..00|
+ * head tail
+ */
+ memset(thr_buff + HEAD, 0xa, MSG_LEN/2);
+ memset(thr_buff + HEAD + MSG_LEN/2, 0xb, MSG_LEN/2);
+
+ /* set the fragmentation information */
+ hfmi &= 0;
+
+ /* calculate number of mme packets needed */
+ nbpkt = (thr_ctx->tail - thr_ctx->head) / ( PKTSIZE - sizeof(MME_t) );
+ if ( (thr_ctx->tail - thr_ctx->head) % ( PKTSIZE - sizeof(MME_t) ) > 0 )
+ {
+ nbpkt++;
+ }
+ /* set fragmentation info, nb of fragments */
+ hfmi = nbpkt - 1;
+ mh->fmi = hfmi;
+
+ /* inverse the addresses */
+ memcpy(tmp_addr, mh->mme_dest, 6);
+ memcpy(mh->mme_dest, mh->mme_src, 6);
+ memcpy(mh->mme_src, tmp_addr, 6);
+
+ /* send this payload */
+ send_message();
+
+ } /* while */
+
+end_receiver:
+ TRACE("Thread 'receiver' stop\n");
+ pthread_exit(NULL);
+}
+
+/* --- TEST PROCEDURES --- */
+
+/** test procedures */
+START_TEST (test_mme_init)
+{
+ mme_error_t ret;
+
+ printf("Testing mme_init()\n");
+
+ /*zero-out ctx */
+ memset((unsigned char *)ctx, 0x0, sizeof(mme_ctx_t));
+
+ //Check arguments
+ ret = mme_init(ctx, mmtype, buffer, len);
+ fail_if(ret != MME_SUCCESS, "mme_init fail");
+
+ fail_if (ctx->length != len, "wrong lenth init");
+ fail_if (ctx->mmtype != mmtype, "wrong mmtype init");
+ fail_if (ctx->buffer != buffer, "wrong length init");
+ fail_if (ctx->head != 0, "wrong head init");
+ fail_if (ctx->tail != 0, "wrong tail init");
+ fail_if (ctx->tail != 0, "wrong tail init");
+}
+END_TEST
+
+START_TEST (test_mme_get_length)
+{
+ unsigned int chklen;
+ mme_error_t ret;
+
+ printf("Testing mme_get_length()\n");
+
+ /* SETUP CONTEXT PAYLOAD - will be used in following unit tests
+ * before getting length we will set-up our contex, not to be init vanilla (with head and tail 0) */
+ ctx->head = HEAD;
+ ctx->tail = HEAD + FAKE_PAYLOAD_LEN;
+ memset(fake_payload, 0xdd, FAKE_PAYLOAD_LEN);
+ memcpy(ctx->buffer + ctx->head, fake_payload, ctx->tail - ctx->head);
+
+ //Check arguments
+ ret = mme_get_length(ctx, &chklen);
+ fail_if(ret != MME_SUCCESS, "mme_get_length fail");
+ /* we did one push before checking the payload length */
+ fail_if (chklen != FAKE_PAYLOAD_LEN, "wrong length returned");
+}
+END_TEST
+
+START_TEST (test_mme_get_free_space)
+{
+ unsigned int chkspace;
+ mme_error_t ret;
+
+ printf("Testing mme_get_free_space()\n");
+
+ //Check arguments
+ ret = mme_get_free_space(ctx, &chkspace);
+ fail_if(ret != MME_SUCCESS, "mme_get_free_space fail");
+
+ fail_if (chkspace != BUFF_LEN - FAKE_PAYLOAD_LEN, "wrong space returned");
+ fail_if (mme_get_free_space(ctx, NULL) != MME_ERROR_GEN, "wrong null pointer protection");
+}
+END_TEST
+
+START_TEST (test_mme_push)
+{
+ mme_error_t ret;
+ int i;
+ unsigned int size;
+ unsigned int res;
+
+ TRACE("Starting mme_push() test.\n");
+
+ /*
+ * state of buffer :
+ *
+ * HEAD FAKE_PAYLOAD_LEN 1024
+ * |---------|=======================|--------------------------------------|
+ * head tail = HEAD + FAKE_PAYLOAD_LEN
+ */
+
+ /* initialize data array to some value, for example 0, 1, 2, ... */
+ for (i=0; i<sizeof(data_push); i++)
+ {
+ data_push[i] = i;
+ }
+ size = sizeof(data_push);
+
+ //Check arguments
+ ret = mme_push(ctx, (void *)data_push, size, &res);
+ fail_if(ret != MME_SUCCESS, "mme_push fail");
+
+ fail_if ( memcmp( ctx->buffer + ctx->head, data_push, sizeof(data_push) ) != 0, "wrong data pushed" );
+ if (sizeof(data_push) > ctx->head)
+ {
+ fail_if ( ctx->head != 0, "old payload wrongly shifted" );
+ fail_if ( memcmp( ctx->buffer + ctx->head + sizeof(data_push), fake_payload,
+ FAKE_PAYLOAD_LEN) != 0, "old payload wrongly shifted" );
+ if (sizeof(data_push) < ctx->head + (BUFF_LEN - ctx->tail) - 3) /* if we have at least 3 bytes of free space left */
+ {
+ /* check if finish at good place */
+ fail_if ( memcmp( ctx->buffer + ctx->head + sizeof(data_push) + FAKE_PAYLOAD_LEN,
+ "\x00\x00\x00", 3) != 0, "old payload wrongly shifted" );
+ }
+ }
+
+ size = 5000;
+ fail_if ( mme_push(ctx, (void *)data_push, size, &res) != MME_ERROR_SPACE, "free space detectoin does not work" );
+}
+END_TEST
+
+START_TEST (test_mme_put)
+{
+ mme_error_t ret;
+ int i;
+ unsigned int size;
+ unsigned int res;
+
+ printf("Testing mme_put()\n");
+
+ /*
+ * state of buffer :
+ *
+ * 768 1024
+ * |============================|---------|
+ * head tail
+ */
+
+ /* initialize data array to some value, for example 0, 1, 2, ... */
+ for (i=0; i<sizeof(data_put); i--)
+ {
+ data_put[i] = i;
+ }
+ size = sizeof(data_put);
+
+ /* make space in the begining */
+ ctx->head = 512; /* move head on the right to 512 */
+ ctx->head = 768; /* it was already here after mme_push, but just to be sure */
+ memset(ctx->buffer, 0x0, 512); /* zero-out the begining, so we can observe payload shift */
+ /*
+ * state of buffer :
+ *
+ * 512 768 1024
+ * |--------|============================|---------|
+ * head tail
+ */
+
+ //Check arguments
+ /* firs put a little chun k, to check if it works */
+ size = sizeof(data_put) / 4;
+ ret = mme_put(ctx, (void *)data_put, size, &res);
+ fail_if(ret != MME_SUCCESS, "mme_put fail");
+
+ fail_if ( memcmp( ctx->buffer + ctx->tail - sizeof(data_put), data_put, sizeof(data_put) / 4 ) != 0, "wrong data put");
+
+ /* this leaves us with 512 (before head) + 128 (after tail) bytes of free space */
+ size = sizeof(data_put); /* bigger size of trailing 128 bytes that will provoke shifting payload left */
+ ret = mme_put(ctx, (void *)data_put, size, &res);
+ fail_if(ret != MME_SUCCESS, "mme_put fail");
+ if (sizeof(data_put) > BUFF_LEN - ctx->tail) /* in this case we have shift */
+ {
+ fail_if ( memcmp( ctx->buffer + ctx->tail - sizeof(data_put), data_put, sizeof(data_put)) != 0, "wrong data shift");
+ if ( sizeof(data_put) < ctx->head + (BUFF_LEN - ctx->tail) - 3 ) /* if we have at least 3 bytes of free space left */
+ {
+ fail_if ( memcmp( ctx->buffer + ctx->head - 3, "\x00\x00\x00", 3) != 0, "wrong data shift");
+ }
+ }
+
+ size = 5000;
+ ret = mme_put(ctx, (void *)data_put, size, &res);
+ fail_if(ret != MME_ERROR_SPACE, "mme_put fail");
+}
+END_TEST
+
+START_TEST (test_mme_pull)
+{
+ unsigned char data[DATA_SIZE];
+ mme_error_t ret;
+ unsigned int size;
+ unsigned int res;
+
+ printf("Testing mme_pull()\n");
+
+ /*zero-out data */
+ memset(data, 0x0, sizeof(data));
+
+ /*zero-out buffer, we will redefine it */
+ memset(ctx->buffer, 0x0, sizeof(ctx->buffer));
+ /* reset head, tail */
+ ctx->head = HEAD;
+ ctx->tail = HEAD + FAKE_PAYLOAD_LEN;
+ /* set the fake payload into buffer */
+ memcpy(ctx->buffer + ctx->head, fake_payload, ctx->tail - ctx->head);
+ /*
+ * state of buffer :
+ *
+ * HEAD FAKE_PAYLOAD_LEN 1024
+ * |---------|=======================|--------------------------------------|
+ * head tail = HEAD + FAKE_PAYLOAD_LEN
+ */
+
+
+ size = FAKE_PAYLOAD_LEN;
+
+ //Check arguments
+ ret = mme_pull(ctx, (void *)data, size, &res);
+ fail_if(ret != MME_SUCCESS, "mme_pull fail");
+
+ /* check if we correctly pulled data that we previously pushed */
+ fail_if ( memcmp( data, fake_payload, sizeof(data) ) != 0, "wrong data pulled" );
+
+ ret = mme_pull(ctx, (void *)data, size, &res);
+ fail_if(ret != MME_ERROR_ENOUGH, "wrong enough data detection");
+}
+END_TEST
+
+START_TEST (test_mme_pop)
+{
+ unsigned char data[FAKE_PAYLOAD_LEN];
+ mme_error_t ret;
+ unsigned int size;
+ unsigned int res;
+
+ printf("Testing mme_pop()\n");
+
+ /*zero-out data */
+ memset(data, 0x0, sizeof(data));
+
+ /*zero-out buffer, we will redefine it */
+ memset(ctx->buffer, 0x0, sizeof(ctx->buffer));
+ /* reset head, tail */
+ ctx->head = HEAD;
+ ctx->tail = HEAD + FAKE_PAYLOAD_LEN;
+ /* set the fake payload into buffer */
+ memcpy(ctx->buffer + ctx->head, fake_payload, ctx->tail - ctx->head);
+ /*
+ * state of buffer :
+ *
+ * HEAD FAKE_PAYLOAD_LEN 1024
+ * |---------|=======================|--------------------------------------|
+ * head tail = HEAD + FAKE_PAYLOAD_LEN
+ */
+
+ size = FAKE_PAYLOAD_LEN;
+
+ size = sizeof(data);
+
+ //Check arguments
+ ret = mme_pop(ctx, (void *)data, size, &res);
+ fail_if(ret != MME_SUCCESS, "mme_pop fail");
+
+ /* check if we correctly popped data that we previously put */
+ fail_if ( memcmp( data, fake_payload, sizeof(data) ) != 0, "wrong data popped" );
+
+ ret = mme_pop(ctx, (void *)data, size, &res);
+ fail_if(ret != MME_ERROR_ENOUGH, "wrong enough datat detection");
+}
+END_TEST
+
+START_TEST (test_mme_send)
+{
+ mme_error_t ret;
+ pthread_t receiver;
+ char *iface = IFACE;
+
+ printf("Testing mme_send()\n");
+
+ /* for dst_addr from chosen string */
+ memcpy(dst_addr, (void *)ether_aton(DST_ADDR_STR), 6);
+ /* create TUN/TAP iface */
+ create_tuntap();
+ /* get the dest addr, it will pretend to be addr of our server thread */
+ memcpy(dst_addr, (void *)ether_aton(DST_ADDR_STR), 6);
+
+ /* form the send message context */
+ snd_ctx->buffer = snd_buff;
+ snd_ctx->mmtype = mmtype;
+ snd_ctx->length = sizeof(snd_buff);
+ snd_ctx->head = HEAD;
+ snd_ctx->tail = HEAD + MSG_LEN;
+ snd_ctx->status = MME_STATUS_OK;
+
+ /* we will form test payload like this :
+ * |MME_HEADER|00...00|11...1122...22|00..00|
+ * head tail
+ */
+ memset(snd_buff + snd_ctx->head, 0x1, MSG_LEN/2);
+ memset(snd_buff + snd_ctx->head + MSG_LEN/2, 0x2, MSG_LEN/2);
+
+ /* form the receive message context */
+ rcv_ctx->buffer = rcv_buff;
+ rcv_ctx->mmtype = mmtype + 1;
+ rcv_ctx->length = sizeof(rcv_buff);
+ rcv_ctx->head = HEAD;
+ rcv_ctx->tail = HEAD + FAKE_PAYLOAD_LEN; /* let's say we have some small data here */
+ rcv_ctx->status = MME_STATUS_OK;
+
+ /* init thread flags */
+ pthread_mutex_init (&thread_receiver_end_mutex, NULL);
+ thread_receiver_end = 0;
+ /* create thread */
+ if(pthread_create(&receiver, NULL, &thread_receiver, NULL))
+ {
+ perror("ERROR pthread_create receiver");
+ exit(EXIT_FAILURE);
+ }
+
+ // Call the send/receive function
+ ret = mme_send (snd_ctx, MME_SEND_REQ_CNF, (unsigned char *)iface, dst_addr, rcv_ctx);
+ fail_if(ret != MME_SUCCESS, "mme_send fail");
+
+ /* check if we have correctly received the payload that thread had send */
+ fail_if( memcmp(rcv_ctx->buffer + HEAD + FAKE_PAYLOAD_LEN, thr_ctx->buffer + HEAD, MSG_LEN) != 0,
+ "did not receive the same data that thread has sent");
+ ret = mme_send (NULL, MME_SEND_REQ_CNF, (unsigned char *)iface, dst_addr, rcv_ctx);
+ fail_if(ret != MME_ERROR_GEN, "mme_send NULL pointer protection fail");
+
+ ret = mme_send (snd_ctx, MME_SEND_REQ_CNF, (unsigned char *)NULL, dst_addr, rcv_ctx);
+ fail_if(ret != MME_ERROR_GEN, "mme_send NULL pointer protection fail");
+
+ ret = mme_send (snd_ctx, MME_SEND_REQ_CNF, (unsigned char *)iface, dst_addr, NULL);
+ fail_if(ret != MME_ERROR_GEN, "mme_send NULL pointer protection fail");
+
+ /* check for timeout */
+ /* reset rcv buff context */
+ memset(rcv_ctx->buffer, 0x0, sizeof(rcv_ctx->buffer));
+ rcv_ctx->head = HEAD;
+ rcv_ctx->tail = HEAD + FAKE_PAYLOAD_LEN; /* let's say we have some small data here */
+
+ rcv_ctx->mmtype = mmtype + 100;
+
+ printf("\t---> will test mme_send() timeout...\n");
+ ret = mme_send (snd_ctx, MME_SEND_REQ_CNF, (unsigned char *)iface, dst_addr, rcv_ctx);
+ fail_if(ret != MME_ERROR_TIMEOUT, "mme_send timeout not detected");
+ if (ret == MME_ERROR_TIMEOUT)
+ printf("\t---> OK, timeout well detected.\n");
+
+ //Wait thread ending
+ /* Protect the flag with a mutex lock. */
+ pthread_mutex_lock (&thread_receiver_end_mutex);
+ thread_receiver_end = 1;
+ pthread_mutex_unlock (&thread_receiver_end_mutex);
+ pthread_join(receiver, NULL);
+ /* close TUN/TAP iface */
+ close_tuntap(tuntap_fd);
+}
+END_TEST
+
+mme_error_t listen_cb (mme_ctx_t *ctx, unsigned char *iface, unsigned char *source)
+{
+ TRACE("Inside callback function.\n");
+ listen_var = 1;
+ return MME_SUCCESS;
+}
+
+START_TEST (test_mme_listen)
+{
+ mme_error_t ret;
+ char *iface = IFACE;
+ pthread_t sender;
+ MME_t *mh = &hdr;
+ struct ifreq ifr;
+ int s; /* temporary socket */
+ int i;
+
+ printf("Testing mme_listen()\n");
+
+ /* for dst_addr from chosen string */
+ memcpy(dst_addr, (void *)ether_aton(DST_ADDR_STR), 6);
+ /* create TUN/TAP iface */
+ create_tuntap();
+ /* set up header stuff */
+ memcpy(mh->mme_src, dst_addr, 6); /* thread will be our distant server */
+ /* server (thread) will send the messages to the tap interface */
+ if ( ( s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) ) == -1 ) /* create tmp socket */
+ {
+ perror("Error creating raw socket: ");
+ exit(-1);
+ }
+ memset(&ifr, 0x0, sizeof(ifr));
+ strcpy(ifr.ifr_name, iface);
+ ioctl(s, SIOCGIFHWADDR, &ifr);
+ for( i = 0; i < 6; i++ )
+ {
+ mh->mme_dest[i] = (unsigned char)ifr.ifr_hwaddr.sa_data[i];
+ }
+ close(s); /* close tmp socket, no longer needed */
+ /* protocol info */
+ mh->mtype = htons(MME_TYPE);
+ /* client (thread 'sender') MME type wil be a type of REQ */
+ mh->mmtype = mmtype;
+
+ /* init thread flags */
+ pthread_mutex_init (&thread_sender_end_mutex, NULL);
+ thread_sender_end = 0;
+ /* create a thread that will listen and send reply */
+ if(pthread_create(&sender, NULL, &thread_sender, NULL))
+ {
+ perror("ERROR pthread_create receiver");
+ exit(EXIT_FAILURE);
+ }
+
+ /* form the receive message context */
+ rcv_ctx->buffer = rcv_buff;
+ rcv_ctx->mmtype = mmtype + 1; /* server will prepare MME type CNF */
+ rcv_ctx->length = sizeof(rcv_buff);
+ rcv_ctx->head = HEAD;
+ rcv_ctx->tail = HEAD + FAKE_PAYLOAD_LEN;
+ rcv_ctx->status = MME_STATUS_OK;
+
+ // Call the send/receive function
+ ret = mme_listen (rcv_ctx, (unsigned char *)iface, dst_addr, listen_cb);
+ fail_if(ret != MME_SUCCESS, "mme_listen fail");
+
+ /* check if we have correctly received the payload that thread had send */
+ fail_if( memcmp(rcv_ctx->buffer + HEAD + FAKE_PAYLOAD_LEN, thr_ctx->buffer + HEAD, MSG_LEN) != 0,
+ "did not receive the same data that thread has sent");
+
+ ret = mme_listen (rcv_ctx, (unsigned char *)NULL, dst_addr, listen_cb);
+ fail_if(ret != MME_ERROR_GEN, "mme_send NULL pointer protection fail");
+ ret = mme_listen (rcv_ctx, (unsigned char *)iface, NULL, listen_cb);
+ fail_if(ret != MME_ERROR_GEN, "mme_send NULL pointer protection fail");
+
+ /* reset rcv buff context */
+ memset(rcv_ctx->buffer, 0x0, sizeof(rcv_ctx->buffer));
+ rcv_ctx->head = HEAD;
+ rcv_ctx->tail = HEAD + FAKE_PAYLOAD_LEN; /* let's say we have some small data here */
+ /* reset flag which notifies that callback fnc was called */
+ listen_var = 0;
+ ret = mme_listen (rcv_ctx, (unsigned char *)iface, dst_addr, NULL);
+ fail_if(ret != MME_SUCCESS || listen_var != 0, "listen without callback fnc fails");
+
+ /* check for timeout */
+ /* reset rcv buff context */
+ memset(rcv_ctx->buffer, 0x0, sizeof(rcv_ctx->buffer));
+ rcv_ctx->head = HEAD;
+ rcv_ctx->tail = HEAD + FAKE_PAYLOAD_LEN; /* let's say we have some small data here */
+
+ rcv_ctx->mmtype = mmtype + 100;
+
+ printf("\t---> will test mme_listen() timeout...\n");
+ ret = mme_listen (rcv_ctx, (unsigned char *)iface, dst_addr, listen_cb);
+ fail_if(ret != MME_ERROR_TIMEOUT, "mme_listen timeout not detected");
+ if (ret == MME_ERROR_TIMEOUT)
+ printf("\t---> OK, timeout well detected.\n");
+
+ //Wait thread ending
+ /* Protect the flag with a mutex lock. */
+ pthread_mutex_lock (&thread_sender_end_mutex);
+ thread_sender_end = 1;
+ pthread_mutex_unlock (&thread_sender_end_mutex);
+ pthread_join(sender, NULL);
+ /* close TUN/TAP iface */
+ close_tuntap(tuntap_fd);
+}
+END_TEST
+
+extern Suite* libmme_suite(void)
+{
+ Suite *s = suite_create("LIBMME");
+ TCase *tc_core = tcase_create("Core");
+
+ //Test mme_init
+ tcase_add_test(tc_core, test_mme_init);
+
+ //Test mme_init
+ tcase_add_test(tc_core, test_mme_get_length);
+
+ //Test mme_get_free_space
+ tcase_add_test(tc_core, test_mme_get_free_space);
+
+ //Test mme_push
+ tcase_add_test(tc_core, test_mme_push);
+
+ //Test mme_put
+ tcase_add_test(tc_core, test_mme_put);
+
+ //Test mme_pull
+ tcase_add_test(tc_core, test_mme_pull);
+
+ //Test mme_pop
+ tcase_add_test(tc_core, test_mme_pop);
+
+ //Test mme_send
+ tcase_add_test(tc_core, test_mme_send);
+
+ //Test mme_listen
+ tcase_add_test(tc_core, test_mme_listen);
+
+ suite_add_tcase(s, tc_core);
+ return s;
+}
+
+int main(void)
+{
+ int number_failed = 0;
+ Suite *s;
+
+ //Run libmme tests
+ s = libmme_suite();
+
+ SRunner *sr = srunner_create(s);
+ srunner_set_fork_status (sr, CK_NOFORK);
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? 0 : -1;
+}
+