fixes #735 epbase seems to have no purpose
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index aaeb9a4..3e148b4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -38,7 +38,6 @@
 
     core/ep.h
     core/ep.c
-    core/epbase.c
     core/global.h
     core/global.c
     core/pipe.c
diff --git a/src/core/ep.c b/src/core/ep.c
index 94b5f5e..a39f01a 100644
--- a/src/core/ep.c
+++ b/src/core/ep.c
@@ -1,6 +1,7 @@
 /*
     Copyright (c) 2012 Martin Sustrik  All rights reserved.
     Copyright (c) 2013 GoPivotal, Inc.  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -54,7 +55,6 @@
         src, self, &sock->fsm);
     self->state = NN_EP_STATE_IDLE;
 
-    self->epbase = NULL;
     self->sock = sock;
     self->eid = eid;
     self->last_errno = 0;
@@ -67,9 +67,9 @@
 
     /*  Create transport-specific part of the endpoint. */
     if (bind)
-        rc = transport->bind ((void*) self, &self->epbase);
+        rc = transport->bind (self);
     else
-        rc = transport->connect ((void*) self, &self->epbase);
+        rc = transport->connect (self);
 
     /*  Endpoint creation failed. */
     if (rc < 0) {
@@ -85,7 +85,7 @@
 {
     nn_assert_state (self, NN_EP_STATE_IDLE);
 
-    self->epbase->vfptr->destroy (self->epbase);
+    self->vfptr->destroy (self);
     nn_list_item_term (&self->item);
     nn_fsm_term (&self->fsm);
 }
@@ -143,7 +143,7 @@
     ep = nn_cont (self, struct nn_ep, fsm);
 
     if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
-        ep->epbase->vfptr->stop (ep->epbase);
+        ep->vfptr->stop (ep);
         ep->state = NN_EP_STATE_STOPPING;
         return;
     }
@@ -228,3 +228,24 @@
 {
     nn_sock_stat_increment (self->sock, name, increment);
 }
+
+/*  Get transport private state object. */
+void *nn_ep_tran_private (struct nn_ep *self)
+{
+    return self->tran_private;
+}
+
+int nn_ep_ispeer_ep (struct nn_ep *self, struct nn_ep *other)
+{
+    return nn_ep_ispeer (self, other->sock->socktype->protocol);
+}
+
+/*  Set up an ep for use by a transport.  Note that the core will already have
+    done most of the initialization steps.  The associated data can be retrieved
+    later with nn_ep_tran_private(). */
+void nn_ep_tran_setup (struct nn_ep *ep, const struct nn_ep_vfptr *vfptr,
+    void *data)
+{
+    ep->vfptr = vfptr;
+    ep->tran_private = data;
+}
diff --git a/src/core/ep.h b/src/core/ep.h
index d32c23b..1e44930 100644
--- a/src/core/ep.h
+++ b/src/core/ep.h
@@ -35,15 +35,21 @@
 struct nn_ep {
     struct nn_fsm fsm;
     int state;
-    struct nn_epbase *epbase;
     struct nn_sock *sock;
     struct nn_ep_options options;
     int eid;
     struct nn_list_item item;
     char addr [NN_SOCKADDR_MAX + 1];
+    int protocol;
 
     /*  Error state for endpoint */
     int last_errno;
+
+    /*  Transport private state structure */
+    void *tran_private;
+
+    /*  Transport specific operations */
+    const struct nn_ep_vfptr *vfptr;
 };
 
 int nn_ep_init (struct nn_ep *self, int src, struct nn_sock *sock, int eid,
diff --git a/src/core/epbase.c b/src/core/epbase.c
deleted file mode 100644
index 28e0905..0000000
--- a/src/core/epbase.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-    Copyright (c) 2013 Martin Sustrik  All rights reserved.
-
-    Permission is hereby granted, free of charge, to any person obtaining a copy
-    of this software and associated documentation files (the "Software"),
-    to deal in the Software without restriction, including without limitation
-    the rights to use, copy, modify, merge, publish, distribute, sublicense,
-    and/or sell copies of the Software, and to permit persons to whom
-    the Software is furnished to do so, subject to the following conditions:
-
-    The above copyright notice and this permission notice shall be included
-    in all copies or substantial portions of the Software.
-
-    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-    IN THE SOFTWARE.
-*/
-
-#include "../transport.h"
-
-#include "ep.h"
-#include "sock.h"
-#include "../utils/attr.h"
-
-void nn_epbase_init (struct nn_epbase *self,
-    const struct nn_epbase_vfptr *vfptr, void *hint)
-{
-    self->vfptr = vfptr;
-    self->ep = (struct nn_ep*) hint;
-}
-
-void nn_epbase_term (NN_UNUSED struct nn_epbase *self)
-{
-}
-
-void nn_epbase_stopped (struct nn_epbase *self)
-{
-    nn_ep_stopped (self->ep);
-}
-
-struct nn_ctx *nn_epbase_getctx (struct nn_epbase *self)
-{
-    return nn_ep_getctx (self->ep);
-}
-
-const char *nn_epbase_getaddr (struct nn_epbase *self)
-{
-    return nn_ep_getaddr (self->ep);
-}
-
-void nn_epbase_getopt (struct nn_epbase *self, int level, int option,
-    void *optval, size_t *optvallen)
-{
-    nn_ep_getopt (self->ep, level, option, optval, optvallen);
-}
-
-int nn_epbase_ispeer (struct nn_epbase *self, int socktype)
-{
-    return nn_ep_ispeer (self->ep, socktype);
-}
-
-void nn_epbase_set_error (struct nn_epbase *self, int errnum)
-{
-    nn_ep_set_error (self->ep, errnum);
-}
-
-void nn_epbase_clear_error (struct nn_epbase *self)
-{
-    nn_ep_clear_error (self->ep);
-}
-
-void nn_epbase_stat_increment(struct nn_epbase *self, int name, int increment) {
-    nn_ep_stat_increment(self->ep, name, increment);
-}
diff --git a/src/core/pipe.c b/src/core/pipe.c
index 5308c3a..e495b80 100644
--- a/src/core/pipe.c
+++ b/src/core/pipe.c
@@ -48,18 +48,17 @@
 #define NN_PIPEBASE_OUTSTATE_ASYNC 4
 
 void nn_pipebase_init (struct nn_pipebase *self,
-    const struct nn_pipebase_vfptr *vfptr, struct nn_epbase *epbase)
+    const struct nn_pipebase_vfptr *vfptr, struct nn_ep *ep)
 {
-    nn_assert (epbase->ep->sock);
+    nn_assert (ep->sock);
 
-    nn_fsm_init (&self->fsm, NULL, NULL, 0, self, &epbase->ep->sock->fsm);
+    nn_fsm_init (&self->fsm, NULL, NULL, 0, self, &ep->sock->fsm);
     self->vfptr = vfptr;
     self->state = NN_PIPEBASE_STATE_IDLE;
     self->instate = NN_PIPEBASE_INSTATE_DEACTIVATED;
     self->outstate = NN_PIPEBASE_OUTSTATE_DEACTIVATED;
-    self->sock = epbase->ep->sock;
-    memcpy (&self->options, &epbase->ep->options,
-        sizeof (struct nn_ep_options));
+    self->sock = ep->sock;
+    memcpy (&self->options, &ep->options, sizeof (struct nn_ep_options));
     nn_fsm_event_init (&self->in);
     nn_fsm_event_init (&self->out);
 }
@@ -223,4 +222,3 @@
     pipebase = (struct nn_pipebase*) self;
     nn_pipebase_getopt (pipebase, level, option, optval, optvallen);
 }
-
diff --git a/src/transport.h b/src/transport.h
index d56a77a..86fb817 100644
--- a/src/transport.h
+++ b/src/transport.h
@@ -1,6 +1,7 @@
 /*
     Copyright (c) 2012-2014 Martin Sustrik  All rights reserved.
     Copyright (c) 2013 GoPivotal, Inc.  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -64,57 +65,54 @@
     by each nn_bind() or nn_connect() call. Each endpoint is associated with
     exactly one address string (e.g. "tcp://127.0.0.1:5555"). */
 
-struct nn_epbase;
+struct nn_ep;
 
