summaryrefslogtreecommitdiffstats
path: root/extras/libmemif/test/socket_test.c
blob: 2d229383c2059ab439f5b5580048b40feb36e544 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
""" abstract vpp object and object registry """

import abc
import six

from six import moves


@six.add_metaclass(abc.ABCMeta)
class VppObject(object):
    """ Abstract vpp object """

    @abc.abstractmethod
    def add_vpp_config(self):
        """ Add the configuration for this object to vpp. """
        pass

    @abc.abstractmethod
    def query_vpp_config(self):
        """Query the vpp configuration.

        :return: True if the object is configured"""
        pass

    @abc.abstractmethod
    def remove_vpp_config(self):
        """ Remove the configuration for this object from vpp. """
        pass

    def object_id(self):
        """ Return a unique string representing this object. """
        return "Undefined. for <%s %s>" % (self.__class__.__name__, id(self))

    def __str__(self):
        return self.object_id()

    def __repr__(self):
        return '<%s>' % self.object_id()

    def __hash__(self):
        return hash(self.object_id())

    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        if other.object_id() == self.object_id():
            return True
        return False

    # This can be removed when python2 support is dropped.
    def __ne__(self, other):
        return not self.__eq__(other)


class VppObjectRegistry(object):
    """ Class which handles automatic configuration cleanup. """
    _shared_state = {}

    def __init__(self):
        self.__dict__ = self._shared_state
        if not hasattr(self, "_object_registry"):
            self._object_registry = []
        if not hasattr(self, "_object_dict"):
            self._object_dict = dict()

    def register(self, obj, logger):
        """ Register an object in the registry. """
        if obj.object_id() not in self._object_dict:
            self._object_registry.append(obj)
            self._object_dict[obj.object_id()] = obj
            logger.debug("REG: registering %s" % obj)
        else:
            logger.debug("REG: duplicate add, ignoring (%s)" % obj)

    def unregister_all(self, logger):
        """ Remove all object registrations from registry. """
        logger.debug("REG: removing all object registrations")
        self._object_registry = []
        self._object_dict = dict()

    def remove_vpp_config(self, logger):
        """
        Remove configuration (if present) from vpp and then remove all objects
        from the registry.
        """
        if not self._object_registry:
            logger.info("REG: No objects registered for auto-cleanup.")
       
/*
 *------------------------------------------------------------------
 * Copyright (c) 2017 Cisco and/or its affiliates.
 * Licensed 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 <socket_test.h>

#include <memif_private.h>
#include <socket.h>

static int
get_queue_len (memif_msg_queue_elt_t * q)
{
  int r = 0;
  memif_msg_queue_elt_t *c = q;
  while (c != NULL)
    {
      r++;
      c = c->next;
    }
  return r;
}

static void
queue_free (memif_msg_queue_elt_t ** e)
{
  if (*e == NULL)
    return;
  queue_free (&(*e)->next);
  free (*e);
  *e = NULL;
  return;
}

START_TEST (test_msg_queue)
{
  int err;
  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_connection_t conn;
  conn.msg_queue = NULL;
  conn.fd = -1;


  int i, len = 10;

  for (i = 0; i < len; i++)
    {
      if (i % 2)
	memif_msg_enq_ack (&conn);
      else
	memif_msg_enq_init (&conn);
    }

  ck_assert_int_eq (len, get_queue_len (conn.msg_queue));

  int pop = 6;

  for (i = 0; i < pop; i++)
    {
      if (i % 2)
	{
	  ck_assert_uint_eq (conn.msg_queue->msg.type, MEMIF_MSG_TYPE_ACK);
	}
      else
	{
	  ck_assert_uint_eq (conn.msg_queue->msg.type, MEMIF_MSG_TYPE_INIT);
	}
      conn.flags |= MEMIF_CONNECTION_FLAG_WRITE;
      /* function will return -1 because no socket is created */
      memif_conn_fd_write_ready (&conn);
    }

  ck_assert_int_eq ((len - pop), get_queue_len (conn.msg_queue));

  queue_free (&conn.msg_queue);
}

