Add NN_RCVMAXSIZE socket option implementation for 'ipc' transport

See nn_getsockopt man page for details.

Basic tests are in tests/ipc.c.
diff --git a/src/transports/ipc/sipc.c b/src/transports/ipc/sipc.c
index 204dc7a..0296073 100644
--- a/src/transports/ipc/sipc.c
+++ b/src/transports/ipc/sipc.c
@@ -209,6 +209,8 @@
     int rc;
     struct nn_sipc *sipc;
     uint64_t size;
+    int opt;
+    size_t opt_sz = sizeof (opt);
 
     sipc = nn_cont (self, struct nn_sipc, fsm);
 
@@ -328,10 +330,22 @@
                 switch (sipc->instate) {
                 case NN_SIPC_INSTATE_HDR:
 
-                    /*  Message header was received. Allocate memory for the
-                        message. */
+                    /*  Message header was received. Check that message size
+                        is acceptable by comparing with NN_RCVMAXSIZE;
+                        if it's too large, drop the connection. */
                     nn_assert (sipc->inhdr [0] == NN_SIPC_MSG_NORMAL);
                     size = nn_getll (sipc->inhdr + 1);
+
+                    nn_pipebase_getopt (&sipc->pipebase, NN_SOL_SOCKET,
+                        NN_RCVMAXSIZE, &opt, &opt_sz);
+
+                    if (opt >= 0 && size > (unsigned)opt) {
+                        sipc->state = NN_SIPC_STATE_DONE;
+                        nn_fsm_raise (&sipc->fsm, &sipc->done, NN_SIPC_ERROR);
+                        return;
+                    }
+
+                    /*  Allocate memory for the message. */
                     nn_msg_term (&sipc->inmsg);
                     nn_msg_init (&sipc->inmsg, (size_t) size);
 
diff --git a/tests/ipc.c b/tests/ipc.c
index d086ffb..8a8f7cb 100644
--- a/tests/ipc.c
+++ b/tests/ipc.c
@@ -37,9 +37,10 @@
     int sc;
     int i;
     int s1, s2;
-#if !defined(NN_HAVE_WINDOWS)
+    void * dummy_buf;
     int rc;
-#endif
+    int opt;
+    size_t opt_sz = sizeof (opt);
 
     int size;
     char * buf;
@@ -123,6 +124,38 @@
     test_close (s1);
 #endif
 
+    /*  Test NN_RCVMAXSIZE limit */
+    sb = test_socket (AF_SP, NN_PAIR);
+    test_bind (sb, SOCKET_ADDRESS);
+    s1 = test_socket (AF_SP, NN_PAIR);
+    test_connect (s1, SOCKET_ADDRESS);
+    opt = 4;
+    rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, opt_sz);
+    nn_assert (rc == 0);
+    nn_sleep (100);
+    test_send (s1, "ABCD");
+    test_recv (sb, "ABCD");
+    test_send (s1, "ABCDE");
+    /*  Without sleep nn_recv returns EAGAIN even for string
+        of acceptable size, so false positives are possible. */
+    nn_sleep (100);
+    rc = nn_recv (sb, &dummy_buf, NN_MSG, NN_DONTWAIT);
+    nn_assert (rc < 0);
+    errno_assert (nn_errno () == EAGAIN);
+    test_close (sb);
+    test_close (s1);
+
+    /*  Test that NN_RCVMAXSIZE can be -1, but not lower */
+    sb = test_socket (AF_SP, NN_PAIR);
+    opt = -1;
+    rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, opt_sz);
+    nn_assert (rc >= 0);
+    opt = -2;
+    rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, opt_sz);
+    nn_assert (rc < 0);
+    errno_assert (nn_errno () == EINVAL);
+    test_close (sb);
+
     /*  Test closing a socket that is waiting to connect. */
     sc = test_socket (AF_SP, NN_PAIR);
     test_connect (sc, SOCKET_ADDRESS);