-struct nn_epbase_vfptr {
+struct nn_ep_vfptr {
 
     /*  Ask the endpoint to stop itself. The endpoint is allowed to linger
         to send the pending outbound data. When done, it reports the fact by
-        invoking nn_epbase_stopped() function. */
-    void (*stop) (struct nn_epbase *self);
+        invoking nn_ep_stopped() function. */
+    void (*stop) (struct nn_ep *);
 
     /*  Deallocate the endpoint object. */
-    void (*destroy) (struct nn_epbase *self);
+    void (*destroy) (struct nn_ep *);
 };
 
-struct nn_epbase {
-    const struct nn_epbase_vfptr *vfptr;
-    struct nn_ep *ep;
-};
+/*  Gets the opaque value stored by a transport at setup time. */
+void *nn_ep_tran_private (struct nn_ep *);
 
-/*  Creates a new endpoint. 'hint' parameter is an opaque value that
-    was passed to transport's bind or connect function. */
-void nn_epbase_init (struct nn_epbase *self,
-    const struct nn_epbase_vfptr *vfptr, void *hint);
+/*  Set up an ep for use by a transport.  The final opaque argument can be
+    accessed later by calling nn_ep_tran_private(). */
+void nn_ep_tran_setup (struct nn_ep *, const struct nn_ep_vfptr *, void *);
 
 /*  Notify the user that stopping is done. */
-void nn_epbase_stopped (struct nn_epbase *self);
-
-/*  Terminate the epbase object. */
-void nn_epbase_term (struct nn_epbase *self);
+void nn_ep_stopped (struct nn_ep *);
 
 /*  Returns the AIO context associated with the endpoint. */
-struct nn_ctx *nn_epbase_getctx (struct nn_epbase *self);
+struct nn_ctx *nn_ep_getctx (struct nn_ep *);
 
 /*  Returns the address string associated with this endpoint. */
-const char *nn_epbase_getaddr (struct nn_epbase *self);
+const char *nn_ep_getaddr (struct nn_ep *self);
 
 /*  Retrieve value of a socket option. */
-void nn_epbase_getopt (struct nn_epbase *self, int level, int option,
+void nn_ep_getopt (struct nn_ep *, int level, int option,
     void *optval, size_t *optvallen);
 
-/*  Returns 1 is the specified socket type is a valid peer for this socket,
+/*  Returns 1 if the specified socket type is a valid peer for this socket,
     or 0 otherwise. */
-int nn_epbase_ispeer (struct nn_epbase *self, int socktype);
+int nn_ep_ispeer (struct nn_ep *, int socktype);
+
+/*  Returns 1 if the ep's are valid peers for each other, 0 otherwise. */
+int nn_ep_ispeer_ep (struct nn_ep *, struct nn_ep *);
 
 /*  Notifies a monitoring system the error on this endpoint  */
-void nn_epbase_set_error(struct nn_epbase *self, int errnum);
+void nn_ep_set_error(struct nn_ep*, int errnum);
 
 /*  Notifies a monitoring system that error is gone  */
-void nn_epbase_clear_error(struct nn_epbase *self);
+void nn_ep_clear_error(struct nn_ep *);
 
 /*  Increments statistics counters in the socket structure  */
-void nn_epbase_stat_increment(struct nn_epbase *self, int name, int increment);
+void nn_ep_stat_increment(struct nn_ep *, int name, int increment);
 
 
 /******************************************************************************/
@@ -176,7 +174,7 @@
 
 /*  Initialise the pipe.  */
 void nn_pipebase_init (struct nn_pipebase *self,
-    const struct nn_pipebase_vfptr *vfptr, struct nn_epbase *epbase);
+    const struct nn_pipebase_vfptr *vfptr, struct nn_ep *ep);
 
 /*  Terminate the pipe. */
 void nn_pipebase_term (struct nn_pipebase *self);
@@ -222,14 +220,13 @@
     void (*init) (void);
     void (*term) (void);
 
-    /*  Each of these functions creates an endpoint and returns the newly
-        created endpoint in 'epbase' parameter. 'hint' is in opaque pointer
-        to be passed to nn_epbase_init(). The epbase object can then be used
-        to retrieve the address to bind/connect to. These functions are guarded
-        by a socket-wide critical section. Two of these function will never be
-        invoked in parallel on the same socket. */
-    int (*bind) (void *hint, struct nn_epbase **epbase);
-    int (*connect) (void *hint, struct nn_epbase **epbase);
+    /*  Each of these functions creates an endpoint and sets up the newly
+        established endpoint in 'ep' parameter using nn_ep_tran_setup ().
+        These functions are guarded by a socket-wide critical section.
+        Two of these function will never be invoked in parallel on the same
+        socket. */
+    int (*bind) (struct nn_ep *);
+    int (*connect) (struct nn_ep *);
 
     /*  Create an object to hold transport-specific socket options.
         Set this member to NULL in case there are no transport-specific
diff --git a/src/transports/inproc/binproc.c b/src/transports/inproc/binproc.c
index af96045..d7fc7d6 100644
--- a/src/transports/inproc/binproc.c
+++ b/src/transports/inproc/binproc.c
@@ -1,6 +1,7 @@
 /*
     Copyright (c) 2012-2013 Martin Sustrik  All rights reserved.
     Copyright (c) 2013 GoPivotal, Inc.  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -37,10 +38,10 @@
 
 #define NN_BINPROC_SRC_SINPROC 1
 
-/*  Implementation of nn_epbase interface. */
-static void nn_binproc_stop (struct nn_epbase *self);
-static void nn_binproc_destroy (struct nn_epbase *self);
-static const struct nn_epbase_vfptr nn_binproc_vfptr = {
+/*  Implementation of nn_ep interface. */
+static void nn_binproc_stop (struct nn_ep *);
+static void nn_binproc_destroy (struct nn_ep *);
+static const struct nn_ep_vfptr nn_binproc_vfptr = {
     nn_binproc_stop,
     nn_binproc_destroy
 };
@@ -54,7 +55,7 @@
     struct nn_ins_item *peer);
 
 
-int nn_binproc_create (void *hint, struct nn_epbase **epbase)
+int nn_binproc_create (struct nn_ep *ep)
 {
     int rc;
     struct nn_binproc *self;
@@ -62,9 +63,9 @@
     self = nn_alloc (sizeof (struct nn_binproc), "binproc");
     alloc_assert (self);
 
-    nn_ins_item_init (&self->item, &nn_binproc_vfptr, hint);
+    nn_ins_item_init (&self->item, ep);
     nn_fsm_init_root (&self->fsm, nn_binproc_handler, nn_binproc_shutdown,
-        nn_epbase_getctx (&self->item.epbase));
+        nn_ep_getctx (ep));
     self->state = NN_BINPROC_STATE_IDLE;
     nn_list_init (&self->sinprocs);
 
@@ -73,7 +74,7 @@
 
     /*  Register the inproc endpoint into a global repository. */
     rc = nn_ins_bind (&self->item, nn_binproc_connect);
-    if (nn_slow (rc < 0)) {
+    if (rc < 0) {
         nn_list_term (&self->sinprocs);
 
         /*  TODO: Now, this is ugly! We are getting the state machine into
@@ -86,24 +87,24 @@
         return rc;
     }
 
-    *epbase = &self->item.epbase;
+    nn_ep_tran_setup (ep, &nn_binproc_vfptr, self);
     return 0;
 }
 
-static void nn_binproc_stop (struct nn_epbase *self)
+static void nn_binproc_stop (struct nn_ep *ep)
 {
     struct nn_binproc *binproc;
 
-    binproc = nn_cont (self, struct nn_binproc, item.epbase);
+    binproc = nn_ep_tran_private (ep);
 
     nn_fsm_stop (&binproc->fsm);
 }
 
-static void nn_binproc_destroy (struct nn_epbase *self)
+static void nn_binproc_destroy (struct nn_ep *ep)
 {
     struct nn_binproc *binproc;
 
-    binproc = nn_cont (self, struct nn_binproc, item.epbase);
+    binproc = nn_ep_tran_private (ep);
 
     nn_list_term (&binproc->sinprocs);
     nn_fsm_term (&binproc->fsm);
@@ -127,13 +128,12 @@
     sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc");
     alloc_assert (sinproc);
     nn_sinproc_init (sinproc, NN_BINPROC_SRC_SINPROC,
-        &binproc->item.epbase, &binproc->fsm);
+        binproc->item.ep, &binproc->fsm);
     nn_list_insert (&binproc->sinprocs, &sinproc->item,
         nn_list_end (&binproc->sinprocs));
     nn_sinproc_connect (sinproc, &cinproc->fsm);
 
-    nn_epbase_stat_increment (&binproc->item.epbase,
-        NN_STAT_ACCEPTED_CONNECTIONS, 1);
+    nn_ep_stat_increment (binproc->item.ep, NN_STAT_ACCEPTED_CONNECTIONS, 1);
 }
 
 static void nn_binproc_shutdown (struct nn_fsm *self, int src, int type,
@@ -162,7 +162,7 @@
         binproc->state = NN_BINPROC_STATE_STOPPING;
         goto finish;
     }
-    if (nn_slow (binproc->state == NN_BINPROC_STATE_STOPPING)) {
+    if (binproc->state == NN_BINPROC_STATE_STOPPING) {
         nn_assert (src == NN_BINPROC_SRC_SINPROC && type == NN_SINPROC_STOPPED);
         sinproc = (struct nn_sinproc*) srcptr;
         nn_list_erase (&binproc->sinprocs, &sinproc->item);
@@ -173,7 +173,7 @@
             return;
         binproc->state = NN_BINPROC_STATE_IDLE;
         nn_fsm_stopped_noevent (&binproc->fsm);
-        nn_epbase_stopped (&binproc->item.epbase);
+        nn_ep_stopped (binproc->item.ep);
         return;
     }
 
@@ -223,7 +223,7 @@
                 sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc");
                 alloc_assert (sinproc);
                 nn_sinproc_init (sinproc, NN_BINPROC_SRC_SINPROC,
-                    &binproc->item.epbase, &binproc->fsm);
+                    binproc->item.ep, &binproc->fsm);
                 nn_list_insert (&binproc->sinprocs, &sinproc->item,
                     nn_list_end (&binproc->sinprocs));
                 nn_sinproc_accept (sinproc, peer);
@@ -246,4 +246,3 @@
         nn_fsm_bad_state (binproc->state, src, type);
     }
 }
-
diff --git a/src/transports/inproc/binproc.h b/src/transports/inproc/binproc.h
index 4516bfa..0320673 100644
--- a/src/transports/inproc/binproc.h
+++ b/src/transports/inproc/binproc.h
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2012-2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -46,6 +47,6 @@
     struct nn_list sinprocs;
 };
 
-int nn_binproc_create (void *hint, struct nn_epbase **epbase);
+int nn_binproc_create (struct nn_ep *);
 
 #endif
diff --git a/src/transports/inproc/cinproc.c b/src/transports/inproc/cinproc.c
index 00c1bb7..06d9466 100644
--- a/src/transports/inproc/cinproc.c
+++ b/src/transports/inproc/cinproc.c
@@ -1,6 +1,7 @@
  /*
     Copyright (c) 2012-2013 Martin Sustrik  All rights reserved.
     Copyright (c) 2013 GoPivotal, Inc.  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -40,10 +41,10 @@
 
 #define NN_CINPROC_SRC_SINPROC 1
 
-/*  Implementation of nn_epbase callback interface. */
-static void nn_cinproc_stop (struct nn_epbase *self);
-static void nn_cinproc_destroy (struct nn_epbase *self);
-static const struct nn_epbase_vfptr nn_cinproc_vfptr = {
+/*  Implementation of nn_ep callback interface. */
+static void nn_cinproc_stop (struct nn_ep *);
+static void nn_cinproc_destroy (struct nn_ep *);
+static const struct nn_ep_vfptr nn_cinproc_vfptr = {
     nn_cinproc_stop,
     nn_cinproc_destroy
 };
@@ -56,21 +57,22 @@
 static void nn_cinproc_connect (struct nn_ins_item *self,
     struct nn_ins_item *peer);
 
-int nn_cinproc_create (void *hint, struct nn_epbase **epbase)
+int nn_cinproc_create (struct nn_ep *ep)
 {
     struct nn_cinproc *self;
 
     self = nn_alloc (sizeof (struct nn_cinproc), "cinproc");
     alloc_assert (self);
 
-    nn_ins_item_init (&self->item, &nn_cinproc_vfptr, hint);
+    nn_ep_tran_setup (ep, &nn_cinproc_vfptr, self);
+
+    nn_ins_item_init (&self->item, ep);
     nn_fsm_init_root (&self->fsm, nn_cinproc_handler, nn_cinproc_shutdown,
-        nn_epbase_getctx (&self->item.epbase));
+        nn_ep_getctx (ep));
     self->state = NN_CINPROC_STATE_IDLE;
     nn_list_init (&self->sinprocs);
 
-    nn_epbase_stat_increment (&self->item.epbase,
-        NN_STAT_INPROGRESS_CONNECTIONS, 1);
+    nn_ep_stat_increment (ep, NN_STAT_INPROGRESS_CONNECTIONS, 1);
 
     /*  Start the state machine. */
     nn_fsm_start (&self->fsm);
@@ -78,24 +80,23 @@
     /*  Register the inproc endpoint into a global repository. */
     nn_ins_connect (&self->item, nn_cinproc_connect);
 
-    *epbase = &self->item.epbase;
     return 0;
 }
 
-static void nn_cinproc_stop (struct nn_epbase *self)
+static void nn_cinproc_stop (struct nn_ep *ep)
 {
     struct nn_cinproc *cinproc;
 
-    cinproc = nn_cont (self, struct nn_cinproc, item.epbase);
+    cinproc = nn_ep_tran_private (ep);
 
     nn_fsm_stop (&cinproc->fsm);
 }
 
-static void nn_cinproc_destroy (struct nn_epbase *self)
+static void nn_cinproc_destroy (struct nn_ep *ep)
 {
     struct nn_cinproc *cinproc;
 
-    cinproc = nn_cont (self, struct nn_cinproc, item.epbase);
+    cinproc = nn_ep_tran_private (ep);
 
     nn_list_term (&cinproc->sinprocs);
     nn_fsm_term (&cinproc->fsm);
@@ -119,17 +120,15 @@
     sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc");
     alloc_assert (sinproc);
     nn_sinproc_init (sinproc, NN_CINPROC_SRC_SINPROC,
-        &cinproc->item.epbase, &cinproc->fsm);
+        cinproc->item.ep, &cinproc->fsm);
 
     nn_list_insert (&cinproc->sinprocs, &sinproc->item,
         nn_list_end (&cinproc->sinprocs));
 
     nn_sinproc_connect (sinproc, &binproc->fsm);
 
-    nn_epbase_stat_increment (&cinproc->item.epbase,
-        NN_STAT_INPROGRESS_CONNECTIONS, -1);
-    nn_epbase_stat_increment (&cinproc->item.epbase,
-        NN_STAT_ESTABLISHED_CONNECTIONS, 1);
+    nn_ep_stat_increment (cinproc->item.ep, NN_STAT_INPROGRESS_CONNECTIONS, -1);
+    nn_ep_stat_increment (cinproc->item.ep, NN_STAT_ESTABLISHED_CONNECTIONS, 1);
 }
 
 static void nn_cinproc_shutdown (struct nn_fsm *self, int src, int type,
@@ -141,7 +140,7 @@
 
     cinproc = nn_cont (self, struct nn_cinproc, fsm);
 
-    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
+    if (src == NN_FSM_ACTION && type == NN_FSM_STOP) {
 
         /*  First, unregister the endpoint from the global repository of inproc
             endpoints. This way, new connections cannot be created anymore. */
@@ -157,7 +156,7 @@
         cinproc->state = NN_CINPROC_STATE_STOPPING;
         goto finish;
     }
-    if (nn_slow (cinproc->state == NN_CINPROC_STATE_STOPPING)) {
+    if (cinproc->state == NN_CINPROC_STATE_STOPPING) {
         sinproc = (struct nn_sinproc *) srcptr;
         nn_list_erase (&cinproc->sinprocs, &sinproc->item);
         nn_sinproc_term (sinproc);
@@ -168,7 +167,7 @@
             return;
         cinproc->state = NN_CINPROC_STATE_IDLE;
         nn_fsm_stopped_noevent (&cinproc->fsm);
-        nn_epbase_stopped (&cinproc->item.epbase);
+        nn_ep_stopped (cinproc->item.ep);
         return;
     }
 
@@ -219,13 +218,13 @@
                 sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc");
                 alloc_assert (sinproc);
                 nn_sinproc_init (sinproc, NN_CINPROC_SRC_SINPROC,
-                    &cinproc->item.epbase, &cinproc->fsm);
+                    cinproc->item.ep, &cinproc->fsm);
                 nn_list_insert (&cinproc->sinprocs, &sinproc->item,
                     nn_list_end (&cinproc->sinprocs));
                 nn_sinproc_accept (sinproc, peer);
-                nn_epbase_stat_increment (&cinproc->item.epbase,
+                nn_ep_stat_increment (cinproc->item.ep,
                     NN_STAT_INPROGRESS_CONNECTIONS, -1);
-                nn_epbase_stat_increment (&cinproc->item.epbase,
+                nn_ep_stat_increment (cinproc->item.ep,
                     NN_STAT_ESTABLISHED_CONNECTIONS, 1);
                 return;
             default:
@@ -235,7 +234,7 @@
         case NN_CINPROC_SRC_SINPROC:
             switch (type) {
             case NN_SINPROC_DISCONNECT:
-                nn_epbase_stat_increment (&cinproc->item.epbase,
+                nn_ep_stat_increment (cinproc->item.ep,
                     NN_STAT_INPROGRESS_CONNECTIONS, 1);
                 return;
             }
@@ -252,4 +251,3 @@
         nn_fsm_bad_state (cinproc->state, src, type);
     }
 }
-
diff --git a/src/transports/inproc/cinproc.h b/src/transports/inproc/cinproc.h
index 8a6355e..c5d7c0b 100644
--- a/src/transports/inproc/cinproc.h
+++ b/src/transports/inproc/cinproc.h
@@ -46,7 +46,7 @@
     struct nn_list sinprocs;
 };
 
-int nn_cinproc_create (void *hint, struct nn_epbase **epbase);
+int nn_cinproc_create (struct nn_ep *);
 
 #endif
 
diff --git a/src/transports/inproc/inproc.c b/src/transports/inproc/inproc.c
index 9f994f5..a77f8fa 100644
--- a/src/transports/inproc/inproc.c
+++ b/src/transports/inproc/inproc.c
@@ -33,8 +33,8 @@
 /*  nn_transport interface. */
 static void nn_inproc_init (void);
 static void nn_inproc_term (void);
-static int nn_inproc_bind (void *hint, struct nn_epbase **epbase);
-static int nn_inproc_connect (void *hint, struct nn_epbase **epbase);
+static int nn_inproc_bind (struct nn_ep *);
+static int nn_inproc_connect (struct nn_ep *);
 
 static struct nn_transport nn_inproc_vfptr = {
     "inproc",
@@ -59,13 +59,13 @@
     nn_ins_term ();
 }
 
-static int nn_inproc_bind (void *hint, struct nn_epbase **epbase)
+static int nn_inproc_bind (struct nn_ep *ep)
 {
-    return nn_binproc_create (hint, epbase);
+    return nn_binproc_create (ep);
 }
 
-static int nn_inproc_connect (void *hint, struct nn_epbase **epbase)
+static int nn_inproc_connect (struct nn_ep *ep)
 {
-    return nn_cinproc_create (hint, epbase);
+    return nn_cinproc_create (ep);
 }
 
diff --git a/src/transports/inproc/ins.c b/src/transports/inproc/ins.c
index b8e08eb..2bd39fe 100644
--- a/src/transports/inproc/ins.c
+++ b/src/transports/inproc/ins.c
@@ -48,23 +48,15 @@
     inproc endpoints in the current process. */
 static struct nn_ins self;
 
-void nn_ins_item_init (struct nn_ins_item *self,
-    const struct nn_epbase_vfptr *vfptr, void *hint)
+void nn_ins_item_init (struct nn_ins_item *self, struct nn_ep *ep)
 {
-    size_t sz;
-
-    nn_epbase_init (&self->epbase, vfptr, hint);
+    self->ep = ep;
     nn_list_item_init (&self->item);
-    sz = sizeof (self->protocol);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_PROTOCOL,
-        &self->protocol, &sz);
-    nn_assert (sz == sizeof (self->protocol));
 }
 
 void nn_ins_item_term (struct nn_ins_item *self)
 {
     nn_list_item_term (&self->item);
-    nn_epbase_term (&self->epbase);
 }
 
 void nn_ins_init (void)
@@ -93,8 +85,10 @@
     for (it = nn_list_begin (&self.bound); it != nn_list_end (&self.bound);
           it = nn_list_next (&self.bound, it)) {
         bitem = nn_cont (it, struct nn_ins_item, item);
-        if (strncmp (nn_epbase_getaddr (&item->epbase),
-              nn_epbase_getaddr (&bitem->epbase), NN_SOCKADDR_MAX) == 0) {
+
+        if (strncmp (nn_ep_getaddr(bitem->ep), nn_ep_getaddr(item->ep),
+            NN_SOCKADDR_MAX) == 0) {
+
             nn_mutex_unlock (&self.sync);
             return -EADDRINUSE;
         }
@@ -109,11 +103,11 @@
           it != nn_list_end (&self.connected);
           it = nn_list_next (&self.connected, it)) {
         citem = nn_cont (it, struct nn_ins_item, item);
-        if (strncmp (nn_epbase_getaddr (&item->epbase),
-              nn_epbase_getaddr (&citem->epbase), NN_SOCKADDR_MAX) == 0) {
+        if (strncmp (nn_ep_getaddr(item->ep), nn_ep_getaddr(citem->ep),
+            NN_SOCKADDR_MAX) == 0) {
 
             /*  Check whether the two sockets are compatible. */
-            if (!nn_epbase_ispeer (&item->epbase, citem->protocol))
+            if (!nn_ep_ispeer_ep (item->ep, citem->ep))
                 continue;
 
             fn (item, citem);
@@ -141,11 +135,12 @@
           it != nn_list_end (&self.bound);
           it = nn_list_next (&self.bound, it)) {
         bitem = nn_cont (it, struct nn_ins_item, item);
-        if (strncmp (nn_epbase_getaddr (&item->epbase),
-              nn_epbase_getaddr (&bitem->epbase), NN_SOCKADDR_MAX) == 0) {
+
+        if (strncmp (nn_ep_getaddr(item->ep), nn_ep_getaddr(bitem->ep),
+            NN_SOCKADDR_MAX) == 0) {
 
             /*  Check whether the two sockets are compatible. */
-            if (!nn_epbase_ispeer (&item->epbase, bitem->protocol))
+            if (!nn_ep_ispeer_ep (item->ep, bitem->ep))
                 break;
 
             /*  Call back to cinproc to create actual connection. */
diff --git a/src/transports/inproc/ins.h b/src/transports/inproc/ins.h
index 04034fb..99b76fd 100644
--- a/src/transports/inproc/ins.h
+++ b/src/transports/inproc/ins.h
@@ -31,19 +31,17 @@
 
 struct nn_ins_item {
 
-    /*  Every ins_item is an endpoint. */
-    struct nn_epbase epbase;
-
     /*  Every ins_item is either in the list of bound or connected endpoints. */
     struct nn_list_item item;
 
+    struct nn_ep *ep;
+
     /*  This is the local cache of the endpoint's protocol ID. This way we can
         check the value without actually locking the object. */
     int protocol;
 };
 
-void nn_ins_item_init (struct nn_ins_item *self,
-    const struct nn_epbase_vfptr *vfptr, void *hint);
+void nn_ins_item_init (struct nn_ins_item *self, struct nn_ep *ep);
 void nn_ins_item_term (struct nn_ins_item *self);
 
 void nn_ins_init (void);
diff --git a/src/transports/inproc/sinproc.c b/src/transports/inproc/sinproc.c
index 546e299..314d827 100644
--- a/src/transports/inproc/sinproc.c
+++ b/src/transports/inproc/sinproc.c
@@ -63,7 +63,7 @@
 };
 
 void nn_sinproc_init (struct nn_sinproc *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner)
+    struct nn_ep *ep, struct nn_fsm *owner)
 {
     int rcvbuf;
     size_t sz;
@@ -73,9 +73,9 @@
     self->state = NN_SINPROC_STATE_IDLE;
     self->flags = 0;
     self->peer = NULL;
-    nn_pipebase_init (&self->pipebase, &nn_sinproc_pipebase_vfptr, epbase);
+    nn_pipebase_init (&self->pipebase, &nn_sinproc_pipebase_vfptr, ep);
     sz = sizeof (rcvbuf);
-    nn_epbase_getopt (epbase, NN_SOL_SOCKET, NN_RCVBUF, &rcvbuf, &sz);
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RCVBUF, &rcvbuf, &sz);
     nn_assert (sz == sizeof (rcvbuf));
     nn_msgqueue_init (&self->msgqueue, rcvbuf);
     nn_msg_init (&self->msg, 0);
diff --git a/src/transports/inproc/sinproc.h b/src/transports/inproc/sinproc.h
index 07b51ad..ed6367f 100644
--- a/src/transports/inproc/sinproc.h
+++ b/src/transports/inproc/sinproc.h
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -82,7 +83,7 @@
 };
 
 void nn_sinproc_init (struct nn_sinproc *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner);
+    struct nn_ep *ep, struct nn_fsm *owner);
 void nn_sinproc_term (struct nn_sinproc *self);
 int nn_sinproc_isidle (struct nn_sinproc *self);
 
diff --git a/src/transports/ipc/aipc.c b/src/transports/ipc/aipc.c
index bc64a4e..8889af2 100644
--- a/src/transports/ipc/aipc.c
+++ b/src/transports/ipc/aipc.c
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2012-2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -46,17 +47,17 @@
    void *srcptr);
 
 void nn_aipc_init (struct nn_aipc *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner)
+    struct nn_ep *ep, struct nn_fsm *owner)
 {
     nn_fsm_init (&self->fsm, nn_aipc_handler, nn_aipc_shutdown,
         src, self, owner);
     self->state = NN_AIPC_STATE_IDLE;
-    self->epbase = epbase;
+    self->ep = ep;
     nn_usock_init (&self->usock, NN_AIPC_SRC_USOCK, &self->fsm);
     self->listener = NULL;
     self->listener_owner.src = -1;
     self->listener_owner.fsm = NULL;
-    nn_sipc_init (&self->sipc, NN_AIPC_SRC_SIPC, epbase, &self->fsm);
+    nn_sipc_init (&self->sipc, NN_AIPC_SRC_SIPC, ep, &self->fsm);
     nn_fsm_event_init (&self->accepted);
     nn_fsm_event_init (&self->done);
     nn_list_item_init (&self->item);
@@ -94,9 +95,9 @@
 
 #if defined NN_HAVE_WINDOWS
     /* Get/Set security attribute pointer*/
-    nn_epbase_getopt (self->epbase, NN_IPC, NN_IPC_SEC_ATTR, &self->usock.sec_attr, &sz);
-    nn_epbase_getopt (self->epbase, NN_IPC, NN_IPC_OUTBUFSZ, &self->usock.outbuffersz, &sz);
-    nn_epbase_getopt (self->epbase, NN_IPC, NN_IPC_INBUFSZ, &self->usock.inbuffersz, &sz);
+    nn_ep_getopt (self->ep, NN_IPC, NN_IPC_SEC_ATTR, &self->usock.sec_attr, &sz);
+    nn_ep_getopt (self->ep, NN_IPC, NN_IPC_OUTBUFSZ, &self->usock.outbuffersz, &sz);
+    nn_ep_getopt (self->ep, NN_IPC, NN_IPC_INBUFSZ, &self->usock.inbuffersz, &sz);
 #endif
 
     /*  Start the state machine. */
@@ -117,8 +118,7 @@
 
     if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
         if (!nn_sipc_isidle (&aipc->sipc)) {
-            nn_epbase_stat_increment (aipc->epbase,
-                NN_STAT_DROPPED_CONNECTIONS, 1);
+            nn_ep_stat_increment (aipc->ep, NN_STAT_DROPPED_CONNECTIONS, 1);
             nn_sipc_stop (&aipc->sipc);
         }
         aipc->state = NN_AIPC_STATE_STOPPING_SIPC_FINAL;
@@ -189,18 +189,16 @@
         case NN_AIPC_SRC_USOCK:
             switch (type) {
             case NN_USOCK_ACCEPTED:
-                nn_epbase_clear_error (aipc->epbase);
+                nn_ep_clear_error (aipc->ep);
 
                 /*  Set the relevant socket options. */
                 sz = sizeof (val);
-                nn_epbase_getopt (aipc->epbase, NN_SOL_SOCKET, NN_SNDBUF,
-                    &val, &sz);
+                nn_ep_getopt (aipc->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
                 nn_assert (sz == sizeof (val));
                 nn_usock_setsockopt (&aipc->usock, SOL_SOCKET, SO_SNDBUF,
                     &val, sizeof (val));
                 sz = sizeof (val);
-                nn_epbase_getopt (aipc->epbase, NN_SOL_SOCKET, NN_RCVBUF,
-                    &val, &sz);
+                nn_ep_getopt (aipc->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
                 nn_assert (sz == sizeof (val));
                 nn_usock_setsockopt (&aipc->usock, SOL_SOCKET, SO_RCVBUF,
                     &val, sizeof (val));
@@ -217,7 +215,7 @@
                 nn_sipc_start (&aipc->sipc, &aipc->usock);
                 aipc->state = NN_AIPC_STATE_ACTIVE;
 
-                nn_epbase_stat_increment (aipc->epbase,
+                nn_ep_stat_increment (aipc->ep,
                     NN_STAT_ACCEPTED_CONNECTIONS, 1);
 
                 return;
@@ -229,10 +227,8 @@
         case NN_AIPC_SRC_LISTENER:
             switch (type) {
             case NN_USOCK_ACCEPT_ERROR:
-                nn_epbase_set_error (aipc->epbase,
-                    nn_usock_geterrno (aipc->listener));
-                nn_epbase_stat_increment (aipc->epbase,
-                    NN_STAT_ACCEPT_ERRORS, 1);
+                nn_ep_set_error (aipc->ep, nn_usock_geterrno (aipc->listener));
+                nn_ep_stat_increment (aipc->ep, NN_STAT_ACCEPT_ERRORS, 1);
                 nn_usock_accept (&aipc->usock, aipc->listener);
 
                 return;
@@ -256,8 +252,7 @@
             case NN_SIPC_ERROR:
                 nn_sipc_stop (&aipc->sipc);
                 aipc->state = NN_AIPC_STATE_STOPPING_SIPC;
-                nn_epbase_stat_increment (aipc->epbase,
-                    NN_STAT_BROKEN_CONNECTIONS, 1);
+                nn_ep_stat_increment (aipc->ep, NN_STAT_BROKEN_CONNECTIONS, 1);
                 return;
             default:
                 nn_fsm_bad_action (aipc->state, src, type);
diff --git a/src/transports/ipc/aipc.h b/src/transports/ipc/aipc.h
index 2c95a7f..e9d7c72 100644
--- a/src/transports/ipc/aipc.h
+++ b/src/transports/ipc/aipc.h
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -49,7 +50,7 @@
     int state;
 
     /*  Pointer to the associated endpoint. */
-    struct nn_epbase *epbase;
+    struct nn_ep *ep;
 
     /*  Underlying socket. */
     struct nn_usock usock;
@@ -70,7 +71,7 @@
 };
 
 void nn_aipc_init (struct nn_aipc *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner);
+    struct nn_ep *ep, struct nn_fsm *owner);
 void nn_aipc_term (struct nn_aipc *self);
 
 int nn_aipc_isidle (struct nn_aipc *self);
@@ -78,4 +79,3 @@
 void nn_aipc_stop (struct nn_aipc *self);
 
 #endif
-
diff --git a/src/transports/ipc/bipc.c b/src/transports/ipc/bipc.c
index f1b3a2a..4b729ab 100644
--- a/src/transports/ipc/bipc.c
+++ b/src/transports/ipc/bipc.c
@@ -60,9 +60,7 @@
     struct nn_fsm fsm;
     int state;
 
-    /*  This object is a specific type of endpoint.
-        Thus it is derived from epbase. */
-    struct nn_epbase epbase;
+    struct nn_ep *ep;
 
     /*  The underlying listening IPC socket. */
     struct nn_usock usock;
@@ -74,10 +72,10 @@
     struct nn_list aipcs;
 };
 
-/*  nn_epbase virtual interface implementation. */
-static void nn_bipc_stop (struct nn_epbase *self);
-static void nn_bipc_destroy (struct nn_epbase *self);
-const struct nn_epbase_vfptr nn_bipc_epbase_vfptr = {
+/*  nn_ep virtual interface implementation. */
+static void nn_bipc_stop (struct nn_ep *self);
+static void nn_bipc_destroy (struct nn_ep *self);
+const struct nn_ep_vfptr nn_bipc_ep_vfptr = {
     nn_bipc_stop,
     nn_bipc_destroy
 };
@@ -90,7 +88,7 @@
 static int nn_bipc_listen (struct nn_bipc *self);
 static void nn_bipc_start_accepting (struct nn_bipc *self);
 
-int nn_bipc_create (void *hint, struct nn_epbase **epbase)
+int nn_bipc_create (struct nn_ep *ep)
 {
     struct nn_bipc *self;
     int rc;
@@ -101,9 +99,10 @@
 
 
     /*  Initialise the structure. */
-    nn_epbase_init (&self->epbase, &nn_bipc_epbase_vfptr, hint);
+    nn_ep_tran_setup (ep, &nn_bipc_ep_vfptr, self);
+    self->ep = ep;
     nn_fsm_init_root (&self->fsm, nn_bipc_handler, nn_bipc_shutdown,
-        nn_epbase_getctx (&self->epbase));
+        nn_ep_getctx (ep));
     self->state = NN_BIPC_STATE_IDLE;
     self->aipc = NULL;
     nn_list_init (&self->aipcs);
@@ -115,36 +114,31 @@
 
     rc = nn_bipc_listen (self);
     if (rc != 0) {
-        nn_epbase_term (&self->epbase);
         return rc;
     }
 
-    /*  Return the base class as an out parameter. */
-    *epbase = &self->epbase;
-
     return 0;
 }
 
-static void nn_bipc_stop (struct nn_epbase *self)
+static void nn_bipc_stop (struct nn_ep *ep)
 {
     struct nn_bipc *bipc;
 
-    bipc = nn_cont (self, struct nn_bipc, epbase);
+    bipc = nn_ep_tran_private (ep);
 
     nn_fsm_stop (&bipc->fsm);
 }
 
-static void nn_bipc_destroy (struct nn_epbase *self)
+static void nn_bipc_destroy (struct nn_ep *ep)
 {
     struct nn_bipc *bipc;
 
-    bipc = nn_cont (self, struct nn_bipc, epbase);
+    bipc = nn_ep_tran_private (ep);
 
     nn_assert_state (bipc, NN_BIPC_STATE_IDLE);
     nn_list_term (&bipc->aipcs);
     nn_assert (bipc->aipc == NULL);
     nn_usock_term (&bipc->usock);
-    nn_epbase_term (&bipc->epbase);
     nn_fsm_term (&bipc->fsm);
 
     nn_free (bipc);
@@ -182,7 +176,7 @@
 
         /* On *nixes, unlink the domain socket file */
 #if defined NN_HAVE_UNIX_SOCKETS
-        addr = nn_epbase_getaddr (&bipc->epbase);
+        addr = nn_ep_getaddr (bipc->ep);
         rc = unlink(addr);
         errno_assert (rc == 0 || errno == ENOENT);
 #endif
@@ -215,7 +209,7 @@
         if (nn_list_empty (&bipc->aipcs)) {
             bipc->state = NN_BIPC_STATE_IDLE;
             nn_fsm_stopped_noevent (&bipc->fsm);
-            nn_epbase_stopped (&bipc->epbase);
+            nn_ep_stopped (bipc->ep);
             return;
         }
 
@@ -296,7 +290,7 @@
 #endif
 
     /*  First, create the AF_UNIX address. */
-    addr = nn_epbase_getaddr (&self->epbase);
+    addr = nn_ep_getaddr (self->ep);
     memset (&ss, 0, sizeof (ss));
     un = (struct sockaddr_un*) &ss;
     nn_assert (strlen (addr) < sizeof (un->sun_path));
@@ -357,7 +351,7 @@
     /*  Allocate new aipc state machine. */
     self->aipc = nn_alloc (sizeof (struct nn_aipc), "aipc");
     alloc_assert (self->aipc);
-    nn_aipc_init (self->aipc, NN_BIPC_SRC_AIPC, &self->epbase, &self->fsm);
+    nn_aipc_init (self->aipc, NN_BIPC_SRC_AIPC, self->ep, &self->fsm);
 
     /*  Start waiting for a new incoming connection. */
     nn_aipc_start (self->aipc, &self->usock);
diff --git a/src/transports/ipc/bipc.h b/src/transports/ipc/bipc.h
index ca43bd5..b7c3f69 100644
--- a/src/transports/ipc/bipc.h
+++ b/src/transports/ipc/bipc.h
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -27,6 +28,6 @@
 
 /*  State machine managing bound IPC socket. */
 
-int nn_bipc_create (void *hint, struct nn_epbase **epbase);
+int nn_bipc_create (struct nn_ep *);
 
 #endif
diff --git a/src/transports/ipc/cipc.c b/src/transports/ipc/cipc.c
index 1f6adad..844cf94 100644
--- a/src/transports/ipc/cipc.c
+++ b/src/transports/ipc/cipc.c
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2012-2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -62,9 +63,7 @@
     struct nn_fsm fsm;
     int state;
 
-    /*  This object is a specific type of endpoint.
-        Thus it is derived from epbase. */
-    struct nn_epbase epbase;
+    struct nn_ep *ep;
 
     /*  The underlying IPC socket. */
     struct nn_usock usock;
@@ -77,10 +76,10 @@
     struct nn_sipc sipc;
 };
 
-/*  nn_epbase virtual interface implementation. */
-static void nn_cipc_stop (struct nn_epbase *self);
-static void nn_cipc_destroy (struct nn_epbase *self);
-const struct nn_epbase_vfptr nn_cipc_epbase_vfptr = {
+/*  nn_ep virtual interface implementation. */
+static void nn_cipc_stop (struct nn_ep *ep);
+static void nn_cipc_destroy (struct nn_ep *ep);
+const struct nn_ep_vfptr nn_cipc_ep_vfptr = {
     nn_cipc_stop,
     nn_cipc_destroy
 };
@@ -92,7 +91,7 @@
     void *srcptr);
 static void nn_cipc_start_connecting (struct nn_cipc *self);
 
-int nn_cipc_create (void *hint, struct nn_epbase **epbase)
+int nn_cipc_create (struct nn_ep *ep)
 {
     struct nn_cipc *self;
     int reconnect_ivl;
@@ -104,54 +103,50 @@
     alloc_assert (self);
 
     /*  Initialise the structure. */
-    nn_epbase_init (&self->epbase, &nn_cipc_epbase_vfptr, hint);
+    self->ep = ep;
+    nn_ep_tran_setup (ep, &nn_cipc_ep_vfptr, self);
     nn_fsm_init_root (&self->fsm, nn_cipc_handler, nn_cipc_shutdown,
-        nn_epbase_getctx (&self->epbase));
+        nn_ep_getctx (ep));
     self->state = NN_CIPC_STATE_IDLE;
     nn_usock_init (&self->usock, NN_CIPC_SRC_USOCK, &self->fsm);
     sz = sizeof (reconnect_ivl);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
-        &reconnect_ivl, &sz);
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL, &reconnect_ivl, &sz);
     nn_assert (sz == sizeof (reconnect_ivl));
     sz = sizeof (reconnect_ivl_max);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
         &reconnect_ivl_max, &sz);
     nn_assert (sz == sizeof (reconnect_ivl_max));
     if (reconnect_ivl_max == 0)
         reconnect_ivl_max = reconnect_ivl;
     nn_backoff_init (&self->retry, NN_CIPC_SRC_RECONNECT_TIMER,
         reconnect_ivl, reconnect_ivl_max, &self->fsm);
-    nn_sipc_init (&self->sipc, NN_CIPC_SRC_SIPC, &self->epbase, &self->fsm);
+    nn_sipc_init (&self->sipc, NN_CIPC_SRC_SIPC, ep, &self->fsm);
 
     /*  Start the state machine. */
     nn_fsm_start (&self->fsm);
 
-    /*  Return the base class as an out parameter. */
-    *epbase = &self->epbase;
-
     return 0;
 }
 
-static void nn_cipc_stop (struct nn_epbase *self)
+static void nn_cipc_stop (struct nn_ep *ep)
 {
     struct nn_cipc *cipc;
 
-    cipc = nn_cont (self, struct nn_cipc, epbase);
+    cipc = nn_ep_tran_private (ep);
 
     nn_fsm_stop (&cipc->fsm);
 }
 
-static void nn_cipc_destroy (struct nn_epbase *self)
+static void nn_cipc_destroy (struct nn_ep *ep)
 {
     struct nn_cipc *cipc;
 
-    cipc = nn_cont (self, struct nn_cipc, epbase);
+    cipc = nn_ep_tran_private (ep);
 
     nn_sipc_term (&cipc->sipc);
     nn_backoff_term (&cipc->retry);
     nn_usock_term (&cipc->usock);
     nn_fsm_term (&cipc->fsm);
-    nn_epbase_term (&cipc->epbase);
 
     nn_free (cipc);
 }
@@ -165,8 +160,7 @@
 
     if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
         if (!nn_sipc_isidle (&cipc->sipc)) {
-            nn_epbase_stat_increment (&cipc->epbase,
-                NN_STAT_DROPPED_CONNECTIONS, 1);
+            nn_ep_stat_increment (cipc->ep, NN_STAT_DROPPED_CONNECTIONS, 1);
             nn_sipc_stop (&cipc->sipc);
         }
         cipc->state = NN_CIPC_STATE_STOPPING_SIPC_FINAL;
@@ -184,7 +178,7 @@
             return;
         cipc->state = NN_CIPC_STATE_IDLE;
         nn_fsm_stopped_noevent (&cipc->fsm);
-        nn_epbase_stopped (&cipc->epbase);
+        nn_ep_stopped (cipc->ep);
         return;
     }
 