END_TEST
START_TEST (test_enq_ack)
{
  int err;
  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
  memif_connection_t conn;
  conn.msg_queue = NULL;

  if ((err = memif_msg_enq_ack (&conn)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
  memif_msg_queue_elt_t *e = conn.msg_queue;

  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_ACK);
  ck_assert_int_eq (e->fd, -1);
  queue_free (&conn.msg_queue);
}

END_TEST
START_TEST (test_enq_init)
{
  int err;
  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
  memif_connection_t conn;
  conn.msg_queue = NULL;

  conn.args.interface_id = 69;
  conn.args.mode = 0;

  strncpy ((char *) conn.args.secret, TEST_SECRET, strlen (TEST_SECRET));

  if ((err = memif_msg_enq_init (&conn)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_msg_queue_elt_t *e = conn.msg_queue;

  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_INIT);
  ck_assert_int_eq (e->fd, -1);

  memif_msg_init_t *i = &e->msg.init;

  ck_assert_uint_eq (i->version, MEMIF_VERSION);
  ck_assert_uint_eq (i->id, conn.args.interface_id);
  ck_assert_uint_eq (i->mode, conn.args.mode);
  ck_assert_str_eq ((char *)i->secret, (char *)conn.args.secret);
  queue_free (&conn.msg_queue);
}

END_TEST
START_TEST (test_enq_add_region)
{
  int err;
  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
  memif_connection_t conn;
  conn.msg_queue = NULL;
  conn.regions = (memif_region_t *) malloc (sizeof (memif_region_t));
  memif_region_t *mr = conn.regions;
  mr->fd = 5;
  mr->region_size = 2048;
  uint8_t region_index = 0;

  if ((err =
       memif_msg_enq_add_region (&conn, region_index)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_msg_queue_elt_t *e = conn.msg_queue;

  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_ADD_REGION);
  ck_assert_int_eq (e->fd, mr->fd);

  memif_msg_add_region_t *ar = &e->msg.add_region;

  ck_assert_uint_eq (ar->index, region_index);
  ck_assert_uint_eq (ar->size, mr->region_size);

  free (conn.regions);
  conn.regions = NULL;
  mr = NULL;
  queue_free (&conn.msg_queue);
}

END_TEST
START_TEST (test_enq_add_ring)
{
  int err;
  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_connection_t conn;
  conn.msg_queue = NULL;
  conn.rx_queues = (memif_queue_t *) malloc (sizeof (memif_queue_t));
  conn.tx_queues = (memif_queue_t *) malloc (sizeof (memif_queue_t));

  memif_queue_t *mq = conn.tx_queues;
  uint8_t dir = MEMIF_RING_S2M;
  mq->int_fd = 5;
  mq->offset = 0;
  mq->log2_ring_size = 10;

  if ((err = memif_msg_enq_add_ring (&conn, 0, dir)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_msg_queue_elt_t *e = conn.msg_queue;

  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_ADD_RING);
  ck_assert_int_eq (e->fd, mq->int_fd);

  memif_msg_add_ring_t *ar = &e->msg.add_ring;

  ck_assert_uint_eq (ar->index, 0);
  ck_assert_uint_eq (ar->offset, mq->offset);
  ck_assert_uint_eq (ar->log2_ring_size, mq->log2_ring_size);
  ck_assert (ar->flags & MEMIF_MSG_ADD_RING_FLAG_S2M);

  dir = MEMIF_RING_M2S;
  if ((err = memif_msg_enq_add_ring (&conn, 0, dir)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
  queue_free (&conn.msg_queue);
}

END_TEST
START_TEST (test_enq_connect)
{
  int err;
  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
  memif_connection_t conn;
  conn.msg_queue = NULL;
  memset (conn.args.interface_name, 0, sizeof (conn.args.interface_name));
  strncpy ((char *) conn.args.interface_name, TEST_IF_NAME,
	   strlen (TEST_IF_NAME));

  if ((err = memif_msg_enq_connect (&conn)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_msg_queue_elt_t *e = conn.msg_queue;

  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_CONNECT);
  ck_assert_int_eq (e->fd, -1);
  ck_assert_str_eq ((char *)e->msg.connect.if_name, TEST_IF_NAME);
  queue_free (&conn.msg_queue);
}

END_TEST
START_TEST (test_enq_connected)
{
  int err;
  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));
  memif_connection_t conn;
  conn.msg_queue = NULL;
  memset (conn.args.interface_name, 0, sizeof (conn.args.interface_name));
  strncpy ((char *) conn.args.interface_name, TEST_IF_NAME,
	   strlen (TEST_IF_NAME));

  if ((err = memif_msg_enq_connected (&conn)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_msg_queue_elt_t *e = conn.msg_queue;

  ck_assert_uint_eq (e->msg.type, MEMIF_MSG_TYPE_CONNECTED);
  ck_assert_int_eq (e->fd, -1);
  ck_assert_str_eq ((char *)e->msg.connect.if_name, TEST_IF_NAME);
  queue_free (&conn.msg_queue);
}

END_TEST
START_TEST (test_send)
{
  int err;
  int fd = -1, afd = 5;
  memif_msg_t msg;
  memset (&msg, 0, sizeof (msg));

  if ((err = memif_msg_send (fd, &msg, afd)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg (err == MEMIF_ERR_BAD_FD,
		   "err code: %u, err msg: %s", err, memif_strerror (err));
}

END_TEST
START_TEST (test_send_hello)
{
  int err;
  memif_connection_t conn;
  conn.fd = -1;

  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  conn.args.socket = libmemif_main.default_socket;

  if ((err = memif_msg_send_hello (get_libmemif_main (conn.args.socket), conn.fd)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg (err == MEMIF_ERR_BAD_FD,
		   "err code: %u, err msg: %s", err, memif_strerror (err));
}

END_TEST
START_TEST (test_send_disconnect)
{
  int err;
  memif_connection_t conn;
  conn.fd = -1;

  /* only possible fail if memif_msg_send fails...  */
  /* obsolete without socket */
  if ((err =
       memif_msg_send_disconnect (conn.fd, (uint8_t *)"unit_test_dc",
				  0)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg (err == MEMIF_ERR_BAD_FD, "err code: %u, err msg: %s", err,
		   memif_strerror (err));
}

END_TEST
START_TEST (test_recv_hello)
{
  int err;
  memif_connection_t conn;
  memif_msg_t msg;

  memif_msg_hello_t *h = &msg.hello;

  msg.type = MEMIF_MSG_TYPE_HELLO;

  h->min_version = MEMIF_VERSION;
  h->max_version = MEMIF_VERSION;
  h->max_s2m_ring = 1;
  h->max_m2s_ring = 1;
  h->max_log2_ring_size = 14;
  strncpy ((char *) h->name, TEST_IF_NAME, strlen (TEST_IF_NAME));
  memset (conn.remote_name, 0, sizeof (conn.remote_name));

  conn.args.num_s2m_rings = 4;
  conn.args.num_m2s_rings = 6;
  conn.args.log2_ring_size = 10;

  if ((err = memif_msg_receive_hello (&conn, &msg)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  ck_assert_uint_eq (conn.run_args.num_s2m_rings, 2);
  ck_assert_uint_eq (conn.run_args.num_m2s_rings, 2);
  ck_assert_uint_eq (conn.run_args.log2_ring_size, 10);
  ck_assert_str_eq ((char *)conn.remote_name, TEST_IF_NAME);

  h->max_version = 9;
  if ((err = memif_msg_receive_hello (&conn, &msg)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg (err == MEMIF_ERR_PROTO,
		   "err code: %u, err msg: %s", err, memif_strerror (err));
}

END_TEST
START_TEST (test_recv_init)
{
  int err;
  memif_connection_t conn;

  conn.args.interface_id = 69;
  conn.args.is_master = 1;
  conn.fd = -1;
  conn.args.mode = 0;
  memset (conn.args.secret, '\0', 24);
  strncpy ((char *) conn.args.secret, TEST_SECRET, strlen (TEST_SECRET));

  memif_msg_t msg;

  memif_msg_init_t *i = &msg.init;

  msg.type = MEMIF_MSG_TYPE_INIT;

  i->version = MEMIF_VERSION;
  i->id = 69;
  i->mode = 0;
  memset (i->name, '\0', 32);
  memset (i->secret, '\0', 24);
  strncpy ((char *) i->name, TEST_IF_NAME, strlen (TEST_IF_NAME));
  strncpy ((char *) i->secret, TEST_SECRET, strlen (TEST_SECRET));

  memif_socket_t ms;
  ms.interface_list_len = 1;
  ms.interface_list = malloc (sizeof (memif_list_elt_t));
  memif_list_elt_t elt;
  elt.key = 69;
  elt.data_struct = &conn;
  add_list_elt (get_libmemif_main (conn.args.socket), &elt, &ms.interface_list, &ms.interface_list_len);

  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  i->version = 9;
  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg (err == MEMIF_ERR_PROTO,
		   "err code: %u, err msg: %s", err, memif_strerror (err));
  i->version = MEMIF_VERSION;

  i->id = 78;
  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg (err == MEMIF_ERR_ID,
		   "err code: %u, err msg: %s", err, memif_strerror (err));
  i->id = 69;

  i->mode = 1;
  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg (err == MEMIF_ERR_MODE,
		   "err code: %u, err msg: %s", err, memif_strerror (err));
  i->mode = 0;

  i->secret[0] = '\0';
  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg (err == MEMIF_ERR_SECRET,
		   "err code: %u, err msg: %s", err, memif_strerror (err));
  strncpy ((char *) i->secret, TEST_SECRET, strlen (TEST_SECRET));

  conn.args.is_master = 0;
  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg (err == MEMIF_ERR_ACCSLAVE,
		   "err code: %u, err msg: %s", err, memif_strerror (err));
  conn.args.is_master = 1;

  conn.fd = 5;
  if ((err = memif_msg_receive_init (&ms, -1, &msg)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg ((err == MEMIF_ERR_ALRCONN) || (err == MEMIF_ERR_BAD_FD),
		   "err code: %u, err msg: %s", err, memif_strerror (err));
}

END_TEST
START_TEST (test_recv_add_region)
{
  int err;
  memif_connection_t conn;
  conn.regions = NULL;
  memif_msg_t msg;
  msg.type = MEMIF_MSG_TYPE_ADD_REGION;
  msg.add_region.size = 2048;
  msg.add_region.index = 0;

  int fd = 5;

  if ((err =
       memif_msg_receive_add_region (&conn, &msg, fd)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_region_t *mr = conn.regions;

  ck_assert_uint_eq (mr->fd, fd);
  ck_assert_uint_eq (mr->region_size, 2048);
  ck_assert_ptr_eq (mr->addr, NULL);
}

END_TEST
START_TEST (test_recv_add_ring)
{
  int err;
  memif_connection_t conn;
  int fd = 5;
  memif_msg_t msg;
  conn.args.num_s2m_rings = 2;
  conn.args.num_m2s_rings = 2;
  conn.rx_queues = NULL;
  conn.tx_queues = NULL;

  msg.type = MEMIF_MSG_TYPE_ADD_RING;
  memif_msg_add_ring_t *ar = &msg.add_ring;

  ar->log2_ring_size = 10;
  ar->region = 0;
  ar->offset = 0;
  ar->flags = 0;
  ar->flags |= MEMIF_MSG_ADD_RING_FLAG_S2M;
  ar->index = 1;

  if ((err =
       memif_msg_receive_add_ring (&conn, &msg, fd)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));


  ar->offset = 2048;
  ar->flags &= ~MEMIF_MSG_ADD_RING_FLAG_S2M;

  if ((err =
       memif_msg_receive_add_ring (&conn, &msg, fd)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

}

END_TEST
START_TEST (test_recv_connect)
{
  int err;
  memif_conn_handle_t c = NULL;
  memif_conn_args_t args;
  memset (&args, 0, sizeof (args));

  args.interface_id = 0;
  args.is_master = 0;
  args.mode = 0;

  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  if ((err = memif_create (&c, &args, on_connect,
			   on_disconnect, on_interrupt,
			   NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_connection_t *conn = (memif_connection_t *) c;

  conn->run_args.num_s2m_rings = 1;
  conn->run_args.num_m2s_rings = 1;
  conn->run_args.log2_ring_size = 10;
  conn->run_args.buffer_size = 2048;

  if ((err = memif_init_regions_and_queues (conn)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_msg_t msg;
  memset (&msg, 0, sizeof (msg));
  msg.type = MEMIF_MSG_TYPE_CONNECT;

  memset (msg.connect.if_name, 0, sizeof (msg.connect.if_name));
  strncpy ((char *) msg.connect.if_name, TEST_IF_NAME, strlen (TEST_IF_NAME));

  if ((err = memif_msg_receive_connect (conn, &msg)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  ck_assert_str_eq ((char *)conn->remote_if_name, TEST_IF_NAME);
}

END_TEST
START_TEST (test_recv_connected)
{
  int err;
  memif_conn_handle_t c = NULL;
  memif_conn_args_t args;
  memset (&args, 0, sizeof (args));

  args.interface_id = 0;
  args.is_master = 0;
  args.mode = 0;

  if ((err =
       memif_init (control_fd_update, TEST_APP_NAME, NULL,
		   NULL, NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  if ((err = memif_create (&c, &args, on_connect,
			   on_disconnect, on_interrupt,
			   NULL)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_connection_t *conn = (memif_connection_t *) c;

  conn->run_args.num_s2m_rings = 1;
  conn->run_args.num_m2s_rings = 1;
  conn->run_args.log2_ring_size = 10;
  conn->run_args.buffer_size = 2048;

  if ((err = memif_init_regions_and_queues (conn)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  memif_msg_t msg;
  memset (&msg, 0, sizeof (msg));
  msg.type = MEMIF_MSG_TYPE_CONNECT;

  memset (msg.connect.if_name, 0, sizeof (msg.connect.if_name));
  strncpy ((char *) msg.connect.if_name, TEST_IF_NAME, strlen (TEST_IF_NAME));

  if ((err = memif_msg_receive_connected (conn, &msg)) != MEMIF_ERR_SUCCESS)
    ck_abort_msg ("err code: %u, err msg: %s", err, memif_strerror (err));

  ck_assert_str_eq ((char *)conn->remote_if_name, TEST_IF_NAME);
}

END_TEST
START_TEST (test_recv_disconnect)
{
  int err;
  memif_connection_t conn;
  memif_msg_t msg;
  msg.type = MEMIF_MSG_TYPE_DISCONNECT;
  memset (msg.disconnect.string, 0, sizeof (msg.disconnect.string));
  strncpy ((char *) msg.disconnect.string, "unit_test_dc", 12);

  if ((err = memif_msg_receive_disconnect (&conn, &msg)) != MEMIF_ERR_SUCCESS)
    ck_assert_msg (err == MEMIF_ERR_DISCONNECT,
		   "err code: %u, err msg: %s", err, memif_strerror (err));

  ck_assert_str_eq ((char *)conn.remote_disconnect_string, "unit_test_dc");
}

END_TEST Suite *
socket_suite ()
{
  Suite *s;
  TCase *tc_msg_queue;
  TCase *tc_msg_enq;
  TCase *tc_msg_send;
  TCase *tc_msg_recv;

  /* create socket test suite */
  s = suite_create ("Socket messaging");

  /* create msg queue test case */
  tc_msg_queue = tcase_create ("Message queue");
  /* add tests to test case */
  tcase_add_test (tc_msg_queue, test_msg_queue);

  /* create msg enq test case */
  tc_msg_enq = tcase_create ("Message enqueue");
  /* add tests to test case */
  tcase_add_test (tc_msg_enq, test_enq_ack);
  tcase_add_test (tc_msg_enq, test_enq_init);
  tcase_add_test (tc_msg_enq, test_enq_add_region);
  tcase_add_test (tc_msg_enq, test_enq_add_ring);
  tcase_add_test (tc_msg_enq, test_enq_connect);
  tcase_add_test (tc_msg_enq, test_enq_connected);

  /* create msg send test case */
  tc_msg_send = tcase_create ("Message send");
  /* add tests to test case */
  tcase_add_test (tc_msg_send, test_send);
  tcase_add_test (tc_msg_send, test_send_hello);
  tcase_add_test (tc_msg_send, test_send_disconnect);

  /* create msg recv test case */
  tc_msg_recv = tcase_create ("Message receive");
  /* add tests to test case */
  tcase_add_test (tc_msg_recv, test_recv_hello);
  tcase_add_test (tc_msg_recv, test_recv_init);
  tcase_add_test (tc_msg_recv, test_recv_add_region);
  tcase_add_test (tc_msg_recv, test_recv_add_ring);
  tcase_add_test (tc_msg_recv, test_recv_connect);
  tcase_add_test (tc_msg_recv, test_recv_connected);
  tcase_add_test (tc_msg_recv, test_recv_disconnect);

  /* add test cases to test suite */
  suite_add_tcase (s, tc_msg_queue);
  suite_add_tcase (s, tc_msg_enq);
  suite_add_tcase (s, tc_msg_send);
  suite_add_tcase (s, tc_msg_recv);

  /* return socket test suite to test runner */
  return s;
}