@@ -232,21 +226,19 @@
             case NN_USOCK_CONNECTED:
                 nn_sipc_start (&cipc->sipc, &cipc->usock);
                 cipc->state = NN_CIPC_STATE_ACTIVE;
-                nn_epbase_stat_increment (&cipc->epbase,
+                nn_ep_stat_increment (cipc->ep,
                     NN_STAT_INPROGRESS_CONNECTIONS, -1);
-                nn_epbase_stat_increment (&cipc->epbase,
+                nn_ep_stat_increment (cipc->ep,
                     NN_STAT_ESTABLISHED_CONNECTIONS, 1);
-                nn_epbase_clear_error (&cipc->epbase);
+                nn_ep_clear_error (cipc->ep);
                 return;
             case NN_USOCK_ERROR:
-                nn_epbase_set_error (&cipc->epbase,
-                    nn_usock_geterrno (&cipc->usock));
+                nn_ep_set_error (cipc->ep, nn_usock_geterrno (&cipc->usock));
                 nn_usock_stop (&cipc->usock);
                 cipc->state = NN_CIPC_STATE_STOPPING_USOCK;
-                nn_epbase_stat_increment (&cipc->epbase,
+                nn_ep_stat_increment (cipc->ep,
                     NN_STAT_INPROGRESS_CONNECTIONS, -1);
-                nn_epbase_stat_increment (&cipc->epbase,
-                    NN_STAT_CONNECT_ERRORS, 1);
+                nn_ep_stat_increment (cipc->ep, NN_STAT_CONNECT_ERRORS, 1);
                 return;
             default:
                 nn_fsm_bad_action (cipc->state, src, type);
@@ -268,8 +260,7 @@
             case NN_SIPC_ERROR:
                 nn_sipc_stop (&cipc->sipc);
                 cipc->state = NN_CIPC_STATE_STOPPING_SIPC;
-                nn_epbase_stat_increment (&cipc->epbase,
-                    NN_STAT_BROKEN_CONNECTIONS, 1);
+                nn_ep_stat_increment (cipc->ep, NN_STAT_BROKEN_CONNECTIONS, 1);
                 return;
             default:
                nn_fsm_bad_action (cipc->state, src, type);
@@ -398,18 +389,18 @@
 
     /*  Set the relevant socket options. */
     sz = sizeof (val);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
     nn_assert (sz == sizeof (val));
     nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF,
         &val, sizeof (val));
     sz = sizeof (val);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
     nn_assert (sz == sizeof (val));
     nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF,
         &val, sizeof (val));
 
     /*  Create the IPC address from the address string. */
-    addr = nn_epbase_getaddr (&self->epbase);
+    addr = nn_ep_getaddr (self->ep);
     memset (&ss, 0, sizeof (ss));
     un = (struct sockaddr_un*) &ss;
     nn_assert (strlen (addr) < sizeof (un->sun_path));
@@ -418,10 +409,10 @@
 
 #if defined NN_HAVE_WINDOWS
     /* Get/Set security attribute pointer*/
-    nn_epbase_getopt (&self->epbase, NN_IPC, NN_IPC_SEC_ATTR, &self->usock.sec_attr, &sz);
+    nn_ep_getopt (self->ep, NN_IPC, NN_IPC_SEC_ATTR, &self->usock.sec_attr, &sz);
 
-    nn_epbase_getopt (&self->epbase, NN_IPC, NN_IPC_OUTBUFSZ, &self->usock.outbuffersz, &sz);
-    nn_epbase_getopt (&self->epbase, NN_IPC, NN_IPC_INBUFSZ, &self->usock.inbuffersz, &sz);
+    nn_ep_getopt (self->ep, NN_IPC, NN_IPC_OUTBUFSZ, &self->usock.outbuffersz, &sz);
+    nn_ep_getopt (self->ep, NN_IPC, NN_IPC_INBUFSZ, &self->usock.inbuffersz, &sz);
 #endif
 
     /*  Start connecting. */
@@ -429,7 +420,5 @@
         sizeof (struct sockaddr_un));
     self->state  = NN_CIPC_STATE_CONNECTING;
 
-    nn_epbase_stat_increment (&self->epbase,
-        NN_STAT_INPROGRESS_CONNECTIONS, 1);
+    nn_ep_stat_increment (self->ep, NN_STAT_INPROGRESS_CONNECTIONS, 1);
 }
-
diff --git a/src/transports/ipc/cipc.h b/src/transports/ipc/cipc.h
index 4036bba..c66db06 100644
--- a/src/transports/ipc/cipc.h
+++ b/src/transports/ipc/cipc.h
@@ -28,6 +28,6 @@
 
 /*  State machine managing connected IPC socket. */
 
-int nn_cipc_create (void *hint, struct nn_epbase **epbase);
+int nn_cipc_create (struct nn_ep *ep);
 
 #endif
diff --git a/src/transports/ipc/ipc.c b/src/transports/ipc/ipc.c
index c4fe740..5f23722 100644
--- a/src/transports/ipc/ipc.c
+++ b/src/transports/ipc/ipc.c
@@ -1,6 +1,7 @@
 /*
     Copyright (c) 2012-2013 Martin Sustrik  All rights reserved.
     Copyright (c) 2013 GoPivotal, Inc.  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -65,8 +66,8 @@
 };
 
 /*  nn_transport interface. */
-static int nn_ipc_bind (void *hint, struct nn_epbase **epbase);
-static int nn_ipc_connect (void *hint, struct nn_epbase **epbase);
+static int nn_ipc_bind (struct nn_ep *ep);
+static int nn_ipc_connect (struct nn_ep *ep);
 static struct nn_optset *nn_ipc_optset (void);
 
 static struct nn_transport nn_ipc_vfptr = {
@@ -82,14 +83,14 @@
 
 struct nn_transport *nn_ipc = &nn_ipc_vfptr;
 
-static int nn_ipc_bind (void *hint, struct nn_epbase **epbase)
+static int nn_ipc_bind (struct nn_ep *ep)
 {
-    return nn_bipc_create (hint, epbase);
+    return nn_bipc_create (ep);
 }
 
-static int nn_ipc_connect (void *hint, struct nn_epbase **epbase)
+static int nn_ipc_connect (struct nn_ep *ep)
 {
-    return nn_cipc_create (hint, epbase);
+    return nn_cipc_create (ep);
 }
 
 static struct nn_optset *nn_ipc_optset ()
diff --git a/src/transports/ipc/sipc.c b/src/transports/ipc/sipc.c
index 8375d49..204dc7a 100644
--- a/src/transports/ipc/sipc.c
+++ b/src/transports/ipc/sipc.c
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -69,7 +70,7 @@
     void *srcptr);
 
 void nn_sipc_init (struct nn_sipc *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner)
+    struct nn_ep *ep, struct nn_fsm *owner)
 {
     nn_fsm_init (&self->fsm, nn_sipc_handler, nn_sipc_shutdown,
         src, self, owner);
@@ -78,7 +79,7 @@
     self->usock = NULL;
     self->usock_owner.src = -1;
     self->usock_owner.fsm = NULL;
-    nn_pipebase_init (&self->pipebase, &nn_sipc_pipebase_vfptr, epbase);
+    nn_pipebase_init (&self->pipebase, &nn_sipc_pipebase_vfptr, ep);
     self->instate = -1;
     nn_msg_init (&self->inmsg, 0);
     self->outstate = -1;
diff --git a/src/transports/ipc/sipc.h b/src/transports/ipc/sipc.h
index eaf1e2b..7102c89 100644
--- a/src/transports/ipc/sipc.h
+++ b/src/transports/ipc/sipc.h
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -79,7 +80,7 @@
 };
 
 void nn_sipc_init (struct nn_sipc *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner);
+    struct nn_ep *ep, struct nn_fsm *owner);
 void nn_sipc_term (struct nn_sipc *self);
 
 int nn_sipc_isidle (struct nn_sipc *self);
diff --git a/src/transports/tcp/atcp.c b/src/transports/tcp/atcp.c
index e94be8f..60d75ef 100644
--- a/src/transports/tcp/atcp.c
+++ b/src/transports/tcp/atcp.c
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2012-2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -46,17 +47,17 @@
     void *srcptr);
 
 void nn_atcp_init (struct nn_atcp *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner)
+    struct nn_ep *ep, struct nn_fsm *owner)
 {
     nn_fsm_init (&self->fsm, nn_atcp_handler, nn_atcp_shutdown,
         src, self, owner);
     self->state = NN_ATCP_STATE_IDLE;
-    self->epbase = epbase;
+    self->ep = ep;
     nn_usock_init (&self->usock, NN_ATCP_SRC_USOCK, &self->fsm);
     self->listener = NULL;
     self->listener_owner.src = -1;
     self->listener_owner.fsm = NULL;
-    nn_stcp_init (&self->stcp, NN_ATCP_SRC_STCP, epbase, &self->fsm);
+    nn_stcp_init (&self->stcp, NN_ATCP_SRC_STCP, ep, &self->fsm);
     nn_fsm_event_init (&self->accepted);
     nn_fsm_event_init (&self->done);
     nn_list_item_init (&self->item);
@@ -107,8 +108,7 @@
 
     if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
         if (!nn_stcp_isidle (&atcp->stcp)) {
-            nn_epbase_stat_increment (atcp->epbase,
-                NN_STAT_DROPPED_CONNECTIONS, 1);
+            nn_ep_stat_increment (atcp->ep, NN_STAT_DROPPED_CONNECTIONS, 1);
             nn_stcp_stop (&atcp->stcp);
         }
         atcp->state = NN_ATCP_STATE_STOPPING_STCP_FINAL;
@@ -179,18 +179,16 @@
         case NN_ATCP_SRC_USOCK:
             switch (type) {
             case NN_USOCK_ACCEPTED:
-                nn_epbase_clear_error (atcp->epbase);
+                nn_ep_clear_error (atcp->ep);
 
                 /*  Set the relevant socket options. */
                 sz = sizeof (val);
-                nn_epbase_getopt (atcp->epbase, NN_SOL_SOCKET, NN_SNDBUF,
-                    &val, &sz);
+                nn_ep_getopt (atcp->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
                 nn_assert (sz == sizeof (val));
                 nn_usock_setsockopt (&atcp->usock, SOL_SOCKET, SO_SNDBUF,
                     &val, sizeof (val));
                 sz = sizeof (val);
-                nn_epbase_getopt (atcp->epbase, NN_SOL_SOCKET, NN_RCVBUF,
-                    &val, &sz);
+                nn_ep_getopt (atcp->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
                 nn_assert (sz == sizeof (val));
                 nn_usock_setsockopt (&atcp->usock, SOL_SOCKET, SO_RCVBUF,
                     &val, sizeof (val));
@@ -207,7 +205,7 @@
                 nn_stcp_start (&atcp->stcp, &atcp->usock);
                 atcp->state = NN_ATCP_STATE_ACTIVE;
 
-                nn_epbase_stat_increment (atcp->epbase,
+                nn_ep_stat_increment (atcp->ep,
                     NN_STAT_ACCEPTED_CONNECTIONS, 1);
 
                 return;
@@ -220,10 +218,8 @@
             switch (type) {
 
             case NN_USOCK_ACCEPT_ERROR:
-                nn_epbase_set_error (atcp->epbase,
-                    nn_usock_geterrno(atcp->listener));
-                nn_epbase_stat_increment (atcp->epbase,
-                    NN_STAT_ACCEPT_ERRORS, 1);
+                nn_ep_set_error (atcp->ep, nn_usock_geterrno(atcp->listener));
+                nn_ep_stat_increment (atcp->ep, NN_STAT_ACCEPT_ERRORS, 1);
                 nn_usock_accept (&atcp->usock, atcp->listener);
                 return;
 
@@ -246,8 +242,7 @@
             case NN_STCP_ERROR:
                 nn_stcp_stop (&atcp->stcp);
                 atcp->state = NN_ATCP_STATE_STOPPING_STCP;
-                nn_epbase_stat_increment (atcp->epbase,
-                    NN_STAT_BROKEN_CONNECTIONS, 1);
+                nn_ep_stat_increment (atcp->ep, NN_STAT_BROKEN_CONNECTIONS, 1);
                 return;
             default:
                 nn_fsm_bad_action (atcp->state, src, type);
diff --git a/src/transports/tcp/atcp.h b/src/transports/tcp/atcp.h
index 435d2a8..ee9cf45 100644
--- a/src/transports/tcp/atcp.h
+++ b/src/transports/tcp/atcp.h
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -48,7 +49,7 @@
     int state;
 
     /*  Pointer to the associated endpoint. */
-    struct nn_epbase *epbase;
+    struct nn_ep *ep;
 
     /*  Underlying socket. */
     struct nn_usock usock;
@@ -69,7 +70,7 @@
 };
 
 void nn_atcp_init (struct nn_atcp *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner);
+    struct nn_ep *ep, struct nn_fsm *owner);
 void nn_atcp_term (struct nn_atcp *self);
 
 int nn_atcp_isidle (struct nn_atcp *self);
diff --git a/src/transports/tcp/btcp.c b/src/transports/tcp/btcp.c
index 1b012c8..a22b60c 100644
--- a/src/transports/tcp/btcp.c
+++ b/src/transports/tcp/btcp.c
@@ -66,9 +66,7 @@
     struct nn_fsm fsm;
     int state;
 
-    /*  This object is a specific type of endpoint.
-        Thus it is derived from epbase. */
-    struct nn_epbase epbase;
+    struct nn_ep *ep;
 
     /*  The underlying listening TCP socket. */
     struct nn_usock usock;
@@ -80,10 +78,10 @@
     struct nn_list atcps;
 };
 
-/*  nn_epbase virtual interface implementation. */
-static void nn_btcp_stop (struct nn_epbase *self);
-static void nn_btcp_destroy (struct nn_epbase *self);
-const struct nn_epbase_vfptr nn_btcp_epbase_vfptr = {
+/*  nn_ep virtual interface implementation. */
+static void nn_btcp_stop (struct nn_ep *);
+static void nn_btcp_destroy (struct nn_ep *);
+const struct nn_ep_vfptr nn_btcp_ep_vfptr = {
     nn_btcp_stop,
     nn_btcp_destroy
 };
@@ -96,7 +94,7 @@
 static int nn_btcp_listen (struct nn_btcp *self);
 static void nn_btcp_start_accepting (struct nn_btcp *self);
 
-int nn_btcp_create (void *hint, struct nn_epbase **epbase)
+int nn_btcp_create (struct nn_ep *ep)
 {
     int rc;
     struct nn_btcp *self;
@@ -110,42 +108,38 @@
 
     /*  Allocate the new endpoint object. */
     self = nn_alloc (sizeof (struct nn_btcp), "btcp");
+    self->ep = ep;
     alloc_assert (self);
 
-    /*  Initalise the epbase. */
-    nn_epbase_init (&self->epbase, &nn_btcp_epbase_vfptr, hint);
-    addr = nn_epbase_getaddr (&self->epbase);
+    nn_ep_tran_setup (ep, &nn_btcp_ep_vfptr, self);
+    addr = nn_ep_getaddr (ep);
 
     /*  Parse the port. */
     end = addr + strlen (addr);
     pos = strrchr (addr, ':');
-    if (nn_slow (!pos)) {
-        nn_epbase_term (&self->epbase);
+    if (pos == NULL) {
         return -EINVAL;
     }
     ++pos;
     rc = nn_port_resolve (pos, end - pos);
-    if (nn_slow (rc < 0)) {
-        nn_epbase_term (&self->epbase);
+    if (rc < 0) {
         return -EINVAL;
     }
 
     /*  Check whether IPv6 is to be used. */
     ipv4onlylen = sizeof (ipv4only);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
-        &ipv4only, &ipv4onlylen);
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen);
     nn_assert (ipv4onlylen == sizeof (ipv4only));
 
     /*  Parse the address. */
     rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen);
     if (nn_slow (rc < 0)) {
-        nn_epbase_term (&self->epbase);
         return -ENODEV;
     }
 
     /*  Initialise the structure. */
     nn_fsm_init_root (&self->fsm, nn_btcp_handler, nn_btcp_shutdown,
-        nn_epbase_getctx (&self->epbase));
+        nn_ep_getctx (ep));
     self->state = NN_BTCP_STATE_IDLE;
     self->atcp = NULL;
     nn_list_init (&self->atcps);
@@ -157,36 +151,31 @@
 
     rc = nn_btcp_listen (self);
     if (rc != 0) {
-        nn_epbase_term (&self->epbase);
         return rc;
     }
 
-    /*  Return the base class as an out parameter. */
-    *epbase = &self->epbase;
-
     return 0;
 }
 
-static void nn_btcp_stop (struct nn_epbase *self)
+static void nn_btcp_stop (struct nn_ep *ep)
 {
     struct nn_btcp *btcp;
 
-    btcp = nn_cont (self, struct nn_btcp, epbase);
+    btcp = nn_ep_tran_private (ep);
 
     nn_fsm_stop (&btcp->fsm);
 }
 
-static void nn_btcp_destroy (struct nn_epbase *self)
+static void nn_btcp_destroy (struct nn_ep *ep)
 {
     struct nn_btcp *btcp;
 
-    btcp = nn_cont (self, struct nn_btcp, epbase);
+    btcp = nn_ep_tran_private (ep);
 
     nn_assert_state (btcp, NN_BTCP_STATE_IDLE);
     nn_list_term (&btcp->atcps);
     nn_assert (btcp->atcp == NULL);
     nn_usock_term (&btcp->usock);
-    nn_epbase_term (&btcp->epbase);
     nn_fsm_term (&btcp->fsm);
 
     nn_free (btcp);
@@ -244,7 +233,7 @@
         if (nn_list_empty (&btcp->atcps)) {
             btcp->state = NN_BTCP_STATE_IDLE;
             nn_fsm_stopped_noevent (&btcp->fsm);
-            nn_epbase_stopped (&btcp->epbase);
+            nn_ep_stopped (btcp->ep);
             return;
         }
 
@@ -328,7 +317,7 @@
     uint16_t port;
 
     /*  First, resolve the IP address. */
-    addr = nn_epbase_getaddr (&self->epbase);
+    addr = nn_ep_getaddr (self->ep);
     memset (&ss, 0, sizeof (ss));
 
     /*  Parse the port. */
@@ -345,7 +334,7 @@
 
     /*  Parse the address. */
     ipv4onlylen = sizeof (ipv4only);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY,
         &ipv4only, &ipv4onlylen);
     nn_assert (ipv4onlylen == sizeof (ipv4only));
     rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen);
@@ -400,7 +389,7 @@
     /*  Allocate new atcp state machine. */
     self->atcp = nn_alloc (sizeof (struct nn_atcp), "atcp");
     alloc_assert (self->atcp);
-    nn_atcp_init (self->atcp, NN_BTCP_SRC_ATCP, &self->epbase, &self->fsm);
+    nn_atcp_init (self->atcp, NN_BTCP_SRC_ATCP, self->ep, &self->fsm);
 
     /*  Start waiting for a new incoming connection. */
     nn_atcp_start (self->atcp, &self->usock);
diff --git a/src/transports/tcp/btcp.h b/src/transports/tcp/btcp.h
index 30aca24..633af88 100644
--- a/src/transports/tcp/btcp.h
+++ b/src/transports/tcp/btcp.h
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -27,7 +28,7 @@
 
 /*  State machine managing bound TCP socket. */
 
-int nn_btcp_create (void *hint, struct nn_epbase **epbase);
+int nn_btcp_create (struct nn_ep *);
 
 #endif
 
diff --git a/src/transports/tcp/ctcp.c b/src/transports/tcp/ctcp.c
index d46ddf7..fb1fc73 100644
--- a/src/transports/tcp/ctcp.c
+++ b/src/transports/tcp/ctcp.c
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2012-2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -73,9 +74,7 @@
     struct nn_fsm fsm;
     int state;
 
-    /*  This object is a specific type of endpoint.
-        Thus it is derived from epbase. */
-    struct nn_epbase epbase;
+    struct nn_ep *ep;
 
     /*  The underlying TCP socket. */
     struct nn_usock usock;
@@ -93,10 +92,10 @@
     struct nn_dns_result dns_result;
 };
 
-/*  nn_epbase virtual interface implementation. */
-static void nn_ctcp_stop (struct nn_epbase *self);
-static void nn_ctcp_destroy (struct nn_epbase *self);
-const struct nn_epbase_vfptr nn_ctcp_epbase_vfptr = {
+/*  nn_ep virtual interface implementation. */
+static void nn_ctcp_stop (struct nn_ep *ep);
+static void nn_ctcp_destroy (struct nn_ep *ep);
+const struct nn_ep_vfptr nn_ctcp_ep_vfptr = {
     nn_ctcp_stop,
     nn_ctcp_destroy
 };
@@ -110,7 +109,7 @@
 static void nn_ctcp_start_connecting (struct nn_ctcp *self,
     struct sockaddr_storage *ss, size_t sslen);
 
-int nn_ctcp_create (void *hint, struct nn_epbase **epbase)
+int nn_ctcp_create (struct nn_ep *ep)
 {
     int rc;
     const char *addr;
@@ -133,16 +132,16 @@
     alloc_assert (self);
 
     /*  Initalise the endpoint. */
-    nn_epbase_init (&self->epbase, &nn_ctcp_epbase_vfptr, hint);
+    self->ep = ep;
+    nn_ep_tran_setup (ep, &nn_ctcp_ep_vfptr, self);
 
     /*  Check whether IPv6 is to be used. */
     ipv4onlylen = sizeof (ipv4only);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
-        &ipv4only, &ipv4onlylen);
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen);
     nn_assert (ipv4onlylen == sizeof (ipv4only));
 
     /*  Start parsing the address. */
-    addr = nn_epbase_getaddr (&self->epbase);
+    addr = nn_ep_getaddr (ep);
     addrlen = strlen (addr);
     semicolon = strchr (addr, ';');
     hostname = semicolon ? semicolon + 1 : addr;
@@ -150,13 +149,11 @@
     end = addr + addrlen;
 
     /*  Parse the port. */
-    if (nn_slow (!colon)) {
-        nn_epbase_term (&self->epbase);
+    if (!colon) {
         return -EINVAL;
     }
     rc = nn_port_resolve (colon + 1, end - colon - 1);
-    if (nn_slow (rc < 0)) {
-        nn_epbase_term (&self->epbase);
+    if (rc < 0) {
         return -EINVAL;
     }
 
@@ -165,7 +162,6 @@
     if (nn_dns_check_hostname (hostname, colon - hostname) < 0 &&
           nn_literal_resolve (hostname, colon - hostname, ipv4only,
           &ss, &sslen) < 0) {
-        nn_epbase_term (&self->epbase);
         return -EINVAL;
     }
 
@@ -173,61 +169,55 @@
     if (semicolon) {
         rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &ss, &sslen);
         if (rc < 0) {
-            nn_epbase_term (&self->epbase);
             return -ENODEV;
         }
     }
 
     /*  Initialise the structure. */
     nn_fsm_init_root (&self->fsm, nn_ctcp_handler, nn_ctcp_shutdown,
-        nn_epbase_getctx (&self->epbase));
+        nn_ep_getctx (ep));
     self->state = NN_CTCP_STATE_IDLE;
     nn_usock_init (&self->usock, NN_CTCP_SRC_USOCK, &self->fsm);
     sz = sizeof (reconnect_ivl);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
-        &reconnect_ivl, &sz);
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL, &reconnect_ivl, &sz);
     nn_assert (sz == sizeof (reconnect_ivl));
     sz = sizeof (reconnect_ivl_max);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
         &reconnect_ivl_max, &sz);
     nn_assert (sz == sizeof (reconnect_ivl_max));
     if (reconnect_ivl_max == 0)
         reconnect_ivl_max = reconnect_ivl;
     nn_backoff_init (&self->retry, NN_CTCP_SRC_RECONNECT_TIMER,
         reconnect_ivl, reconnect_ivl_max, &self->fsm);
-    nn_stcp_init (&self->stcp, NN_CTCP_SRC_STCP, &self->epbase, &self->fsm);
+    nn_stcp_init (&self->stcp, NN_CTCP_SRC_STCP, ep, &self->fsm);
     nn_dns_init (&self->dns, NN_CTCP_SRC_DNS, &self->fsm);
 
     /*  Start the state machine. */
     nn_fsm_start (&self->fsm);
 
-    /*  Return the base class as an out parameter. */
-    *epbase = &self->epbase;
-
     return 0;
 }
 
-static void nn_ctcp_stop (struct nn_epbase *self)
+static void nn_ctcp_stop (struct nn_ep *ep)
 {
     struct nn_ctcp *ctcp;
 
-    ctcp = nn_cont (self, struct nn_ctcp, epbase);
+    ctcp = nn_ep_tran_private (ep);
 
     nn_fsm_stop (&ctcp->fsm);
 }
 
-static void nn_ctcp_destroy (struct nn_epbase *self)
+static void nn_ctcp_destroy (struct nn_ep *ep)
 {
     struct nn_ctcp *ctcp;
 
-    ctcp = nn_cont (self, struct nn_ctcp, epbase);
+    ctcp = nn_ep_tran_private (ep);
 
     nn_dns_term (&ctcp->dns);
     nn_stcp_term (&ctcp->stcp);
     nn_backoff_term (&ctcp->retry);
     nn_usock_term (&ctcp->usock);
     nn_fsm_term (&ctcp->fsm);
-    nn_epbase_term (&ctcp->epbase);
 
     nn_free (ctcp);
 }
@@ -239,15 +229,14 @@
 
     ctcp = nn_cont (self, struct nn_ctcp, fsm);
 
-    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
+    if (src == NN_FSM_ACTION && type == NN_FSM_STOP) {
         if (!nn_stcp_isidle (&ctcp->stcp)) {
-            nn_epbase_stat_increment (&ctcp->epbase,
-                NN_STAT_DROPPED_CONNECTIONS, 1);
+            nn_ep_stat_increment (ctcp->ep, NN_STAT_DROPPED_CONNECTIONS, 1);
             nn_stcp_stop (&ctcp->stcp);
         }
         ctcp->state = NN_CTCP_STATE_STOPPING_STCP_FINAL;
     }
-    if (nn_slow (ctcp->state == NN_CTCP_STATE_STOPPING_STCP_FINAL)) {
+    if (ctcp->state == NN_CTCP_STATE_STOPPING_STCP_FINAL) {
         if (!nn_stcp_isidle (&ctcp->stcp))
             return;
         nn_backoff_stop (&ctcp->retry);
@@ -262,7 +251,7 @@
             return;
         ctcp->state = NN_CTCP_STATE_IDLE;
         nn_fsm_stopped_noevent (&ctcp->fsm);
-        nn_epbase_stopped (&ctcp->epbase);
+        nn_ep_stopped (ctcp->ep);
         return;
     }
 
@@ -357,21 +346,19 @@
             case NN_USOCK_CONNECTED:
                 nn_stcp_start (&ctcp->stcp, &ctcp->usock);
                 ctcp->state = NN_CTCP_STATE_ACTIVE;
-                nn_epbase_stat_increment (&ctcp->epbase,
+                nn_ep_stat_increment (ctcp->ep,
                     NN_STAT_INPROGRESS_CONNECTIONS, -1);
-                nn_epbase_stat_increment (&ctcp->epbase,
+                nn_ep_stat_increment (ctcp->ep,
                     NN_STAT_ESTABLISHED_CONNECTIONS, 1);
-                nn_epbase_clear_error (&ctcp->epbase);
+                nn_ep_clear_error (ctcp->ep);
                 return;
             case NN_USOCK_ERROR:
-                nn_epbase_set_error (&ctcp->epbase,
-                    nn_usock_geterrno (&ctcp->usock));
+                nn_ep_set_error (ctcp->ep, nn_usock_geterrno (&ctcp->usock));
                 nn_usock_stop (&ctcp->usock);
                 ctcp->state = NN_CTCP_STATE_STOPPING_USOCK;
-                nn_epbase_stat_increment (&ctcp->epbase,
+                nn_ep_stat_increment (ctcp->ep,
                     NN_STAT_INPROGRESS_CONNECTIONS, -1);
-                nn_epbase_stat_increment (&ctcp->epbase,
-                    NN_STAT_CONNECT_ERRORS, 1);
+                nn_ep_stat_increment (ctcp->ep, NN_STAT_CONNECT_ERRORS, 1);
                 return;
             default:
                 nn_fsm_bad_action (ctcp->state, src, type);
@@ -393,8 +380,7 @@
             case NN_STCP_ERROR:
                 nn_stcp_stop (&ctcp->stcp);
                 ctcp->state = NN_CTCP_STATE_STOPPING_STCP;
-                nn_epbase_stat_increment (&ctcp->epbase,
-                    NN_STAT_BROKEN_CONNECTIONS, 1);
+                nn_ep_stat_increment (ctcp->ep, NN_STAT_BROKEN_CONNECTIONS, 1);
                 return;
             default:
                 nn_fsm_bad_action (ctcp->state, src, type);
@@ -513,7 +499,7 @@
     size_t ipv4onlylen;
 
     /*  Extract the hostname part from address string. */
-    addr = nn_epbase_getaddr (&self->epbase);
+    addr = nn_ep_getaddr (self->ep);
     begin = strchr (addr, ';');
     if (!begin)
         begin = addr;
@@ -524,7 +510,7 @@
 
     /*  Check whether IPv6 is to be used. */
     ipv4onlylen = sizeof (ipv4only);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY,
         &ipv4only, &ipv4onlylen);
     nn_assert (ipv4onlylen == sizeof (ipv4only));
 
@@ -553,7 +539,7 @@
     size_t sz;
 
     /*  Create IP address from the address string. */
-    addr = nn_epbase_getaddr (&self->epbase);
+    addr = nn_ep_getaddr (self->ep);
     memset (&remote, 0, sizeof (remote));
 
     /*  Parse the port. */
@@ -565,7 +551,7 @@
 
     /*  Check whether IPv6 is to be used. */
     ipv4onlylen = sizeof (ipv4only);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY,
         &ipv4only, &ipv4onlylen);
     nn_assert (ipv4onlylen == sizeof (ipv4only));
 
@@ -603,12 +589,12 @@
 
     /*  Set the relevant socket options. */
     sz = sizeof (val);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
     nn_assert (sz == sizeof (val));
     nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF,
         &val, sizeof (val));
     sz = sizeof (val);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
     nn_assert (sz == sizeof (val));
     nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF,
         &val, sizeof (val));
@@ -624,7 +610,5 @@
     /*  Start connecting. */
     nn_usock_connect (&self->usock, (struct sockaddr*) &remote, remotelen);
     self->state = NN_CTCP_STATE_CONNECTING;
-    nn_epbase_stat_increment (&self->epbase,
-        NN_STAT_INPROGRESS_CONNECTIONS, 1);
+    nn_ep_stat_increment (self->ep, NN_STAT_INPROGRESS_CONNECTIONS, 1);
 }
-
diff --git a/src/transports/tcp/ctcp.h b/src/transports/tcp/ctcp.h
index 92b1694..11db1ca 100644
--- a/src/transports/tcp/ctcp.h
+++ b/src/transports/tcp/ctcp.h
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -27,7 +28,7 @@
 
 /*  State machine managing connected TCP socket. */
 
-int nn_ctcp_create (void *hint, struct nn_epbase **epbase);
+int nn_ctcp_create (struct nn_ep *);
 
 #endif
 
diff --git a/src/transports/tcp/stcp.c b/src/transports/tcp/stcp.c
index 5abe536..61be273 100644
--- a/src/transports/tcp/stcp.c
+++ b/src/transports/tcp/stcp.c
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -65,7 +66,7 @@
     void *srcptr);
 
 void nn_stcp_init (struct nn_stcp *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner)
+    struct nn_ep *ep, struct nn_fsm *owner)
 {
     nn_fsm_init (&self->fsm, nn_stcp_handler, nn_stcp_shutdown,
         src, self, owner);
@@ -74,7 +75,7 @@
     self->usock = NULL;
     self->usock_owner.src = -1;
     self->usock_owner.fsm = NULL;
-    nn_pipebase_init (&self->pipebase, &nn_stcp_pipebase_vfptr, epbase);
+    nn_pipebase_init (&self->pipebase, &nn_stcp_pipebase_vfptr, ep);
     self->instate = -1;
     nn_msg_init (&self->inmsg, 0);
     self->outstate = -1;
diff --git a/src/transports/tcp/stcp.h b/src/transports/tcp/stcp.h
index d817807..0a53717 100644
--- a/src/transports/tcp/stcp.h
+++ b/src/transports/tcp/stcp.h
@@ -1,5 +1,6 @@
 /*
     Copyright (c) 2013 Martin Sustrik  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -79,7 +80,7 @@
 };
 
 void nn_stcp_init (struct nn_stcp *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner);
+    struct nn_ep *ep, struct nn_fsm *owner);
 void nn_stcp_term (struct nn_stcp *self);
 
 int nn_stcp_isidle (struct nn_stcp *self);
diff --git a/src/transports/tcp/tcp.c b/src/transports/tcp/tcp.c
index 3039e21..32e5c60 100644
--- a/src/transports/tcp/tcp.c
+++ b/src/transports/tcp/tcp.c
@@ -1,6 +1,7 @@
 /*
     Copyright (c) 2012-2013 Martin Sustrik  All rights reserved.
     Copyright (c) 2013 GoPivotal, Inc.  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -63,8 +64,8 @@
 };
 
 /*  nn_transport interface. */
-static int nn_tcp_bind (void *hint, struct nn_epbase **epbase);
-static int nn_tcp_connect (void *hint, struct nn_epbase **epbase);
+static int nn_tcp_bind (struct nn_ep *ep);
+static int nn_tcp_connect (struct nn_ep *ep);
 static struct nn_optset *nn_tcp_optset (void);
 
 static struct nn_transport nn_tcp_vfptr = {
@@ -80,14 +81,14 @@
 
 struct nn_transport *nn_tcp = &nn_tcp_vfptr;
 
-static int nn_tcp_bind (void *hint, struct nn_epbase **epbase)
+static int nn_tcp_bind (struct nn_ep *ep)
 {
-    return nn_btcp_create (hint, epbase);
+    return nn_btcp_create (ep);
 }
 
-static int nn_tcp_connect (void *hint, struct nn_epbase **epbase)
+static int nn_tcp_connect (struct nn_ep *ep)
 {
-    return nn_ctcp_create (hint, epbase);
+    return nn_ctcp_create (ep);
 }
 
 static struct nn_optset *nn_tcp_optset ()
diff --git a/src/transports/ws/aws.c b/src/transports/ws/aws.c
index bb025e4..d60a1fd 100644
--- a/src/transports/ws/aws.c
+++ b/src/transports/ws/aws.c
@@ -1,7 +1,7 @@
 /*
     Copyright (c) 2012-2013 250bpm s.r.o.  All rights reserved.
     Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved.
-    Copyright 2015 Garrett D'Amore <garrett@damore.org>
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -49,17 +49,17 @@
     void *srcptr);
 
 void nn_aws_init (struct nn_aws *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner)
+    struct nn_ep *ep, struct nn_fsm *owner)
 {
     nn_fsm_init (&self->fsm, nn_aws_handler, nn_aws_shutdown,
         src, self, owner);
     self->state = NN_AWS_STATE_IDLE;
-    self->epbase = epbase;
+    self->ep = ep;
     nn_usock_init (&self->usock, NN_AWS_SRC_USOCK, &self->fsm);
     self->listener = NULL;
     self->listener_owner.src = -1;
     self->listener_owner.fsm = NULL;
-    nn_sws_init (&self->sws, NN_AWS_SRC_SWS, epbase, &self->fsm);
+    nn_sws_init (&self->sws, NN_AWS_SRC_SWS, ep, &self->fsm);
     nn_fsm_event_init (&self->accepted);
     nn_fsm_event_init (&self->done);
     nn_list_item_init (&self->item);
@@ -110,8 +110,7 @@
 
     if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
         if (!nn_sws_isidle (&aws->sws)) {
-            nn_epbase_stat_increment (aws->epbase,
-                NN_STAT_DROPPED_CONNECTIONS, 1);
+            nn_ep_stat_increment (aws->ep, NN_STAT_DROPPED_CONNECTIONS, 1);
             nn_sws_stop (&aws->sws);
         }
         aws->state = NN_AWS_STATE_STOPPING_SWS_FINAL;
@@ -183,24 +182,21 @@
         case NN_AWS_SRC_USOCK:
             switch (type) {
             case NN_USOCK_ACCEPTED:
-                nn_epbase_clear_error (aws->epbase);
+                nn_ep_clear_error (aws->ep);
 
                 /*  Set the relevant socket options. */
                 sz = sizeof (val);
-                nn_epbase_getopt (aws->epbase, NN_SOL_SOCKET, NN_SNDBUF,
-                    &val, &sz);
+                nn_ep_getopt (aws->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
                 nn_assert (sz == sizeof (val));
                 nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_SNDBUF,
                     &val, sizeof (val));
                 sz = sizeof (val);
-                nn_epbase_getopt (aws->epbase, NN_SOL_SOCKET, NN_RCVBUF,
-                    &val, &sz);
+                nn_ep_getopt (aws->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
                 nn_assert (sz == sizeof (val));
                 nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_RCVBUF,
                     &val, sizeof (val));
                 sz = sizeof (val);
-                nn_epbase_getopt (aws->epbase, NN_WS, NN_WS_MSG_TYPE,
-                    &val, &sz);
+                nn_ep_getopt (aws->ep, NN_WS, NN_WS_MSG_TYPE, &val, &sz);
                 msg_type = (uint8_t)val;
 
                 /*   Since the WebSocket handshake must poll, the receive
@@ -224,8 +220,7 @@
                     NULL, NULL, msg_type);
                 aws->state = NN_AWS_STATE_ACTIVE;
 
-                nn_epbase_stat_increment (aws->epbase,
-                    NN_STAT_ACCEPTED_CONNECTIONS, 1);
+                nn_ep_stat_increment (aws->ep, NN_STAT_ACCEPTED_CONNECTIONS, 1);
 
                 return;
 
@@ -237,10 +232,8 @@
             switch (type) {
 
             case NN_USOCK_ACCEPT_ERROR:
-                nn_epbase_set_error (aws->epbase,
-                    nn_usock_geterrno (aws->listener));
-                nn_epbase_stat_increment (aws->epbase,
-                    NN_STAT_ACCEPT_ERRORS, 1);
+                nn_ep_set_error (aws->ep, nn_usock_geterrno (aws->listener));
+                nn_ep_stat_increment (aws->ep, NN_STAT_ACCEPT_ERRORS, 1);
                 nn_usock_accept (&aws->usock, aws->listener);
                 return;
 
@@ -269,8 +262,7 @@
             case NN_SWS_RETURN_ERROR:
                 nn_sws_stop (&aws->sws);
                 aws->state = NN_AWS_STATE_STOPPING_SWS;
-                nn_epbase_stat_increment (aws->epbase,
-                    NN_STAT_BROKEN_CONNECTIONS, 1);
+                nn_ep_stat_increment (aws->ep, NN_STAT_BROKEN_CONNECTIONS, 1);
                 return;
             default:
                 nn_fsm_bad_action (aws->state, src, type);
diff --git a/src/transports/ws/aws.h b/src/transports/ws/aws.h
index ae271be..8a03255 100644
--- a/src/transports/ws/aws.h
+++ b/src/transports/ws/aws.h
@@ -1,6 +1,7 @@
 /*
     Copyright (c) 2013 250bpm s.r.o.  All rights reserved.
     Copyright (c) 2014 Wirebird Labs LLC.  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -49,7 +50,7 @@
     int state;
 
     /*  Pointer to the associated endpoint. */
-    struct nn_epbase *epbase;
+    struct nn_ep *ep;
 
     /*  Underlying socket. */
     struct nn_usock usock;
@@ -70,7 +71,7 @@
 };
 
 void nn_aws_init (struct nn_aws *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner);
+    struct nn_ep *ep, struct nn_fsm *owner);
 void nn_aws_term (struct nn_aws *self);
 
 int nn_aws_isidle (struct nn_aws *self);
diff --git a/src/transports/ws/bws.c b/src/transports/ws/bws.c
index da3a53f..98c5448 100644
--- a/src/transports/ws/bws.c
+++ b/src/transports/ws/bws.c
@@ -65,9 +65,7 @@
     struct nn_fsm fsm;
     int state;
 
-    /*  This object is a specific type of endpoint.
-        Thus it is derived from epbase. */
-    struct nn_epbase epbase;
+    struct nn_ep *ep;
 
     /*  The underlying listening WS socket. */
     struct nn_usock usock;
@@ -79,10 +77,10 @@
     struct nn_list awss;
 };
 
-/*  nn_epbase virtual interface implementation. */
-static void nn_bws_stop (struct nn_epbase *self);
-static void nn_bws_destroy (struct nn_epbase *self);
-const struct nn_epbase_vfptr nn_bws_epbase_vfptr = {
+/*  nn_ep virtual interface implementation. */
+static void nn_bws_stop (struct nn_ep *);
+static void nn_bws_destroy (struct nn_ep *);
+const struct nn_ep_vfptr nn_bws_ep_vfptr = {
     nn_bws_stop,
     nn_bws_destroy
 };
@@ -95,7 +93,7 @@
 static int nn_bws_listen (struct nn_bws *self);
 static void nn_bws_start_accepting (struct nn_bws *self);
 
-int nn_bws_create (void *hint, struct nn_epbase **epbase)
+int nn_bws_create (struct nn_ep *ep)
 {
     int rc;
     struct nn_bws *self;
@@ -110,41 +108,37 @@
     /*  Allocate the new endpoint object. */
     self = nn_alloc (sizeof (struct nn_bws), "bws");
     alloc_assert (self);
+    self->ep = ep;
 
-    /*  Initalise the epbase. */
-    nn_epbase_init (&self->epbase, &nn_bws_epbase_vfptr, hint);
-    addr = nn_epbase_getaddr (&self->epbase);
+    nn_ep_tran_setup (ep, &nn_bws_ep_vfptr, self);
+    addr = nn_ep_getaddr (ep);
 
     /*  Parse the port. */
     end = addr + strlen (addr);
     pos = strrchr (addr, ':');
-    if (nn_slow (!pos)) {
-        nn_epbase_term (&self->epbase);
+    if (!pos) {
         return -EINVAL;
     }
     ++pos;
     rc = nn_port_resolve (pos, end - pos);
-    if (nn_slow (rc < 0)) {
-        nn_epbase_term (&self->epbase);
+    if (rc < 0) {
         return -EINVAL;
     }
 
     /*  Check whether IPv6 is to be used. */
     ipv4onlylen = sizeof (ipv4only);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
-        &ipv4only, &ipv4onlylen);
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen);
     nn_assert (ipv4onlylen == sizeof (ipv4only));
 
     /*  Parse the address. */
     rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen);
-    if (nn_slow (rc < 0)) {
-        nn_epbase_term (&self->epbase);
+    if (rc < 0) {
         return -ENODEV;
     }
 
     /*  Initialise the structure. */
     nn_fsm_init_root (&self->fsm, nn_bws_handler, nn_bws_shutdown,
-        nn_epbase_getctx (&self->epbase));
+        nn_ep_getctx (ep));
     self->state = NN_BWS_STATE_IDLE;
     self->aws = NULL;
     nn_list_init (&self->awss);
@@ -156,36 +150,31 @@
 
     rc = nn_bws_listen (self);
     if (rc != 0) {
-        nn_epbase_term (&self->epbase);
         return rc;
     }
 
-    /*  Return the base class as an out parameter. */
-    *epbase = &self->epbase;
-
     return 0;
 }
 
-static void nn_bws_stop (struct nn_epbase *self)
+static void nn_bws_stop (struct nn_ep *ep)
 {
     struct nn_bws *bws;
 
-    bws = nn_cont (self, struct nn_bws, epbase);
+    bws = nn_ep_tran_private (ep);
 
     nn_fsm_stop (&bws->fsm);
 }
 
-static void nn_bws_destroy (struct nn_epbase *self)
+static void nn_bws_destroy (struct nn_ep *ep)
 {
     struct nn_bws *bws;
 
-    bws = nn_cont (self, struct nn_bws, epbase);
+    bws = nn_ep_tran_private (ep);
 
     nn_assert_state (bws, NN_BWS_STATE_IDLE);
     nn_list_term (&bws->awss);
     nn_assert (bws->aws == NULL);
     nn_usock_term (&bws->usock);
-    nn_epbase_term (&bws->epbase);
     nn_fsm_term (&bws->fsm);
 
     nn_free (bws);
@@ -200,7 +189,7 @@
 
     bws = nn_cont (self, struct nn_bws, fsm);
 
-    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
+    if (src == NN_FSM_ACTION && type == NN_FSM_STOP) {
         if (bws->aws) {
             nn_aws_stop (bws->aws);
             bws->state = NN_BWS_STATE_STOPPING_AWS;
@@ -209,7 +198,7 @@
             bws->state = NN_BWS_STATE_STOPPING_USOCK;
         }
     }
-    if (nn_slow (bws->state == NN_BWS_STATE_STOPPING_AWS)) {
+    if (bws->state == NN_BWS_STATE_STOPPING_AWS) {
         if (!nn_aws_isidle (bws->aws))
             return;
         nn_aws_term (bws->aws);
@@ -218,7 +207,7 @@
         nn_usock_stop (&bws->usock);
         bws->state = NN_BWS_STATE_STOPPING_USOCK;
     }
-    if (nn_slow (bws->state == NN_BWS_STATE_STOPPING_USOCK)) {
+    if (bws->state == NN_BWS_STATE_STOPPING_USOCK) {
        if (!nn_usock_isidle (&bws->usock))
             return;
         for (it = nn_list_begin (&bws->awss);
@@ -230,7 +219,7 @@
         bws->state = NN_BWS_STATE_STOPPING_AWSS;
         goto awss_stopping;
     }
-    if (nn_slow (bws->state == NN_BWS_STATE_STOPPING_AWSS)) {
+    if (bws->state == NN_BWS_STATE_STOPPING_AWSS) {
         nn_assert (src == NN_BWS_SRC_AWS && type == NN_AWS_STOPPED);
         aws = (struct nn_aws *) srcptr;
         nn_list_erase (&bws->awss, &aws->item);
@@ -243,7 +232,7 @@
         if (nn_list_empty (&bws->awss)) {
             bws->state = NN_BWS_STATE_IDLE;
             nn_fsm_stopped_noevent (&bws->fsm);
-            nn_epbase_stopped (&bws->epbase);
+            nn_ep_stopped (bws->ep);
             return;
         }
 
@@ -332,7 +321,7 @@
     uint16_t port;
 
     /*  First, resolve the IP address. */
-    addr = nn_epbase_getaddr (&self->epbase);
+    addr = nn_ep_getaddr (self->ep);
     memset (&ss, 0, sizeof (ss));
 
     /*  Parse the port. */
@@ -348,7 +337,7 @@
 
     /*  Parse the address. */
     ipv4onlylen = sizeof (ipv4only);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY,
         &ipv4only, &ipv4onlylen);
     nn_assert (ipv4onlylen == sizeof (ipv4only));
     rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen);
@@ -401,7 +390,7 @@
     /*  Allocate new aws state machine. */
     self->aws = nn_alloc (sizeof (struct nn_aws), "aws");
     alloc_assert (self->aws);
-    nn_aws_init (self->aws, NN_BWS_SRC_AWS, &self->epbase, &self->fsm);
+    nn_aws_init (self->aws, NN_BWS_SRC_AWS, self->ep, &self->fsm);
 
     /*  Start waiting for a new incoming connection. */
     nn_aws_start (self->aws, &self->usock);
diff --git a/src/transports/ws/bws.h b/src/transports/ws/bws.h
index 9203b2e..7e9f3f3 100644
--- a/src/transports/ws/bws.h
+++ b/src/transports/ws/bws.h
@@ -1,6 +1,7 @@
 /*
     Copyright (c) 2013 250bpm s.r.o.  All rights reserved.
     Copyright (c) 2014 Wirebird Labs LLC.  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -28,7 +29,6 @@
 
 /*  State machine managing bound WS socket. */
 
-int nn_bws_create (void *hint, struct nn_epbase **epbase);
+int nn_bws_create (struct nn_ep *ep);
 
 #endif
-
diff --git a/src/transports/ws/cws.c b/src/transports/ws/cws.c
index 627d1ec..546430f 100644
--- a/src/transports/ws/cws.c
+++ b/src/transports/ws/cws.c
@@ -1,7 +1,7 @@
 /*
     Copyright (c) 2012-2013 250bpm s.r.o.  All rights reserved.
     Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved.
-    Copyright 2015 Garrett D'Amore <garrett@damore.org>
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -75,9 +75,7 @@
     struct nn_fsm fsm;
     int state;
 
-    /*  This object is a specific type of endpoint.
-        Thus it is derived from epbase. */
-    struct nn_epbase epbase;
+    struct nn_ep *ep;
 
     /*  The underlying WS socket. */
     struct nn_usock usock;
@@ -109,10 +107,10 @@
     struct nn_dns_result dns_result;
 };
 
-/*  nn_epbase virtual interface implementation. */
-static void nn_cws_stop (struct nn_epbase *self);
-static void nn_cws_destroy (struct nn_epbase *self);
-const struct nn_epbase_vfptr nn_cws_epbase_vfptr = {
+/*  nn_ep virtual interface implementation. */
+static void nn_cws_stop (struct nn_ep *ep);
+static void nn_cws_destroy (struct nn_ep *ep);
+const struct nn_ep_vfptr nn_cws_ep_vfptr = {
     nn_cws_stop,
     nn_cws_destroy
 };
@@ -126,7 +124,7 @@
 static void nn_cws_start_connecting (struct nn_cws *self,
     struct sockaddr_storage *ss, size_t sslen);
 
-int nn_cws_create (void *hint, struct nn_epbase **epbase)
+int nn_cws_create (struct nn_ep *ep)
 {
     int rc;
     const char *addr;
@@ -151,18 +149,18 @@
     /*  Allocate the new endpoint object. */
     self = nn_alloc (sizeof (struct nn_cws), "cws");
     alloc_assert (self);
+    self->ep = ep;
 
     /*  Initalise the endpoint. */
-    nn_epbase_init (&self->epbase, &nn_cws_epbase_vfptr, hint);
+    nn_ep_tran_setup (ep, &nn_cws_ep_vfptr, self);
 
     /*  Check whether IPv6 is to be used. */
     ipv4onlylen = sizeof (ipv4only);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
-        &ipv4only, &ipv4onlylen);
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen);
     nn_assert (ipv4onlylen == sizeof (ipv4only));
 
     /*  Start parsing the address. */
-    addr = nn_epbase_getaddr (&self->epbase);
+    addr = nn_ep_getaddr (ep);
     addrlen = strlen (addr);
     semicolon = strchr (addr, ';');
     hostname = semicolon ? semicolon + 1 : addr;
@@ -175,10 +173,9 @@
     hostlen = resource - hostname;
 
     /*  Parse the port; assume port 80 if not explicitly declared. */
-    if (nn_slow (colon != NULL)) {
+    if (colon != NULL) {
         rc = nn_port_resolve (colon + 1, resource - colon - 1);
-        if (nn_slow (rc < 0)) {
-            nn_epbase_term (&self->epbase);
+        if (rc < 0) {
             return -EINVAL;
         }
         self->remote_port = rc;
@@ -192,7 +189,6 @@
     if (nn_dns_check_hostname (hostname, self->remote_hostname_len) < 0 &&
           nn_literal_resolve (hostname, self->remote_hostname_len, ipv4only,
           &ss, &sslen) < 0) {
-        nn_epbase_term (&self->epbase);
         return -EINVAL;
     }
 
@@ -200,7 +196,6 @@
     if (semicolon) {
         rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &ss, &sslen);
         if (rc < 0) {
-            nn_epbase_term (&self->epbase);
             return -ENODEV;
         }
     }
@@ -235,22 +230,20 @@
 
     /*  Initialise the structure. */
     nn_fsm_init_root (&self->fsm, nn_cws_handler, nn_cws_shutdown,
-        nn_epbase_getctx (&self->epbase));
+        nn_ep_getctx (ep));
     self->state = NN_CWS_STATE_IDLE;
     nn_usock_init (&self->usock, NN_CWS_SRC_USOCK, &self->fsm);
 
     sz = sizeof (msg_type);
-    nn_epbase_getopt (&self->epbase, NN_WS, NN_WS_MSG_TYPE,
-        &msg_type, &sz);
+    nn_ep_getopt (ep, NN_WS, NN_WS_MSG_TYPE, &msg_type, &sz);
     nn_assert (sz == sizeof (msg_type));
     self->msg_type = (uint8_t) msg_type;
 
     sz = sizeof (reconnect_ivl);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL,
-        &reconnect_ivl, &sz);
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL, &reconnect_ivl, &sz);
     nn_assert (sz == sizeof (reconnect_ivl));
     sz = sizeof (reconnect_ivl_max);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
+    nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX,
         &reconnect_ivl_max, &sz);
     nn_assert (sz == sizeof (reconnect_ivl_max));
     if (reconnect_ivl_max == 0)
@@ -258,32 +251,29 @@
     nn_backoff_init (&self->retry, NN_CWS_SRC_RECONNECT_TIMER,
         reconnect_ivl, reconnect_ivl_max, &self->fsm);
 
-    nn_sws_init (&self->sws, NN_CWS_SRC_SWS, &self->epbase, &self->fsm);
+    nn_sws_init (&self->sws, NN_CWS_SRC_SWS, ep, &self->fsm);
     nn_dns_init (&self->dns, NN_CWS_SRC_DNS, &self->fsm);
 
     /*  Start the state machine. */
     nn_fsm_start (&self->fsm);
 
-    /*  Return the base class as an out parameter. */
-    *epbase = &self->epbase;
-
     return 0;
 }
 
-static void nn_cws_stop (struct nn_epbase *self)
+static void nn_cws_stop (struct nn_ep *ep)
 {
     struct nn_cws *cws;
 
-    cws = nn_cont (self, struct nn_cws, epbase);
+    cws = nn_ep_tran_private (ep);
 
     nn_fsm_stop (&cws->fsm);
 }
 
-static void nn_cws_destroy (struct nn_epbase *self)
+static void nn_cws_destroy (struct nn_ep *ep)
 {
     struct nn_cws *cws;
 
-    cws = nn_cont (self, struct nn_cws, epbase);
+    cws = nn_ep_tran_private (ep);
 
     nn_chunkref_term (&cws->resource);
     nn_chunkref_term (&cws->remote_host);
@@ -293,7 +283,6 @@
     nn_backoff_term (&cws->retry);
     nn_usock_term (&cws->usock);
     nn_fsm_term (&cws->fsm);
-    nn_epbase_term (&cws->epbase);
 
     nn_free (cws);
 }
@@ -307,8 +296,7 @@
 
     if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
         if (!nn_sws_isidle (&cws->sws)) {
-            nn_epbase_stat_increment (&cws->epbase,
-                NN_STAT_DROPPED_CONNECTIONS, 1);
+            nn_ep_stat_increment (cws->ep, NN_STAT_DROPPED_CONNECTIONS, 1);
             nn_sws_stop (&cws->sws);
         }
         cws->state = NN_CWS_STATE_STOPPING_SWS_FINAL;
@@ -328,7 +316,7 @@
             return;
         cws->state = NN_CWS_STATE_IDLE;
         nn_fsm_stopped_noevent (&cws->fsm);
-        nn_epbase_stopped (&cws->epbase);
+        nn_ep_stopped (cws->ep);
         return;
     }
 
@@ -426,21 +414,19 @@
                     nn_chunkref_data (&cws->remote_host), cws->msg_type);
                 cws->state = NN_CWS_STATE_ACTIVE;
                 cws->peer_gone = 0;
-                nn_epbase_stat_increment (&cws->epbase,
+                nn_ep_stat_increment (cws->ep,
                     NN_STAT_INPROGRESS_CONNECTIONS, -1);
-                nn_epbase_stat_increment (&cws->epbase,
+                nn_ep_stat_increment (cws->ep,
                     NN_STAT_ESTABLISHED_CONNECTIONS, 1);
-                nn_epbase_clear_error (&cws->epbase);
+                nn_ep_clear_error (cws->ep);
                 return;
             case NN_USOCK_ERROR:
-                nn_epbase_set_error (&cws->epbase,
-                    nn_usock_geterrno (&cws->usock));
+                nn_ep_set_error (cws->ep, nn_usock_geterrno (&cws->usock));
                 nn_usock_stop (&cws->usock);
                 cws->state = NN_CWS_STATE_STOPPING_USOCK;
-                nn_epbase_stat_increment (&cws->epbase,
+                nn_ep_stat_increment (cws->ep,
                     NN_STAT_INPROGRESS_CONNECTIONS, -1);
-                nn_epbase_stat_increment (&cws->epbase,
-                    NN_STAT_CONNECT_ERRORS, 1);
+                nn_ep_stat_increment (cws->ep, NN_STAT_CONNECT_ERRORS, 1);
                 return;
             default:
                 nn_fsm_bad_action (cws->state, src, type);
@@ -469,8 +455,7 @@
             case NN_SWS_RETURN_ERROR:
                 nn_sws_stop (&cws->sws);
                 cws->state = NN_CWS_STATE_STOPPING_SWS;
-                nn_epbase_stat_increment (&cws->epbase,
-                    NN_STAT_BROKEN_CONNECTIONS, 1);
+                nn_ep_stat_increment (cws->ep, NN_STAT_BROKEN_CONNECTIONS, 1);
                 return;
             default:
                 nn_fsm_bad_action (cws->state, src, type);
@@ -593,7 +578,7 @@
 
     /*  Check whether IPv6 is to be used. */
     ipv4onlylen = sizeof (ipv4only);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY,
         &ipv4only, &ipv4onlylen);
     nn_assert (ipv4onlylen == sizeof (ipv4only));
 
@@ -615,7 +600,6 @@
     struct sockaddr_storage local;
     size_t locallen;
     int ipv4only;
-    size_t ipv4onlylen;
     int val;
     size_t sz;
 
@@ -623,10 +607,9 @@
     memset (&local, 0, sizeof (local));
 
     /*  Check whether IPv6 is to be used. */
-    ipv4onlylen = sizeof (ipv4only);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY,
-        &ipv4only, &ipv4onlylen);
-    nn_assert (ipv4onlylen == sizeof (ipv4only));
+    sz = sizeof (ipv4only);
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &sz);
+    nn_assert (sz == sizeof (ipv4only));
 
     rc = nn_iface_resolve (nn_chunkref_data (&self->nic),
     nn_chunkref_size (&self->nic), ipv4only, &local, &locallen);
@@ -657,12 +640,12 @@
 
     /*  Set the relevant socket options. */
     sz = sizeof (val);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
     nn_assert (sz == sizeof (val));
     nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF,
         &val, sizeof (val));
     sz = sizeof (val);
-    nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
+    nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
     nn_assert (sz == sizeof (val));
     nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF,
         &val, sizeof (val));
@@ -678,6 +661,5 @@
     /*  Start connecting. */
     nn_usock_connect (&self->usock, (struct sockaddr*) &remote, remotelen);
     self->state = NN_CWS_STATE_CONNECTING;
-    nn_epbase_stat_increment (&self->epbase,
-        NN_STAT_INPROGRESS_CONNECTIONS, 1);
+    nn_ep_stat_increment (self->ep, NN_STAT_INPROGRESS_CONNECTIONS, 1);
 }
diff --git a/src/transports/ws/cws.h b/src/transports/ws/cws.h
index 6c25b38..5314018 100644
--- a/src/transports/ws/cws.h
+++ b/src/transports/ws/cws.h
@@ -1,6 +1,7 @@
 /*
     Copyright (c) 2013 250bpm s.r.o.  All rights reserved.
     Copyright (c) 2014 Wirebird Labs LLC.  All rights reserved.
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -28,7 +29,7 @@
 
 /*  State machine managing connected WS socket. */
 
-int nn_cws_create (void *hint, struct nn_epbase **epbase);
+int nn_cws_create (struct nn_ep *);
 
 #endif
 
diff --git a/src/transports/ws/sws.c b/src/transports/ws/sws.c
index 7029131..b2590d4 100644
--- a/src/transports/ws/sws.c
+++ b/src/transports/ws/sws.c
@@ -1,7 +1,7 @@
 /*
     Copyright (c) 2013 250bpm s.r.o.  All rights reserved.
     Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved.
-    Copyright 2015 Garrett D'Amore <garrett@damore.org>
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -132,18 +132,17 @@
 static void nn_sws_acknowledge_close_handshake (struct nn_sws *self);
 
 void nn_sws_init (struct nn_sws *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner)
+    struct nn_ep *ep, struct nn_fsm *owner)
 {
     nn_fsm_init (&self->fsm, nn_sws_handler, nn_sws_shutdown,
         src, self, owner);
     self->state = NN_SWS_STATE_IDLE;
-    self->epbase = epbase;
     nn_ws_handshake_init (&self->handshaker,
         NN_SWS_SRC_HANDSHAKE, &self->fsm);
     self->usock = NULL;
     self->usock_owner.src = -1;
     self->usock_owner.fsm = NULL;
-    nn_pipebase_init (&self->pipebase, &nn_sws_pipebase_vfptr, epbase);
+    nn_pipebase_init (&self->pipebase, &nn_sws_pipebase_vfptr, ep);
     self->instate = -1;
     nn_list_init (&self->inmsg_array);
     self->outstate = -1;
diff --git a/src/transports/ws/sws.h b/src/transports/ws/sws.h
index 9ab02e6..7f2659d 100644
--- a/src/transports/ws/sws.h
+++ b/src/transports/ws/sws.h
@@ -1,7 +1,7 @@
 /*
     Copyright (c) 2013 250bpm s.r.o.  All rights reserved.
     Copyright (c) 2014 Wirebird Labs LLC.  All rights reserved.
-    Copyright 2015 Garrett D'Amore <garrett@damore.org>
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -83,9 +83,6 @@
     struct nn_fsm fsm;
     int state;
 
-    /*  Endpoint base. */
-    struct nn_epbase *epbase;
-
     /*  Default message type set on outbound frames. */
     uint8_t msg_type;
 
@@ -193,7 +190,7 @@
 void nn_msg_array_term (struct nn_list *msg_array);
 
 void nn_sws_init (struct nn_sws *self, int src,
-    struct nn_epbase *epbase, struct nn_fsm *owner);
+    struct nn_ep *ep, struct nn_fsm *owner);
 void nn_sws_term (struct nn_sws *self);
 
 int nn_sws_isidle (struct nn_sws *self);
diff --git a/src/transports/ws/ws.c b/src/transports/ws/ws.c
index af5bf8b..4e6d805 100644
--- a/src/transports/ws/ws.c
+++ b/src/transports/ws/ws.c
@@ -2,7 +2,7 @@
     Copyright (c) 2012-2013 250bpm s.r.o.  All rights reserved.
     Copyright (c) 2013 GoPivotal, Inc.  All rights reserved.
     Copyright (c) 2014 Wirebird Labs LLC.  All rights reserved.
-    Copyright 2015 Garrett D'Amore <garrett@damore.org>
+    Copyright 2016 Garrett D'Amore <garrett@damore.org>
 
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"),
@@ -65,8 +65,8 @@
 };
 
 /*  nn_transport interface. */
-static int nn_ws_bind (void *hint, struct nn_epbase **epbase);
-static int nn_ws_connect (void *hint, struct nn_epbase **epbase);
+static int nn_ws_bind (struct nn_ep *);
+static int nn_ws_connect (struct nn_ep *);
 static struct nn_optset *nn_ws_optset (void);
 
 static struct nn_transport nn_ws_vfptr = {
@@ -82,14 +82,14 @@
 
 struct nn_transport *nn_ws = &nn_ws_vfptr;
 
-static int nn_ws_bind (void *hint, struct nn_epbase **epbase)
+static int nn_ws_bind (struct nn_ep *ep)
 {
-    return nn_bws_create (hint, epbase);
+    return nn_bws_create (ep);
 }
 
-static int nn_ws_connect (void *hint, struct nn_epbase **epbase)
+static int nn_ws_connect (struct nn_ep *ep)
 {
-    return nn_cws_create (hint, epbase); 
+    return nn_cws_create (ep);
 }
 
 static struct nn_optset *nn_ws_optset ()
diff --git a/src/transports/ws/ws_handshake.c b/src/transports/ws/ws_handshake.c
index 26b7367..ddf5f25 100644
--- a/src/transports/ws/ws_handshake.c
+++ b/src/transports/ws/ws_handshake.c
@@ -916,7 +916,6 @@
     {
         const char *conn = NULL;
         size_t conn_len = 0;
-fprintf(stderr, "POS is %s\n", pos);
         if (nn_ws_match_token ("Host:", &pos, 1, 0)) {
             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
                 &self->host, &self->host_len);